如何用CRTP实现可直接使用的Base类,无需虚函数扩展派生类
解决C++中无virtual情况下Base类调用Derived方法及链式调用问题
问题分析
原代码中,Derived继承Base后调用genericWrapper时,内部的specificConfig会执行Base版本——因为没有多态机制;同时genericWrapper返回Base&,导致后续链式调用的methodChaining也只能触发Base版本,不符合预期。我们可以用**CRTP(奇异递归模板模式)**实现编译时多态,完全不需要virtual函数。
解决方案代码
#include <iostream> #include <string> template <typename T> struct Base { T& genericWrapper(); std::string specificConfig(); T& methodChaining(); }; template <typename T> T& Base<T>::genericWrapper() { std::cout << "Base::genericWrapper():\n" << static_cast<T&>(*this).specificConfig() << std::endl; return static_cast<T&>(*this); } template <typename T> std::string Base<T>::specificConfig() { return "Base::specificConfig()"; } template <typename T> T& Base<T>::methodChaining() { std::cout << ".Base::methodChaining()\n"; return static_cast<T&>(*this); } struct Derived : public Base<Derived> { std::string specificConfig(); Derived& methodChaining(); }; std::string Derived::specificConfig() { return "Derived::specificConfig()"; } Derived& Derived::methodChaining() { std::cout << ".Derived::methodChaining()\n"; return *this; } int main() { Base<Base> b{}; Derived d{}; std::cout << "Base:\n"; b.genericWrapper().methodChaining().methodChaining(); std::cout << "\nDerived:\n"; d.genericWrapper().methodChaining().methodChaining(); return 0; }
输出结果
Base: Base::genericWrapper(): Base::specificConfig() .Base::methodChaining() .Base::methodChaining() Derived: Base::genericWrapper(): Derived::specificConfig() .Derived::methodChaining() .Derived::methodChaining()
关键说明
- CRTP模板化Base类:将Base定义为模板类,模板参数为派生类T,让Derived继承
Base<Derived>,实现编译时的类型绑定。 - 静态转换获取派生类实例:在Base的成员函数中,通过
static_cast<T&>(*this)将Base实例转换为派生类引用,确保优先调用派生类重写的方法;如果派生类未重写,则自动回退到Base的版本。 - 链式调用返回派生类引用:所有需要链式调用的方法返回
T&,保证后续调用始终针对派生类实例,避免返回Base引用导致的类型降级问题。 - Base自身的实例化:用
Base<Base>创建Base对象是合法的,因为模板成员函数的定义放在类外,此时Base已经完成完整定义,不会触发未定义类型的编译错误。
内容的提问来源于stack exchange,提问作者JWCS
相关产品推荐
相关产品推荐

