传递一个派生类作为基类模板参数

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

本文关键字:基类 参数 派生 一个      更新时间:2023-10-16

我在传递从BaseObject(模板类BaseClass的一部分)派生的类DerivedObject(从模板类BaseClass派生的类DerivedClass的一部分)作为模板参数到模板类BaseClass时遇到了麻烦。

这样,基类和派生类都可以访问对象池,对象池可以包含派生对象。这听起来有点令人困惑,下面是示例:

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

以上是基类的实现。

error C2065: 'DerivedObject' undeclared identifier

上面的错误是由下面类定义的第一行引起的:

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

有办法做到这一点吗?如果没有,是否有更好的解决方案,可以给我相同/类似的功能?

此时

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

编译器没有看到DerivedClass::DerivedObject,所以你得到一个未声明的标识符错误。由于没有看到它们的类型,因此不能将其用作模板参数。你没有得到一个DerivedClass,因为你已经将DerivedClass声明为class

你可以改变你的基类,让它存储一个std::vector<BaseObject*>如果你这样做,你可以改变你的代码:

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
    }
};

这里有一种类似于请求的方法:

#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                                                                                                                                                                                                             
    }
};

从您的示例代码中,我得到的印象是您希望为不同的基类提供不同的实现。使用模板有什么特殊的原因吗?如果没有,可以使用经典多态性:

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(){/*...*/}
};

同样,BaseObject可以根据需要提供虚函数或纯虚函数。

但是,这样做会丢失一件事:在vector中始终存在一个特定BaseObject子类型的对象的保证。如果这对您很重要,您可以保护池,只允许通过DerivedClass添加新的BaseObjects。如果这是不适用的,我可能会想到从BaseClass内的另一个解决方案。

如果您不介意将DerivedObject结构与DerivedClass分开,您可以这样做:

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                                                                                                                                 
    }                                                                                                                                                          
 };

我不认为这是一个非常聪明的解决方案,但你可以得到的想法-使用类型特征或typedef

相关文章: