【问题标题】:Can I use CRTP with multiple derived classes, and use them polymorphically?我可以将 CRTP 与多个派生类一起使用,并以多态方式使用它们吗?
【发布时间】:2016-08-07 03:35:18
【问题描述】:

我有这样的类层次结构:

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

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

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

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

【问题讨论】:

    标签: c++ templates inheritance virtual-functions crtp


    【解决方案1】:

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

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

    然后,将您的向量声明为std::vector&lt;AbstractBase*&gt;

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

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

    另一方面,如果只是在foo中调用类似boo的函数,你也可以将boo设为虚拟,将非虚拟foo放入基础,从而摆脱的 CRTP。成本将相同:非虚拟调度 (foo) 和虚拟调度 (boo)。


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

    【讨论】:

    • 我使用crtp的所有东西都是为了避免虚函数,那么这个解决方案的意义是什么?引入crtp类避免虚函数,然后用虚函数的抽象类解决问题?废话
    • @user1289 好吧,CRTP 是一种编译时解决方案,这意味着您可以根据不同类型进行编译时调度。然后您要求具有相同的类型,这意味着运行时调度和虚函数。请注意,boo() 仍然是静态分派的。
    • @Angew,如果没有 crtp,也只需要一个运行时调度,在这种情况下,我有一个运行时和一个静态,可能比不使用 crtp 更糟糕。可能我的问题没有解决方案,只是想检查一下是否有破解。
    • @user1289 你不能一边吃蛋糕一边吃。如果您想要运行时多态性(并且您想要,通过答案中的最后一个 sn-p),那么您在某些时候需要虚函数。您不需要在基本层次结构中使用它,您可以使用类型擦除来非侵入性地使用多态性。
    • @user1289 使用 CRTP 是更糟还是更好取决于细节。如果您有一个foo,其Base 实现在内部调用了20 个不同的boos,则最好将CRTP 用于boos,并且虚拟地仅调度foo。当然,如果只是像示例中的一对一,那可能只是额外的开销。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-05-26
    • 1970-01-01
    • 2021-05-18
    • 2014-07-31
    • 1970-01-01
    • 2012-04-25
    相关资源
    最近更新 更多