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>。

相关推荐
莫听穿林打叶声儿14 分钟前
Qt中使用QString显示平方符号(如²)
c++·qt
大锦终19 分钟前
【Linux】文件系统
linux·服务器·c++
重启的码农1 小时前
llama.cpp 分布式推理介绍(2) 后端注册机制 (Backend Registration)
c++·人工智能·神经网络
重启的码农1 小时前
llama.cpp 分布式推理介绍(1) 远程计算设备 (RPC Device)
c++·人工智能·神经网络
蜗牛沐雨2 小时前
C++ 类型转换
开发语言·c++
_poplar_2 小时前
08.5【C++ 初阶】实现一个相对完整的日期类--附带源码
c语言·开发语言·数据结构·c++·vscode·算法·vim
源远流长jerry3 小时前
STM32之MCU和GPIO
linux·c++·stm32·单片机·嵌入式硬件
汤永红3 小时前
week2-[一维数组]最大元素
数据结构·c++·算法·信睡奥赛
Minecraft红客6 小时前
C++小游戏荒芜的城堡
c++·游戏·娱乐
scx2013100413 小时前
20250814 最小生成树和重构树总结
c++·算法·最小生成树·重构树