前往小程序,Get更优阅读体验!
立即前往
发布
社区首页 >专栏 >浅析C++中的CRTP

浅析C++中的CRTP

作者头像
程序员的园
发布2025-02-18 21:16:07
发布2025-02-18 21:16:07
6200
代码可运行
举报
运行总次数:0
代码可运行

在C++编程中,有许多精妙的设计模式和技巧,CRTP(Curiously Recurring Template Pattern,奇异递归模板模式)便是其中之一,作为一种简洁而强大的模式,被广泛用于提高代码的灵活性和性能。

基本思想

CRTP利用模板元编程的特性,通过模板继承的方式实现递归结构。CRTP的基本思想:基类模板以派生类作为模板参数,在基类接口中将this指针强转为派生类指针,调用派生类中的方法,从而实现了一种静态多态性。

如下的示例代码有助于理解CRTP的工作原理:

代码语言:javascript
代码运行次数:0
复制
// 基类模板
template <typename Derived>
class CBase {
public:
void commonMethod() {
static_cast<Derived*>(this)->implementation();
    }

void anotherCommonMethod() {
std::cout << "Another common method in Base." << std::endl;
    }
};

// 派生类1
class Derived1 : public CBase<Derived1> {
public:
void implementation() {
std::cout << "Implementation in Derived1." << std::endl;
    }
};

// 派生类2
class Derived2 : public CBase<Derived2> {
public:
void implementation() {
std::cout << "Implementation in Derived2." << std::endl;
    }
};


void test_CRTP()
{
    Derived1 d1;
    d1.commonMethod();
    d1.anotherCommonMethod();

    Derived2 d2;
    d2.commonMethod();
    d2.anotherCommonMethod();
}

由如上代码可知,CBase模板类作为一个接口,定义了一个commonMethod方法,它通过CRTP的方式调用派生类中的方法implementation。派生类Derived1和Derived2都继承自CBase,并实现了implementation方法。通过CRTP,我们可以在基类中调用派生类的方法,而不需要使用虚函数的运行时开销。

扩展

CRTP在C++标准库中有广泛应用,模板类std::enable_shared_from_this便是其中之一,应用代码如下:

代码语言:javascript
代码运行次数:0
复制
class MyClass : public std::enable_shared_from_this<MyClass> {
public:
void foo() 
{
// 在成员函数中调用 shared_from_this() 获取指向自身的 std::shared_ptr
std::shared_ptr<MyClass> ptr = shared_from_this();
std::cout << "SharedPtr count: " << ptr.use_count() << std::endl;
}
};

int using_enable() 
{
std::shared_ptr<MyClass> objPtr = std::make_shared<MyClass>();
// 在 MyClass 的成员函数中调用 shared_from_this() 方法
objPtr->foo();
return 0;
}

自定义类继承自模板类std::enable_shared_from_this,便可以在自定义类中使用模板类中的shared_from_this() 方法。注意需要自定义本身调用了shared_ptr的构造函数后,方可调用shared_from_this() 方法。

这是因为shared_from_this()使用模板类内持有的弱引用指针进行转换得到自身的共享指针shared_ptr。只有调用shared_ptr的构造函数且自定义类继承自std::enable_shared_from_this时才会给弱指针赋值。如果弱引用指针未被赋值,空指针强转会触发异常。

回归CRTP,自定义类需要将自身作为模板参数传递给 std::enable_shared_from_this,在派生类中才可以使用 std::enable_shared_from_this 提供的 shared_from_this() 方法。

如果将非自定义类作为模板参数传递给 std::enable_shared_from_this会出现编译错误,示例如下

代码语言:javascript
代码运行次数:0
复制
class A
{
public:
    A()=default;
    ~A()=default;
};

class MyClass : 
        public std::enable_shared_from_this<A> 
{
public:
void foo() {
//error, error C2440: “初始化”: 无法从“std::shared_ptr<A>”转换为“std::shared_ptr<MyClass>”
//std::shared_ptr<MyClass> ptr = shared_from_this();
//std::cout << "SharedPtr count: " << ptr.use_count() << std::endl;
    }
};

CRTP的应用场景

CRTP通常用于需要在编译期解决多态性问题的情况下,以提高代码性能和灵活性。一些常见的应用场景包括:

  • 实现静态多态性:通过CRTP可以在编译期实现多态性,而不需要虚函数的运行时开销,提高性能。
  • 实现策略模式:CRTP可以用于实现策略模式,将不同的策略封装在不同的派生类中,并在编译期确定使用哪种策略。
  • 实现优化的数据结构:CRTP可以用于实现优化的数据结构,例如静态多叉树、静态链表等,以提高性能和内存利用率。

结论

CRTP是一种强大的C++编程技巧,通过模板元编程实现了静态多态性和灵活性。尽管在一般情况下不太容易理解,但一旦掌握其原理和应用场景,便能发挥其巨大的作用。在实际项目中,我们可以将CRTP应用于各种场景,从而提高代码的性能和可维护性。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2025-02-13,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 程序员的园 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档