CRTP:一个继承 以自己为模板参数的模板类 的类

什么是CRTP?

The curiously recurring template pattern (CRTP) is a C++ idiom in which a class X derives from a class template instantiation using X itself as template argument.

翻译过来叫做”奇特的递归模板模式“,具体介绍请参看维基百科https://en.wikipedia.org/wiki/Curiously_recurring_template_pattern

简单的表述一下,类B继承了一个以B作为模板参数的的模板类A,这就是CRTP,代码如下:

template<typename T>
class A
{}
class B :public A<B> {}

CRTP有什么用?

在网上看了很多文章,大体上分为两种表述,一类是实现静态多态,二类是类计数器,单例模式等等

但仔细想想,这些看似花哨的功能到底作用在何处呢,似乎好像都可以通过其他方式来实现

CRTP核心特性

在我看来,CRTP最核心的特性有两点:

1、为不同的子类保留了不同的基类信息

2、让基类提前知道子类的信息,以做一些泛型操作

这两点听起来似乎有点不好理解,下面做一些解释

1、为不同的子类保留了不同的基类信息

class C :public A<C>
{}

还是在上述例子的基础上,此时有一个C类,在普通的继承模式下,B和C共享了同一个基类信息,而在此模式下,B和C保留了各自不同的特化基类A<B>和A<C>

在此基础上,与类相关的操作得以很容易的实现,最典型就是类的静态成员相关的操作,比如引用计数,再比如com思想中的uid的实现

template<typename T>
class A
{
public:
    A() {++m_nCounter; }
    ~A() {--m_nCounter; }

public:
    void printCount() { cout << m_nCounter << endl; }

private:
    static int m_nCounter;
};

template <typename T>
int A<T>::m_nCounter = 0;

class B :public A<B>
{
public:
    B() { }; 
    ~B() { }; 

    void printCountOfB() { printCount(); }

};

class C :public A<C>
{
public:
    C() { }; 
    ~C() { }; 

public:
    void printCountOfC() { printCount(); }
};

如上所示,B和C可以持有自己独立的类计数。

2、让基类提前知道子类的信息,以做一些泛型操作

最典型的例子,通过CTRP来实现单例模式的复用,在父类中通过模板参数预留接口。同时,该例子中也使用到了特性1,即让每个基类蕴含了一个独特的单例对象

template <typename T>
class Singleton
{
public:
    static T& Instance()
    {
        static T s_Instance;
        return s_Instance;
    }
    Singleton(const Singleton& rhs) = delete;
    Singleton& operator = (const Singleton& rhs)  = delete;
    Singleton(const Singleton&& rhs) = delete;
    Singleton& operator = (const Singleton&& rhs)  = delete;

protected:
    Singleton() = default;
    ~Singleton() = default 

};

class SingletonInstance : public Singleton<SingletonInstance>
{
    friend class Singleton<SingletonInstance>;
    ...
}

  

posted on 2021-09-16 11:01  二十一级厨子  阅读(787)  评论(0编辑  收藏  举报

导航