The Curiously Recurring Template Pattern (CRTP)

CRTP(Curiously Recurring Template Pattern)是一种C++编程技巧,通过让基类模板参数为派生类自身,实现特定功能。本文详细介绍了CRTP的定义、工作原理、潜在问题及其解决方案,并提供了一个使用示例。CRTP的主要优点在于它允许基类对派生类有特殊的访问权限,但需要注意方法隐藏的问题。作者建议,如果已熟悉CRTP,可以直接阅读第三部分,了解一个实用的CRTP辅助实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

The Curiously Recurring Template Pattern (CRTP) is a C++ idiom whose name was coined by James Coplien in 1995, in early C++ template code.

The “C” in CRTP made it travel the years in the C++ community by being this: a Curiosity. We often find definitions of what CRTP is, and it is indeed an intriguing construct.

But what’s even more interesting is what CRTP means in code, as in what you can express and achieve by using it, and this is the point of this series.

If you have used CRTP in your own code then you certainly know what it is useful for. In this case you may know most of what’s written in this series of posts (though you may want to give a quick glance to episode #2, just to make sure we’re in line), and you can just skip over to episode #3 where I propose a generic helper for CRTP, that I found helpful when using it in code.

What CRTP is

The CRTP consists in:

  • inheriting from a template class,
  • use the derived class itself as a template parameter of the base class.

This is what it looks like in code:

template <typename T>
class Base
{
    ...
};

class Derived : public Base<Derived>
{
    ...
};

The purpose of doing this is using the derived class in the base class. From the perspective of the base object, the derived object is itself, but downcasted. Therefore the base class can access the derived class by static_casting itself into the derived class.

template <typename T>
class Base
{
public:
    void doSomething()
    {
        T& derived = static_cast<T&>(*this);
        use derived...
    }
};

Note that contrary to typical casts to derived class, we don’t use dynamic_cast here. A dynamic_cast is used when you want to make sure at run-time that the derived class you are casting into is the correct one. But here we don’t need this guarantee: the Base class is designed to be inherited from by its template parameter, and by nothing else. Therefore it takes this as an assumption, and a static_cast is enough.

What could go wrong

If two classes happen to derive from the same CRTP base class we likely get to undefined behaviour when the CRTP will try to use the wrong class:

class Derived1 : public Base<Derived1>
{
    ...
};

class Derived2 : public Base<Derived1> // bug in this line of code
{
    ...
};

There is a solution to prevent this, that has been proposed by Marek Kurdej in the comments section. It consists in adding a private constructor in the base class, and making the base class friend with the templated class:

template <typename T>
class Base
{
public:
    // ...
private:
    Base(){};
    friend T;
};

Indeed, the constructors of the derived class have to call the constructor of the base class (even if you don’t write it explicitly in the code, the compiler will do his best to do it for you). Since the constructor in the base class is private, no one can access it except the friend classes. And the only friend class is… the template class! So if the derived class is different from the template class, the code doesn’t compile. Neat, right?

Another risk with CRTP is that methods in the derived class will hide methods from the base class with the same name. As explained in Effective C++ Item 33, the reason for that is that these methods are not virtual. Therefore you want to be careful not to have identical names in the base and derived classes:

class Derived : public Base<Derived>
{
public:
    void doSomething(); // oops this hides the doSomething methods from the base class !
}

The first time I was shown CRTP my initial reaction was: “wait, I didn’t get it”. Then I saw it a couple of other times and I got it. So if you didn’t get how it works, just re-read section 1 a couple of times, and that should do it (if it doesn’t just get in touch and I’ll be happy to talk with you about it).

To tell you the truth, I started by writing a huge blog post about CRTP, which would have been daunting to read completely I think. For that reason I decided to split it up into several logical parts, which constitute the episodes of this series. This post was relatively short, but was necessary to put the basics in place.

Next up: how the CRTP can be useful to your code.

Related articles:

 

#include <iostream>
using namespace std;
template <typename T>
class Animal{
	public:
	void eat (){
		T& anml = static_cast<T&>(*this);
		cout <<anml << "eat" << endl;
	}
};

class Dog : public Animal <Dog>{
	friend ostream & operator<<(ostream &out,Dog & d);
	public:
	void name(){
		cout << "dog" << endl;
	}
};

 ostream & operator<<(ostream &out, Dog& d)
{
   out << "Dog ";
    return out;
}

int main()
{
	Dog dog;
	dog.eat();
   return 0;
}

 

Android校园二手交易App项目源码(高分期末大作业),个人经导师指导并认可通过的高分设计项目,评审分98分,项目中的源码都是经过本地编译过可运行的,都经过严格调试,确保可以运行!主要针对计算机相关专业的正在做大作业、毕业设计的学生和需要项目实战练习的学习者,资源项目的难度比较适中,内容都是经过助教老师审定过的能够满足学习、使用需求,如果有需要的话可以放心下载使用。 Android校园二手交易App项目源码(高分期末大作业)Android校园二手交易App项目源码(高分期末大作业)Android校园二手交易App项目源码(高分期末大作业)Android校园二手交易App项目源码(高分期末大作业)Android校园二手交易App项目源码(高分期末大作业)Android校园二手交易App项目源码(高分期末大作业)Android校园二手交易App项目源码(高分期末大作业)Android校园二手交易App项目源码(高分期末大作业)Android校园二手交易App项目源码(高分期末大作业)Android校园二手交易App项目源码(高分期末大作业)Android校园二手交易App项目源码(高分期末大作业)Android校园二手交易App项目源码(高分期末大作业)Android校园二手交易App项目源码(高分期末大作业)Android校园二手交易App项目源码(高分期末大作业)Android校园二手交易App项目源码(高分期末大作业)Android校园二手交易App项目源码(高分期末大作业)Android校园二手交易App项目源码(高分期末大作业)Android校园二手交易App项目源码(高分期末大作业)Android校园二手交易App项目源码(高分期末大作业)Android校园二手交易App项目源码(高分期末大作业)Android校园二手交易App项目源码(高分期末大作业)And
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值