避免在构造函数中使用虚方法

Rad*_*094 5 c++

假设我有以下类层次结构:

class Base
{
   virtual int GetClassID(){ return 0;};
public:
   Base() { SomeSingleton.RegisterThisObject(this->GetClassID());
}

class Derived
{
   virtual int GetClassID(){ return 1;};
public:
   Derived():Base(){};
}
Run Code Online (Sandbox Code Playgroud)

嗯,这一切都从我的实际情况简化,但这是它的一般要点.

我想避免在每个派生类的构造函数中调用RegisterThisObject,所以我试图将调用移动到基类的构造函数.

是否有任何模式可用于在不使用构造函数中的虚方法的情况下完成此操作?

seh*_*ehe 8

您可以使用奇怪的重复模板模式

template <class T>
class Base
{
protected:  // note change
   Base() { SomeSingleton.RegisterThisObject(T::GetClassID());
}

class Derived : Base<Derived>
{
   static int GetClassID(){ return 1;};
public:
   Derived(): Base<Derived>(){};
}
Run Code Online (Sandbox Code Playgroud)

此外,当您拥有多派生类时(例如DerivedDerived : Derived),它将需要额外的工作.我建议您只是避免这种情况,但在其他情况下,您可能希望将注册转移到策略类中(使行为可聚合而不是类标识的一部分)

性状

扩展我的提示(使行为可聚合),你会看到这样的事情:

namespace detail
{
    template <class T> struct registerable_traits { };         
    template<> struct registerable_traits<Derived>
    { 
        enum _id { type_id = 1 };
    };
}

template <class T>
class Base
{
protected:  // note change
   Base() { SomeSingleton::RegisterThisObject(detail::registerable_traits<T>::type_id); }
};

class Derived : Base<Derived>
{
public:
   Derived(): Base<Derived>(){};
};
Run Code Online (Sandbox Code Playgroud)

请参阅Codepad.org


Dav*_*eas 7

virtual方法的问题在于它不起作用,因为在执行基础构造函数对象时,对象的类型是基础,而不是派生类型.

如果GetClassID是静态成员函数,则可以更改设计,以便将标识符作为参数传递给基类型:

struct Base {
   Base( int id ) {
      register_object( id, this );
   }
};
struct Derived {
   static int getId() { return 5; }
   Derived() : Base( getId() ) {}
};
Run Code Online (Sandbox Code Playgroud)