2016-04-15 64 views
4

我有这样的类层次结构:我可以将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 { ... } 
}; 

的事情是,我想用我的课以这样的方式

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

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

回答

3

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

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<AbstractBase*>

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

尽管如此,它仍然是有益的。例如,如果所有派生类共享foo的实现,但调用许多不同的boo样式函数(每个派生类具有不同的实现方式),则仅在调用foo时支付一次动态调度成本,然后内的所有呼叫都在foo内静态调度,CRTP风格。

在另一方面,如果它的内foo只需一个电话到boo样的功能,你不妨做boo虚拟的,把非虚foo到基础,从而摆脱CRTP的。成本将是相同的:非虚拟调度(foo)和虚拟调度(boo)。


侧面说明,你应该认真考虑在std::vector存储智能指针; 拥有原始指针是不好的做法。

+0

我用过crtp的所有东西都是为了避免虚函数,那么这个解决方案的含义是什么?引入crtp类来避免虚函数,然后使用具有虚函数的抽象类来解决这个问题?废话 – user1289

+1

@ user1289那么,CRTP是一个编译时解决方案,这意味着你有基于不同类型的编译时调度。然后你要求具有相同的类型,这意味着运行时调度和虚拟功能。请注意,'boo()'仍然是静态调度的。 – Angew

+0

@Angew,没有crtp也只会需要一个运行时调度,在这种情况下,我有一个运行时和一个静态,可能比没有使用crtp更差。我的问题可能没有解决办法,只是想检查一下是否存在黑客攻击。 – user1289

相关问题