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

相关推荐
TCW11215 分钟前
AI底层系列:用C++实现线性代数的公式推导与算法设计-6.线性方程组的解集
c++·人工智能·算法
拳里剑气22 分钟前
C++算法:链表
c++·算法·链表
superkcl202223 分钟前
【QT Thread】
c++·qt
旖-旎33 分钟前
《LeetCode 417 太平洋大西洋水流问题 FloodFill DFS 解法》
c++·算法·深度优先·力扣·floodfill
鱼子星_41 分钟前
C++从零开始系列篇(二):C++入门——函数重载,引用,inline与nullptr
开发语言·c++·笔记
小灰灰搞电子1 小时前
C++ boost::circular_buffer 详解:原理、用法与实战
开发语言·c++·boost
星恒随风2 小时前
C++ string 类详解:常用接口、OJ 场景与模拟实现中的深浅拷贝
开发语言·c++·笔记·学习·状态模式
程序喵大人2 小时前
【C++并发系列】第二章:锁解决了什么问题?
开发语言·c++·并发编程·
天天代码码天天2 小时前
用 TensorRT 加速 PP-OCR:一套 C++ DLL + C# 调用的高性能 OCR 推理方案
c++·c#·ocr
我不是懒洋洋2 小时前
从零实现一个分布式链路追踪:TraceId与Span
c++