news 2026/6/9 23:11:23

架构设计 - CRTP 奇异递归模板模式

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
架构设计 - CRTP 奇异递归模板模式

作者:billy
版权声明:著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处

一、什么是 CRTP?
CRTP(Curiously Recurring Template Pattern)直译是 “奇异递归模板模式”,核心特征是:一个类 A 继承自一个模板类,而这个模板类的模板参数正是类 A 本身。CRTP 在 C++ 标准库(如std::enable_shared_from_this)、开源框架(如 Boost)中广泛使用,是高性能 C++ 开发的重要技巧。

1. 最基础的 CRTP 结构

先看一个极简示例,直观理解结构:

// 模板类(基类) template <typename Derived> class Base { public: void do_something() { // 向下转型:将基类指针/引用转为派生类类型 Derived& derived = static_cast<Derived&>(*this); // 调用派生类的具体实现 derived.implementation(); } }; // 派生类:继承自Base<Derived>(模板参数是自己) class Derived : public Base<Derived> { public: void implementation() { std::cout << "Derived的具体实现" << std::endl; } }; // 测试代码 int main() { Derived d; d.do_something(); // 输出:Derived的具体实现 return 0; }
2. CRTP 的核心逻辑
  • 基类模板通过模板参数 “感知” 派生类的类型;
  • 基类中通过static_cast<Derived&>(*this)安全地将自身转为派生类对象;
  • 从而可以调用派生类的成员函数 / 成员变量,实现编译期的多态(区别于运行期的虚函数多态)。

二、CRTP 的核心用途(解决什么问题?)

CRTP 的核心价值是用编译期静态绑定替代运行期动态绑定,避免虚函数的开销,同时实现 “复用代码 + 定制化实现”

用途 1:静态多态(替代虚函数)

虚函数的多态是运行期确定调用哪个函数(有 vtable 开销),而 CRTP 在编译期就能确定,效率更高。

#include <iostream> using namespace std; // 基类模板:定义通用逻辑 template <typename Derived> class Shape { public: // 通用接口:计算面积 double area() const { // 调用派生类的具体计算逻辑 return static_cast<const Derived*>(this)->calc_area(); } }; // 圆形:定制calc_area class Circle : public Shape<Circle> { private: double radius; public: Circle(double r) : radius(r) {} // 派生类的具体实现 double calc_area() const { return 3.14159 * radius * radius; } }; // 矩形:定制calc_area class Rectangle : public Shape<Rectangle> { private: double width, height; public: Rectangle(double w, double h) : width(w), height(h) {} double calc_area() const { return width * height; } }; int main() { Circle c(2.0); Rectangle r(3.0, 4.0); // 统一接口调用,编译期确定调用哪个calc_area cout << "圆面积:" << c.area() << endl; // 输出:12.56636 cout << "矩形面积:" << r.area() << endl; // 输出:12 return 0; }
用途 2:实现 “混入(Mixin)” 功能

Mixin 是一种代码复用方式,CRTP 可以轻松实现 Mixin,给不同类批量添加通用功能(比如日志、计数、克隆)。

#include <iostream> #include <string> using namespace std; // Mixin:添加计数功能的CRTP基类 template <typename Derived> class Counter { private: static int count; // 静态变量:统计派生类对象数量 public: Counter() { count++; } ~Counter() { count--; } // 通用接口:获取当前对象数量 static int get_count() { return count; } }; // 静态变量初始化 template <typename Derived> int Counter<Derived>::count = 0; // 类A:混入计数功能 class A : public Counter<A> {}; // 类B:混入计数功能 class B : public Counter<B> {}; int main() { A a1, a2; B b1; cout << "A的对象数:" << A::get_count() << endl; // 输出:2 cout << "B的对象数:" << B::get_count() << endl; // 输出:1 { A a3; cout << "A的对象数:" << A::get_count() << endl; // 输出:3 } // a3析构 cout << "A的对象数:" << A::get_count() << endl; // 输出:2 return 0; }
用途 3:避免代码重复(静态多态的扩展)

比如实现 “可比较” 的类,CRTP 可以封装</>/==等比较逻辑,派生类只需实现核心的operator<:

