欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 财经 > 创投人物 > C++ CRTP技术(奇异递归模版模式)

C++ CRTP技术(奇异递归模版模式)

2025/5/9 9:33:09 来源:https://blog.csdn.net/jerryhe_com/article/details/147766571  浏览:    关键词:C++ CRTP技术(奇异递归模版模式)

C++ 的CRTP技术

最近了解到C++的CRTP技术,通过博客来这里记录一下。

我们首先可以了解一下什么是CRTP技术。CRTP是C++的一种高级模版变成模式。

他主要的用途有以下的几点:

  1. 编译时实现多态(静态多态):通过CRTP技术,可以在编译时实现所有绑定,不同于虚函数多态(在运行时进行对象的绑定),这样可以减少动态多态的时间开销。
  2. 基类声明公有接口 : 基类实现公有的接口,可以让派生类继承后进行动态实现,提高了代码的扩展性,满足开闭原则。

怎么实现CRTP技术

CRTP的本质就是通过模版的方式实现基类访问派生类。他的实现的方式就是将派生类的类型通过模版传递给到基类,然后调用派生类的函数。下面给到一个示例:

template <class Derive>
class Base
{
public:void function(){dynamic_cast<Derive*>(this)->function();}
};class Derive : public Base<Derive>
{
public:void function(){std::cout << "Type is Derive" << std::endl;}
};

这个时候,我们如果创建一个派生类的对象,我们可以通过基类的指针或者引用来管理派生类,并且可以调用派生类的函数,实现了一种多态的模拟

为什么不会出现循环

能想到这个问题说明你真的认真的在思考,因为Derive的创建依赖于Base的类型,Base的类型又同时因为模版依赖于Derive,这个时候难道不会出现循环依赖的问题吗?

答案是否定的,当然是否定的,如果是真的就不会有这项技术,想要彻底弄懂这个问题,我们就要从编译器的角度来理解模版。

模版
c++的编译器只会检查模版的定义,包括模板中的语法是否存在问题,但并不会检查模版中的模版类型,什么意思呢,具体就是,c++的模版参数允许使用不完整的类,比如我的模版参数使用了一个声明的类,模版也不会报错,他不会管我们在实现模版的时候这个类型是否完整,只要保证,我们在具体实例化这个模版参数的时候,保证模版参数是完整的。
再看这个问题,我们的疑惑是存在循环依赖,但是什么事循环依赖,循环依赖的本质是A依赖完整的B,B同时依赖完整的A,但是这里不存在这个问题,Base并不依赖完整的Derive,他只需要告诉他Derive这个类型即可,这个没有问题

CRTP技术的具体应用场景

对象计数是CRTP计数的最常用的应用场景
假如存在这样一种情况:

我想实现多态,同时对派生的所有类的对象进行计数。并且是每一种对象都能单独计数,而不是只能整个的计数。

如果是传统的多态显然是不能解决这个问题,为什么?一个很简单的思想就是基类中定义一个static静态变量,在所有对象构造的时候进行自加,析构的时候进行自减,这样貌似是可以解决这个问题,但是由于所有的派生类都是继承的一个基类,我们只能整体的计算,但是我如果知道某一个类型自己的对象的个数呢?这里就可以使用我们的CRTP技术。

因为模版的特点,不同的派生类本质上继承的是不同的基类。
下面给出一个模拟的实现;

#include <iostream>class Base
{
public:Base() { _all_count++; }~Base() { _all_count--; }static int getAllCount() { return _all_count;  }
private:inline static int _all_count = 0;
};
template <class Derive>
class Object : public Base
{
public:Object(){_count++;}void function(){dynamic_cast<Derive*>(this)->function();}~Object(){_count--;}static int getCount() { return _count;  }
private:inline static int _count = 0;
};class Derive1 : public Object<Derive1>
{
public:void function(){std::cout << "Type is Derive1" << std::endl;}
};class Derive2 : public Object<Derive2>
{
public:void function(){std::cout << "Type is Derive2" << std::endl;}
};int main()
{Derive1 d11, d12;Derive2 d21, d22, d23;std::cout << "Derive1 size : " << Derive1::getCount() << std::endl;std::cout << "Derive2 size : " << Derive2::getCount() << std::endl;std::cout << "All size : " << Base::getAllCount() << std::endl;return 0;
}

在这里插入图片描述

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com

热搜词