奇特递归模板模式(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中实现了+=,-=
它们依靠子类的+和-运算符的实现。
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。 |