template <typename Derived> class Comparable { public: // 封装通用比较逻辑 bool operator>(const Derived& other) const { return other < static_cast<const Derived&>(*this); } bool operator<=(const Derived& other) const { return !(static_cast<const Derived&>(*this) > other); } bool operator>=(const Derived& other) const { return !(static_cast<const Derived&>(*this) < other); } }; // 整数包装类:只需实现operator< class MyInt : public Comparable<MyInt> { private: int val; public: MyInt(int v) : val(v) {} // 核心比较逻辑 bool operator<(const MyInt& other) const { return val < other.val; } }; int main() { MyInt a(5), b(10); cout << (a > b) << endl; // 输出:0(false) cout << (a <= b) << endl; // 输出:1(true) return 0; }

三、CRTP 的关键注意事项

  1. 编译期确定类型:CRTP 的所有逻辑都在编译期完成,没有运行期开销,但也无法像虚函数那样 “动态绑定”(比如基类指针指向不同派生类对象);
  2. 转型安全性:必须确保模板参数是真正的派生类,否则 static_cast 会导致未定义行为;
  3. 与虚函数的区别:
    虚函数:运行期多态,灵活但有 vtable 开销;
    CRTP:编译期多态,高效但缺乏运行期灵活性。
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/6/9 17:28:04

告别CUDA噩梦:预装M2FP环境的云端解决方案

告别CUDA噩梦&#xff1a;预装M2FP环境的云端解决方案 你是不是也经历过这样的“深度学习入门惨案”&#xff1f;兴冲冲地想跑一个人体解析项目&#xff0c;结果刚打开电脑就陷入无尽的依赖地狱&#xff1a;CUDA版本不对、cuDNN不兼容、PyTorch编译失败、GCC报错……折腾三天三…

作者头像 李华
网站建设 2026/6/5 5:44:51

BGE-Reranker-v2-m3多版本对比:v1/v2/v3同台竞技

BGE-Reranker-v2-m3多版本对比&#xff1a;v1/v2/v3同台竞技 你是不是也遇到过这样的问题&#xff1a;作为技术决策者&#xff0c;想评估BGE-Reranker模型从v1到v3的升级到底值不值得投入&#xff1f;但本地显存不够&#xff0c;三个版本没法同时加载&#xff0c;来回切换费时…

作者头像 李华
网站建设 2026/6/8 17:44:31

C++:实现BCC校验计算(附带源码)

一、项目背景详细介绍在底层通信、嵌入式开发以及工业控制领域中&#xff0c;数据可靠性 是一个永恒的主题。在以下典型场景中&#xff1a;串口通信&#xff08;UART / RS232 / RS485&#xff09;工业总线&#xff08;Modbus / 自定义协议&#xff09;传感器数据采集MCU ↔ 上位…

作者头像 李华
网站建设 2026/6/9 21:53:54

零基础玩转通义千问2.5:vLLM离线推理保姆级教程

零基础玩转通义千问2.5&#xff1a;vLLM离线推理保姆级教程 1. 引言&#xff1a;为什么选择 vLLM Qwen2.5-7B-Instruct&#xff1f; 在大模型落地应用的实践中&#xff0c;高效、低成本、可本地部署的推理方案是开发者最关心的核心问题。通义千问2.5系列中的 Qwen2.5-7B-Ins…

作者头像 李华
网站建设 2026/6/5 5:06:00

实战演示:用麦橘超然Flux生成赛博朋克风城市街景

实战演示&#xff1a;用麦橘超然Flux生成赛博朋克风城市街景 1. 引言&#xff1a;AI图像生成的本地化实践新选择 随着生成式AI技术的快速发展&#xff0c;高质量图像生成已不再局限于云端服务。在边缘设备或本地环境中运行大模型成为越来越多开发者和创作者的需求。然而&…

作者头像 李华
网站建设 2026/6/6 5:29:02

FSMN VAD金融风控应用:电话销售合规话术检测支持

FSMN VAD金融风控应用&#xff1a;电话销售合规话术检测支持 1. 引言 在金融行业的电话销售场景中&#xff0c;合规性是监管机构和企业自身极为关注的核心问题。销售人员是否完整告知风险、是否存在误导性陈述、是否遗漏关键条款说明&#xff0c;这些都直接关系到企业的法律风…

作者头像 李华