C++模板能否实现编译时多态?如何让派生类返回对应TypePrinter
问题描述
考虑以下代码片段:
#include <iostream> #include <typeinfo> template<typename T> class TypePrinter{ public: void print_type() { std::cout << typeid(T).name() << std::endl; } }; // end class TypePrinter class Base{ public: TypePrinter<Base> createTypePrinter(){ // TODO replace "Base" with the class of the instance. return TypePrinter<Base>(); } }; // end Base class Derived: public Base{ }; int main() { // Create a derived instance and try to create a TypePrinter for it Derived d; auto tp = d.createTypePrinter(); tp.print_type(); // prints "4Base". return 0; } // end main
在上述示例中,定义了:
- 一个带有类型模板参数的类(
TypePrinter) - 另一个使用自身类型作为参数实例化它的类(
Base)
如何重写上述代码,使得继承的derived_instance.createTypePrinter()方法能够创建TypePrinter<Derived>而非TypePrinter<Base>?换句话说,需要进行哪些修改才能让d.createTypePrinter().print_type()输出“Derived”?
解决方案
可以使用**奇异递归模板模式(CRTP)**来实现需求,具体修改步骤如下:
- 将
Base改为模板类,模板参数指定为派生类的类型:
template<typename DerivedType> class Base{ public: TypePrinter<DerivedType> createTypePrinter(){ return TypePrinter<DerivedType>(); } };
- 让
Derived继承Base时,将自身作为模板参数传入:
class Derived: public Base<Derived>{ };
修改后的完整代码如下:
#include <iostream> #include <typeinfo> template<typename T> class TypePrinter{ public: void print_type() { std::cout << typeid(T).name() << std::endl; } }; // end class TypePrinter template<typename DerivedType> class Base{ public: TypePrinter<DerivedType> createTypePrinter(){ return TypePrinter<DerivedType>(); } }; // end Base class Derived: public Base<Derived>{ }; int main() { Derived d; auto tp = d.createTypePrinter(); tp.print_type(); // 现在会输出对应Derived的类型名(不同编译器格式可能有差异,比如GCC可能输出"7Derived") return 0; } // end main
原理说明
这种写法叫奇异递归模板模式(CRTP),核心就是让派生类继承一个以自己为模板参数的基类。这样基类在编译阶段就能获取到派生类的具体类型,createTypePrinter方法自然就能返回对应派生类的TypePrinter实例,从而打印出正确的类型名称。
需要注意的是,typeid(T).name()的输出格式依赖于编译器,不同编译器可能会输出带长度前缀的类型名,但都会正确识别出Derived类型。
内容的提问来源于stack exchange,提问作者NullPointerException
相关产品推荐
相关产品推荐

