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

2024-09-04 05:28

本文主要是介绍奇异递归模板模式(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中实现了+=,-=

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

这篇关于奇异递归模板模式(Curiously Recurring Template Pattern)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1135115

相关文章

poj3468(线段树成段更新模板题)

题意:包括两个操作:1、将[a.b]上的数字加上v;2、查询区间[a,b]上的和 下面的介绍是下解题思路: 首先介绍  lazy-tag思想:用一个变量记录每一个线段树节点的变化值,当这部分线段的一致性被破坏我们就将这个变化值传递给子区间,大大增加了线段树的效率。 比如现在需要对[a,b]区间值进行加c操作,那么就从根节点[1,n]开始调用update函数进行操作,如果刚好执行到一个子节点,

C++11第三弹:lambda表达式 | 新的类功能 | 模板的可变参数

🌈个人主页: 南桥几晴秋 🌈C++专栏: 南桥谈C++ 🌈C语言专栏: C语言学习系列 🌈Linux学习专栏: 南桥谈Linux 🌈数据结构学习专栏: 数据结构杂谈 🌈数据库学习专栏: 南桥谈MySQL 🌈Qt学习专栏: 南桥谈Qt 🌈菜鸡代码练习: 练习随想记录 🌈git学习: 南桥谈Git 🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈�

在JS中的设计模式的单例模式、策略模式、代理模式、原型模式浅讲

1. 单例模式(Singleton Pattern) 确保一个类只有一个实例,并提供一个全局访问点。 示例代码: class Singleton {constructor() {if (Singleton.instance) {return Singleton.instance;}Singleton.instance = this;this.data = [];}addData(value)

poj 1258 Agri-Net(最小生成树模板代码)

感觉用这题来当模板更适合。 题意就是给你邻接矩阵求最小生成树啦。~ prim代码:效率很高。172k...0ms。 #include<stdio.h>#include<algorithm>using namespace std;const int MaxN = 101;const int INF = 0x3f3f3f3f;int g[MaxN][MaxN];int n

uva 1342 欧拉定理(计算几何模板)

题意: 给几个点,把这几个点用直线连起来,求这些直线把平面分成了几个。 解析: 欧拉定理: 顶点数 + 面数 - 边数= 2。 代码: #include <iostream>#include <cstdio>#include <cstdlib>#include <algorithm>#include <cstring>#include <cmath>#inc

uva 11178 计算集合模板题

题意: 求三角形行三个角三等分点射线交出的内三角形坐标。 代码: #include <iostream>#include <cstdio>#include <cstdlib>#include <algorithm>#include <cstring>#include <cmath>#include <stack>#include <vector>#include <

poj 2104 and hdu 2665 划分树模板入门题

题意: 给一个数组n(1e5)个数,给一个范围(fr, to, k),求这个范围中第k大的数。 解析: 划分树入门。 bing神的模板。 坑爹的地方是把-l 看成了-1........ 一直re。 代码: poj 2104: #include <iostream>#include <cstdio>#include <cstdlib>#include <al

最大流、 最小费用最大流终极版模板

最大流  const int inf = 1000000000 ;const int maxn = 20000 , maxm = 500000 ;struct Edge{int v , f ,next ;Edge(){}Edge(int _v , int _f , int _next):v(_v) ,f(_f),next(_next){}};int sourse , mee

模版方法模式template method

学习笔记,原文链接 https://refactoringguru.cn/design-patterns/template-method 超类中定义了一个算法的框架, 允许子类在不修改结构的情况下重写算法的特定步骤。 上层接口有默认实现的方法和子类需要自己实现的方法

【iOS】MVC模式

MVC模式 MVC模式MVC模式demo MVC模式 MVC模式全称为model(模型)view(视图)controller(控制器),他分为三个不同的层分别负责不同的职责。 View:该层用于存放视图,该层中我们可以对页面及控件进行布局。Model:模型一般都拥有很好的可复用性,在该层中,我们可以统一管理一些数据。Controlller:该层充当一个CPU的功能,即该应用程序