有一个基类
Base
,它有很多功能,并且可以/应该按原样使用。但我想用(几个)Derived
类来扩展它,而不用一堆虚拟/覆盖来污染原始类(因为,不确定哪些方法实际上需要从基本版本中更改)。当然,天真地让派生对象调用继承的方法会使该方法仅调用基类的方法,而不是任何重写的方法。
我尝试将其设为 CRTP,但问题似乎出在基类上;如果 Base 是一个模板,那么当类型当时不完整时,怎么可能有它自己的实例化?大多数其他 SO 问题似乎实际上并没有使用基类,而是将其保留为接口定义。或者,答案是否在当前硬编码 Base 的成员的函数模板中,而不是类模板中?
// template <class T = struct Base>
struct Base {
Base& genericWrapper(); // return T&
std::string specificConfig();
Base& methodChaining(); // return T&
};
Base& Base::genericWrapper(){
std::cout << "Base::genericWrapper():\n" <<
/* T:: */ specificConfig() << std::endl;
return *this; // T??
}
std::string Base::specificConfig(){
return "Base::specificConfig()";
}
Base& Base::methodChaining(){
std::cout << ".Base::methodChaining()\n";
return *this;
}
struct Derived : public Base {
std::string specificConfig();
Derived& methodChaining(); // return T&
};
std::string Derived::specificConfig(){
return "Derived::specificConfig()";
}
Derived& Derived::methodChaining(){
std::cout << ".Derived::methodChaining()\n";
return *this;
}
int main()
{
Base b{};
Derived d{};
std::cout << "Base:\n";
b.genericWrapper().methodChaining().methodChaining();
std::cout << "\nDerived:\n";
d.genericWrapper().methodChaining().methodChaining();
return 0;
}
哪个打印:
Derived:
Base::genericWrapper(): // OK
Base::specificConfig() // No
.Base::methodChaining() // Also no
.Base::methodChaining()
如果你想使用CRTP,那么你确实需要一个基类模板,正如你所说,你不能实例化它本身,但你可以创建一个派生的
struct
来实例化基类模板,这不会改变行为(如下,TriviallyDerived
)。 使用 CRTP 时,需要进行一些静态转换,如下所示。
#include <string>
#include <iostream>
template <class Derived>
struct Base {
Derived& genericWrapper();
std::string specificConfig();
Derived& methodChaining();
};
template <class Derived>
Derived& Base<Derived>::genericWrapper(){
std::cout << "Base::genericWrapper():\n" <<
static_cast<Derived*>(this)->specificConfig() << std::endl;
return static_cast<Derived&>(*this);
}
template <class Derived>
std::string Base<Derived>::specificConfig(){
return "Base::specificConfig()";
}
template <class Derived>
Derived& Base<Derived>::methodChaining(){
std::cout << ".Base::methodChaining()\n";
return static_cast<Derived&>(*this);
}
struct Derived : Base<Derived> {
std::string specificConfig();
Derived& methodChaining();
};
std::string Derived::specificConfig(){
return "Derived::specificConfig()";
}
Derived& Derived::methodChaining(){
std::cout << ".Derived::methodChaining()\n";
return *this;
}
struct TriviallyDerived : Base<TriviallyDerived> { };
int main()
{
TriviallyDerived b{};
Derived d{};
std::cout << "Base:\n";
b.genericWrapper().methodChaining().methodChaining();
std::cout << "\nDerived:\n";
d.genericWrapper().methodChaining().methodChaining();
}