Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C++ Passing a derived class as a base class template parameter

Tags:

c++

templates

I'm having trouble passing a class DerivedObject (part of class DerivedClass derived from template class BaseClass) derived from BaseObject (part of template class BaseClass) as a template argument to template class BaseClass.

This way, both Base and Derived classes have the access to the object pool, that can contain derived objects. This sounds a bit confusing, so here is the example:

template <class TDerivedClass, class TDerivedObject>
class BaseClass
{
protected:
    class BaseObject
    {
        // Class implementation
    }
    void foo() 
    { 
        static_cast<TDerivedClass*>(this)->foo(); 
    }
    std::vector<TDerivedObject*> m_objectPool;
};

The above is the base class implementation.

error C2065: 'DerivedObject' undeclared identifier

The above error is cause by the first line of the class definition bellow:

class DerivedClass : public BaseClass<DerivedClass, DerivedClass::DerivedObject>
{
protected:
    class DerivedObject : public BaseObject
    {
        // Class implementation
    }
    void foo()
    {
        // Method implementation
    }
};

Is there a way to do this? If not, is there a better solution that would give me the same / similar functionality?

like image 608
Paul A. Avatar asked Aug 25 '15 14:08

Paul A.


People also ask

Can a derived class be template?

It is possible to inherit from a template class. All the usual rules for inheritance and polymorphism apply. If we want the new, derived class to be generic it should also be a template class; and pass its template parameter along to the base class.

What is a template template parameter?

The Template Parameters tool is available for viewing template parameter usage in articles. It works with TemplateData to show the frequency of parameter name usage in a template's mainspace transclusions, along with whether or not each parameter is listed in that template's TemplateData code as a supported parameter.

What is Typename C++?

" typename " is a keyword in the C++ programming language used when writing templates. It is used for specifying that a dependent name in a template definition or declaration is a type.

Can derived class access public members of base class?

You can derive classes using any of the three access specifiers: In a public base class, public and protected members of the base class remain public and protected members of the derived class. In a protected base class, public and protected members of the base class are protected members of the derived class.


3 Answers

At this point

class DerivedClass : public BaseClass<DerivedClass, DerivedClass::DerivedObject>

The compiler has not seen DerivedClass::DerivedObject so you get an undeclared identifier error. As they type has not been seen you cannot use it as a template parameter. You don't get one for DerivedClass as you already have declared DerivedClass as a class.

You could change you base class and have it store a std::vector<BaseObject*> in it and if you do that then you can change your code to:

template <class TDerivedClass>
class BaseClass
{
protected:
    class BaseObject
    {
        // Class implementation
    };
    void foo() 
    { 
        static_cast<TDerivedClass*>(this)->foo(); 
    }
    std::vector<BaseObject*> m_objectPool;
};

class DerivedClass : public BaseClass<DerivedClass>
{
protected:
    class DerivedObject : public BaseObject
    {
        // Class implementation
    };
    void foo()
    {
        // Method implementation
    }
};
like image 99
NathanOliver Avatar answered Nov 14 '22 21:11

NathanOliver


Here is one way of doing something similar to what was requested:

#include <vector>

using std::vector;

template <class TDerivedClass, class TDerivedObject>
class BaseClass
{
public:
    class BaseObject
    {
        // Class implementation                                                                                                                                                                                                              
    };

protected:
    // void foo()                                                                                                                                                                                                                            
    // {                                                                                                                                                                                                                                     
    //     static_cast<TDerivedClass*>(this)->foo();                                                                                                                                                                                         
    // }                                                                                                                                                                                                                                     
    // std::vector<TDerivedObject*> m_objectPool;                                                                                                                                                                                            
};

class DerivedClass;
class DerivedObject : public BaseClass<DerivedClass, DerivedObject>::BaseObject
{
    // Class implementation                                                                                                                                                                                                                  
};

class DerivedClass : public BaseClass<DerivedClass, DerivedObject>
{
public:
    void foo()
    {
        // Method implementation                                                                                                                                                                                                             
    }
};
like image 21
Erik Alapää Avatar answered Nov 14 '22 21:11

Erik Alapää


From your example code, I get the impression that you want to provide different implementations for different base classes. Is there any special reason for using templates? If not, you could use classic polymorphism instead:

class BaseClass
{
  class BaseObject {};
  virtual ~BaseClass() {} // <- do not forget to provide virtual dtor!
  virtual void foo() = 0;
  std::vector<BaseObject*> m_objectPool;
};
class DerivedClass : public BaseClass
{
  class DerivedObject : public BaseObject {/*...*/};
  virtual void foo(){/*...*/}
};

Again, BaseObject would offer virtual or pure virtual functions - as you need.

One thing, however, you lose this way: the guarantee that in the vector there are always the objects of one specific BaseObject sub-type. If this matters for you, you could protect the pool and only allow to add new BaseObjects via DerivedClass. If this is not applicable, I might think up another solution from within BaseClass.

like image 26
Aconcagua Avatar answered Nov 14 '22 22:11

Aconcagua