当前位置: 首页 > article >正文

奇异递归模板模式(Curiously Recurring Template Pattern)

奇异递归模板模式(Curiously Recurring Template Pattern) - 知乎 (zhihu.com)

本文来自上面的文章!!!本菜鸡学习和记录一下。

CRTP是C++模板编程时的一种惯用法:把派生类作为基类的模板参数。

1.静态多态

#include <iostream>
using namespace std;

template <typename Child>
struct Base
{
	void interface()
	{
		static_cast<Child*>(this)->implementation();
	}
};

struct Derived : Base<Derived>
{
	void implementation()
	{
		cerr << "Derived implementation\n";
	}
};

struct test : Base<test>
{
	void implementation()
	{
		cerr << "test\n";
	}
};

int main()
{
	Derived d;
	d.interface();  // Prints "Derived implementation"

    test t;
    t.interface();
	return 0;
}

基类为Base,是模板类,子类Drived继承自Base同时模板参数为Drived,基类中有接口

interface而子类中有接口对应实现implementation,基类interface中将this通过static_cast转换为模板参数类型,这里是Drived,并调用该类型的implemention方法。

为什么是static_cast,而不是dynamic_cast?

因为只有继承了Base的类型才能调用interface且这里是向下转型,所以采用static_cast是安全的。

(不太理解)

通过CRTP可以使得类具有类似于虚函数的效果,同时没有虚函数调用时的开销(虚函数调用时需要通过虚函数指针查找虚函数表进行调用),同时类的对象的体积相比使用虚函数也会减少(不需要存储虚函数指针),但是缺点是无法动态绑定。

2.

template<typename Child>
class Animal
{
public:
	void Run()
	{
		static_cast<Child*>(this)->Run();
	}
};

class Dog :public Animal<Dog>
{
public:
	void Run()
	{
		cout << "Dog Run" << endl;
	}
};

class Cat :public Animal<Cat>
{
public:
	void Run()
	{
		cout << "Cat Run" << endl;
	}
};

template<typename T>
void Action(Animal<T> &animal)
{
	animal.Run();
}

int main()
{
	Dog dog;
	Action(dog);

	Cat cat;
	Action(cat);
	return 0;
}

Dog继承自Animal且模板参数为Dog,Cat继承自Animal且模板参数为Cat

Animal,Dog,Cat中都声明了Run,Animal中的Run是通过类型转换后调用模板类型的Run方法实现的。在Action模板参数中接收Animal类型的引用(或指针)并在其中调用了animal对象的Run方法,由于这里传入的是不同的子类对象,因此Action中的animal也会有不同的行为。

3.添加方法,减少冗余

//Vec3
struct Vector3
{
	float x;
	float y;
	float z;

	Vector3() = default;

	Vector3(float _x, float _y, float _z);

	inline Vector3& operator+=(const Vector3& rhs);
	inline Vector3& operator-=(const Vector3& rhs);
	//....
};

inline Vector3 operator+(const Vector3& lhs, const Vector3& rhs);
inline Vector3 operator-(const Vector3& lhs, const Vector3& rhs);
//....

//Vec2
struct Vector2
{
	float x;
	float y;

	Vector2() = default;

	Vector2(float _x, float _y);

	inline Vector2& operator+=(const Vector2& rhs);
	inline Vector2& operator-=(const Vector2& rhs);
	//....
};

inline Vector2 operator+(const Vector2& lhs, const Vector2& rhs);
inline Vector2 operator-(const Vector2& lhs, const Vector2& rhs);
//....

 类型Vector3需要实现+=,-=,+,-等运算符重载。

 类型Vector2需要实现+=,-=,+,-等运算符重载。

其中+=,-=这两个运算符可以采取+,-运算符实现,这时候可以把+=,-=给抽象出来,减少代码冗余。

template<typename T>
struct VectorBase
{
	T& underlying() { return static_cast<T&>(*this); }
	T const& underlying() const { return static_cast<T const&>(*this); }

	inline T& operator+=(const T& rhs) 
	{ 
		this->underlying() = this->underlying() + rhs;
		return this->underlying();
	}

	inline T& operator-=(const T& rhs)
	{
		this->underlying() = this->underlying() - rhs;
		return this->underlying();
	}
	
	//.....
};

struct Vector3 : public VectorBase<Vector3>
{
	float x;
	float y;
	float z;

	Vector3() = default;

	Vector3(float _x, float _y, float _z)
	{
		x = _x;
		y = _y;
		z = _z;
	}
};

inline Vector3 operator+(const Vector3& lhs, const Vector3& rhs)
{
	Vector3 result;
	result.x = lhs.x + rhs.x;
	result.y = lhs.y + rhs.y;
	result.z = lhs.z + rhs.z;
	return result;
}

inline Vector3 operator-(const Vector3& lhs, const Vector3& rhs)
{
	Vector3 result;
	result.x = lhs.x - rhs.x;
	result.y = lhs.y - rhs.y;
	result.z = lhs.z - rhs.z;
	return result;
}
//......

int main()
{
	Vector3 v0(6.0f, 5.0f, 4.0f);
	Vector3 v2(4.0f, 5.0f, 6.0f);

	v0 += v2;
	v0 -= v2;

	return 0;
}

在VectorBase中实现了+=,-=

它们依赖子类的+和-运算符的实现。


http://www.kler.cn/a/294135.html

相关文章:

  • 【WPF】Prism学习(二)
  • 122、java的LambdaQueryWapper的条件拼接实现数据sql中and (column1 =1 or column1 is null)
  • [Linux网络编程]10-http协议,分别使用epoll和libevent两种方式实现B/S服务器
  • 论文 | The Capacity for Moral Self-Correction in LargeLanguage Models
  • 【vue3中el-table表格高度自适应】
  • 【CSS】什么是BFC?
  • 未雨绸缪:环保专包二级资质续期工程师招聘时间策略
  • Python和MATLAB(Java)及Arduino和Raspberry Pi(树莓派)点扩展函数导图
  • TYPE-C USB设计
  • [数据集][目标检测]轮胎检测数据集VOC+YOLO格式4629张1类别
  • 等保测评:如何构建安全的远程工作环境
  • 工作:GX WORKS标签的分类
  • Seata环境搭建
  • Unity TMP (TextMeshPro) 更新中文字符集
  • IDEA取消自动选择光标所在行
  • go面试:说一下 GMP 模型的原理
  • 关于IDEA的快捷键不能使用的原因
  • jQuery基础——Ajax
  • 如何免费将视频转换为 MP4?将视频转换为 MP4 的 5 种方法
  • Linux——redis主从复制、哨兵模式
  • Java程序分析工具
  • Python 操作大数据使用 Hadoop
  • Unity3D在2D游戏中获取触屏物体的方法
  • 做运营,发布时间很重要
  • Android Studio更新代码可正常运行但IDE报红
  • 【保姆级教程】使用 PyTorch 自定义卷积神经网络(CNN) 实现图像分类、训练验证、预测全流程【附数据集与源码】