将实现从继承的CRTP注入到继承的接口类

时间:2017-08-10 11:13:36

标签: c++ interface c++14 crtp vtable

我希望摆脱重复的代码,而不会产生额外的v-table成本。

  • B是一个接口类:它不能是虚拟的
  • D1D2是B的具体类。
    • 它们的某些部分相同:在mcve中显示为std::cout<<"same"
    • 部分内容不同:显示为different1()different2()

这是代码。它运作正常。 (Demo

class B{//can't be template
    public: virtual void show()=0;
};
class D1 : public B{
    public: bool different1(){return true;}
    public: virtual void show(){ 
        if( different1() )
            std::cout<<"same";   //duplicate
    }
};
class D2 : public B{
    public: bool different2(){return true;}
    public: virtual void show(){ 
        if( different2() )
            std::cout<<"same";   //duplicate
    }
};
int main(){
    D1 d;
    B* b=&d;
    b->show();  //1 v-table look up : OK!
}

我糟糕的解决方案(1/2)

将重复的代码移至基类( Demo ): -

class B{//can't be template
    public: virtual void show(){
        if( differentX() )
            std::cout<<"same";   //duplicate
    }
    public: virtual bool differentX() = 0;
};
class D1 : public B{
    public: bool differentX(){return true;}
};
class D2 : public B{
    public: bool differentX(){return true;}
};

问题是b->show()会产生2个v-table查找。 (?)

我知道“过早优化是邪恶的”,但我想听听是否有可能将v-table成本降低到1.(在借口并使用此方法之前)

我的解决方案(2/2)

使用CRTP( demo

class B{//can't be template
    public: virtual void show()=0;
};
template<class T>class C{  //
    public: bool differentX(){
        return static_cast<T*>(this)->differentImpl()   ;
    }
    public: void show(){
        differentX();
        std::cout<<"same"; 
    }
};
class D1 : public B, public C<D1>{
    public: bool differentImpl(){return true;}
};
class D2 : public B, public C<D2>{
    public: bool differentImpl(){return true;}
};

但是,它不再是可以兼容的,因为D1不再是具体的类。

如何解决?我是CRTP的新手。

3 个答案:

答案 0 :(得分:2)

如何解决这个问题?

C实现了B的show方法,并提供了show的通用实现,它依赖于模板参数T提供不同的实现。

D1和D2从C继承自己作为模板参数。

http://coliru.stacked-crooked.com/a/34e8a727e81e19f7

#include <iostream>
class B {//can't be template
    public: virtual void show() = 0;
};

template<class T>
class C : public B {
public:
    void show() override {
        if (Impl().different()) {
            std::cout << "same"; 
        }
    }
private:
    T& Impl() {
        return *static_cast<T*>(this);
    }
};

class D1 : public C<D1> {
    public: bool different() { return true; }
};
class D2 : public C<D2> {
    public: bool different() { return true; }
};

int main() {
    D1 d;
    B* b = &d;
    b->show();  
}

答案 1 :(得分:1)

解决方案3:将重复的代码放入函数中。像这样:

class B{//can't be template
    public: virtual void show()=0;
    public: void same(){
        std::cout<<"same";   //no duplicate
    }
};
class D1 : public B{
    public: bool different1(){return true;}
    public: virtual void show(){ 
        if( different1() )
            same();
    }
};
class D2 : public B{
    public: bool different2(){return true;}
    public: virtual void show(){ 
        if( different2() )
            same();
    }
};
int main(){
    D1 d;
    B* b=&d;
    b->show();  //1 v-table look up : OK!
}

答案 2 :(得分:1)

正如我在评论中所说,你可以创建一个具有共同功能的功能:

void ShowFuncX( B& b )
{
    if ( b.differentX() )
    {
        std::cout<<"same";
    }
}

然后在派生中:

class D1 : public B{
    public: bool different1(){return true;}
    public: virtual void show(){ 
        ShowFuncX( *this );
    }
};
class D2 : public B{
    public: bool different2(){return true;}
    public: virtual void show(){ 
        ShowFuncX( *this );
    }
};

另请参阅“Is it always a best practice to write a function for anything that needs to repeat twice?