You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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)**来实现需求,具体修改步骤如下:

  1. 将Base改为模板类,模板参数指定为派生类的类型:
template<typename DerivedType>
class Base{
    public:
    TypePrinter<DerivedType> createTypePrinter(){
        return TypePrinter<DerivedType>();
    }
};
  1. 让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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.20 04:29:54