CRTP奇异递归模板模式

文章目录

CRTP

运行时多态(动态多态)使用传统继承 + 虚函数,会引入 虚表(vtable),每次调用虚函数都要通过间接寻址,影响性能。

CRTP(Curiously Recurring Template Pattern),即奇异递归模板模式,是一种 C++ 编译期多态技术(静态多态)。它的核心思想是:派生类作为模板参数传递给基类,从而在编译期实现静态多态,避免了运行时的虚函数开销。同时保持接口的可复用性。

基本实现

普通虚函数实现(动态多态):

虚函数(动态多态):interface() 通过 vtable(虚表) 调用 implementation(),运行时解析,有额外的虚函数开销。

cpp 复制代码
class Base {
public:
    virtual void implementation() { std::cout << "Base\n"; }
    void interface() { implementation(); }
    virtual ~Base() = default;
};

class Derived : public Base {
public:
    void implementation() override { std::cout << "Derived\n"; }
};

CRTP 实现(静态多态,消除虚表):

Base< Derived> 是一个 模板基类,但它的模板参数是派生类 Derived 自己。

interface() 里使用 static_cast<Derived*>(this)->implementation();,在编译期解析出正确的implementation(),避免了虚函数的开销。

Derived 继承自 Base< Derived> ,提供 implementation() 方法,实际执行时 直接调用派生类的方法。

cpp 复制代码
#include <iostream>

// CRTP 基类
template <typename Derived>
class Base {
public:
    void interface() {
        // 调用派生类的方法
        static_cast<Derived*>(this)->implementation();
    }
};

// 具体派生类
class Derived : public Base<Derived> {
public:
    void implementation() {
        std::cout << "Derived::implementation()" << std::endl;
    }
};

int main() {
    Derived d;
    d.interface();  // 调用 Derived::implementation()
}

CRTP 的应用

  1. 实现静态计数器
    通过 CRTP 模板参数区分不同类的静态变量,保证 A 和 B 各自维护自己的计数。
cpp 复制代码
template <typename T>
class Counter {
    static int count;
public:
    Counter() { ++count; }
    ~Counter() { --count; }
    static int getCount() { return count; }
};

// 静态变量初始化
template <typename T> int Counter<T>::count = 0;

// 统计不同类对象的数量
class A : public Counter<A> {};
class B : public Counter<B> {};

int main() {
    A a1, a2;
    B b1;
    std::cout << "A count: " << A::getCount() << "\n"; // 2
    std::cout << "B count: " << B::getCount() << "\n"; // 1
}
  1. C++ 标准库 std::enable_shared_from_this< T> 采用了 CRTP,让 MyClass 能够安全地从 this 返回 shared_ptr< T>,避免对象 被错误地 delete 两次。
cpp 复制代码
#include <iostream>
#include <memory>

class MyClass : public std::enable_shared_from_this<MyClass> {
public:
    std::shared_ptr<MyClass> getShared() {
        return shared_from_this();
    }
};

int main() {
    auto ptr = std::make_shared<MyClass>();
    auto sharedPtr = ptr->getShared();
    std::cout << "Reference count: " << sharedPtr.use_count() << "\n"; // 2
}

std::enable_shared_from_this 只是 管理 shared_ptr 生命周期,和 CRTP 静态多态无关。

std::unique_ptr< Base>,建议用传统继承 + 虚函数。

如果想使用CRTP 的静态多态,但又希望能存储不同的子类对象,可以使用 std::variant如下所示:

cpp 复制代码
#include <variant>

template <typename Derived>
class Base {
public:
    void interface() {
        static_cast<Derived*>(this)->implementation();
    }
};

class Derived : public Base<Derived> {
public:
    void implementation() {
        std::cout << "Derived implementation\n";
    }
};

int main() {
    std::variant<Derived> obj = Derived();
    std::visit([](auto& derived) { derived.interface(); }, obj);
}

总结

CRTP(奇异递归模板模式) 是 静态多态 的一种实现方式。

优势:

避免虚函数开销,提高性能。

可以在基类中调用派生类的方法。

模板编程的基础,支持静态计数器、链式调用、策略模式等。

劣势:

代码可读性较低,不适合过于复杂的继承体系。

不支持运行时多态,无法用于 std::unique_ptr< Base>。

相关推荐
双叶83634 分钟前
(51单片机)LCD展示动画(延时函数)(LLCD1602教程)
c语言·数据库·c++·单片机·嵌入式硬件·51单片机
愚润求学1 小时前
【数据结构】哈希表
数据结构·c++·笔记·散列表
倔强的石头1061 小时前
【C++指南】位运算知识详解
java·开发语言·c++
mozun20202 小时前
QT:Qt5 串口模块 (QSerialPort) 在 VS2015 中正确关闭串口避免被占用
开发语言·c++·qt·串口·串口调试·上位机软件
byte轻骑兵2 小时前
【C++ 类和数据抽象】static 类成员
开发语言·c++
努力学习的小廉2 小时前
【C++】 —— 笔试刷题day_24
开发语言·c++
刃神太酷啦2 小时前
堆和二叉树--数据结构初阶(3)(C/C++)
c语言·数据结构·c++·算法·leetcode·深度优先·宽度优先
用户jjbjjbk2 小时前
QT多线程以及事件循环
c++·qt
阳光_你好2 小时前
医学图像(DICOM数据)读取及显示(横断面、冠状面、矢状面、3D显示)为什么用ITK+VTK,单独用ITK或者VTK能实一样功能吗?
c++
啊阿狸不会拉杆3 小时前
数据结构-排序
java·c语言·数据结构·c++·python·算法·排序算法