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

相关推荐
_GR11 分钟前
2020年蓝桥杯第十一届C&C++大学B组(第二次)真题及代码
c语言·数据结构·c++·算法·蓝桥杯
Bczheng124 分钟前
C++ 语法之函数和函数指针
开发语言·c++
C语言小火车28 分钟前
Redis 10大核心场景实战手册:从缓存加速到分布式锁的全面解析
c语言·开发语言·数据库·c++·redis
xiecoding.cn2 小时前
C语言和C++到底有什么关系?
c语言·开发语言·c++·c/c++·c语言入门
c7_ln3 小时前
C++输入输出流第一弹:标准输入输出流 详解(带测试代码)
c++·g++·标准输入输出
Aomnitrix3 小时前
Qt 实操记录:打造自己的“ QQ 音乐播放器”
开发语言·c++·qt·ui·音视频
f狐0狸x4 小时前
【蓝桥杯每日一题】3.17
c语言·c++·算法·蓝桥杯·二进制枚举
Elnaij5 小时前
从C语言开始的C++编程生活(1)
c语言·c++
此刻我在家里喂猪呢5 小时前
C++ 介绍STL底层一些数据结构
c++