我可以将CRTP与多个派生类一起使用,并以多态方式使用它们吗?

use*_*289 5 c++ inheritance templates virtual-functions crtp

我有这样的类层次结构:

template <class Type>
class CrtpBase
{
protected:
    Type& real_this()
    {
        return static_cast<Type&>(*this);
    }
};

template <class ChildType>
class Base : CrtpBase<ChildType>
{
public:
    void foo()
    {
        this->real_this().boo();
    }
};

class Derived1 : public Base<Derived1>
{
public:
    void boo { ... }
};

class Derived2 : public Base<Derived2>
{
public:
    void boo { ... }
};
Run Code Online (Sandbox Code Playgroud)

问题是,我想以这种方式使用我的类:

std::vector<Base*> base_vec;
base_vec.push_bach(new Derived1());
base_vec.push_bach(new Derived2());
.........
base_vec[0]->foo();
Run Code Online (Sandbox Code Playgroud)

但这是不可能的,因为所有派生类的基类是不同的(实际上Base根本不是一个类型,它是模板).那么,有没有办法使用crtp与多个派生类,以及多态?

Rei*_*ica 5

确实有,您还需要添加适当的非模板基类:

class AbstractBase
{
public:
  virtual ~AbstractBase() {}

  virtual void foo() = 0;
};


template <class ChildType>
class Base : CrtpBase<ChildType>, public AbstactBase
{
  void foo() override { this->real_this().boo(); }
};
Run Code Online (Sandbox Code Playgroud)

然后,将向量声明为std::vector<AbstractBase*>

这确实引入了动态分派的开销(您可能试图通过使用 CRTP 来避免),但动态分派是在 C++ 中获得运行时多态性的唯一方法。

不过,它仍然是有益的。例如,如果 的实现foo由所有派生类共享,但调用许多不同的boo风格函数(每个派生类都有不同的实现),则在调用 时只需支付一次动态调度成本foo,然后内部 进行的所有调用foo均以 CRTP 方式静态调度。

另一方面,如果只是对boo中类似函数的一次调用foo,您也可以将其设为boovirtual,将 non-virtualfoo放入基类中,从而摆脱 CRTP。那么成本将是相同的:非虚拟调度 ( foo) 和虚拟调度 ( boo)。


旁注,您应该强烈考虑将智能指针存储在std::vector;中。拥有原始指针是不好的做法。

  • @user1289嗯,CRTP是一个编译时解决方案,这意味着您可以根据不同类型进行编译时调度。然后您要求具有相同的类型,这意味着运行时调度以及虚拟函数。请注意,“boo()”仍然是静态调度的。 (2认同)
  • @user1289 鱼与熊掌不可兼得。如果您想要运行时多态性(并且您想要,请按照答案中的最后一个片段进行操作),那么您在某些时候需要虚拟函数。您在基本层次结构中不需要它,您可以采用类型擦除来非侵入性地使用多态性。 (2认同)