我想在不产生额外的 v-table 成本的情况下摆脱重复的代码。
-
B
是一个接口(interface)类:它不能是虚拟的 -
D1
和D2
是 B 的具体类。- 部分相同:显示为
std::cout<<"same"
在 mcve 中。 - 有些部分不同:显示为
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 表查找。 (?)
我知道“过早的优化是邪恶的”,但我想听听是否有可能将 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 的新手。
最佳答案
这个解决方案怎么样?
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();
}
关于c++ - 将继承的 CRTP 实现注入(inject)继承的接口(interface)类,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45612144/