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

I am unable to pass the DerivedObject class (part of the DerivedClass class obtained from the BaseClass template BaseClass ) derived from BaseObject (part of the BaseClass class BaseClass ) as a template argument to the BaseClass template BaseClass .

Thus, both the Base and Derived classes have access to the pool of objects, which may contain derived objects. This sounds a bit confusing, here is an 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 implementation of the base class.

 error C2065: 'DerivedObject' undeclared identifier 

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

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

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

+5
source share
4 answers

Here is one way to do 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 } }; 
+1
source

In this moment

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

The compiler did not see DerivedClass::DerivedObject to get an undeclared identifier error. Since they are not visible, you cannot use it as a template parameter. You will not get it for DerivedClass since you already declared DerivedClass as a class .

You can change your base class and store std::vector<BaseObject*> , and if you do, 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 } }; 
+5
source

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

 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 will offer virtual or pure virtual functions - as needed.

One thing, however, you lose this path: ensuring that the vector always contains objects of one particular subtype of BaseObject. If that matters to you, you can protect the pool and let you add new BaseObjects through DerivedClass. If this is not applicable, I could come up with another solution from BaseClass.

+1
source

If you don't mind having a DerivedObject structure separate from DerivedClass, you can do something like this:

 template <class T> struct ObjectTypeTrait { static_assert(sizeof(T) == 0, "undefined trait"); }; template <class TDerivedClass> class BaseClass { protected: class BaseObject { // Class implementation }; void foo() { static_cast<TDerivedClass*>(this)->foo(); } std::vector<typename ObjectTypeTrait<TDerivedClass>::obj*> m_objectPool; }; class DerivedClass; class DerivedObject { // Class implementation }; template<> struct ObjectTypeTrait<DerivedClass> { using obj = DerivedObject; }; class DerivedClass : public BaseClass<DerivedClass> { protected: void foo() { // Method implementation } }; 

I am not saying that this is a very brilliant solution, but you can get the idea - using type traits or typedefs

0
source

All Articles