ToB企服应用市场:ToB评测及商务社交产业平台

标题: 奇特递归模板模式(Curiously Recurring Template Pattern) [打印本页]

作者: 李优秀    时间: 2024-9-8 06:31
标题: 奇特递归模板模式(Curiously Recurring Template Pattern)
奇特递归模板模式(Curiously Recurring Template Pattern) - 知乎 (zhihu.com)
本文来自上面的文章!!!本菜鸡学习和记载一下。
CRTP是C++模板编程时的一种惯用法:把派生类作为基类的模板参数。
1.静态多态
  1. #include <iostream>
  2. using namespace std;
  3. template <typename Child>
  4. struct Base
  5. {
  6.         void interface()
  7.         {
  8.                 static_cast<Child*>(this)->implementation();
  9.         }
  10. };
  11. struct Derived : Base<Derived>
  12. {
  13.         void implementation()
  14.         {
  15.                 cerr << "Derived implementation\n";
  16.         }
  17. };
  18. struct test : Base<test>
  19. {
  20.         void implementation()
  21.         {
  22.                 cerr << "test\n";
  23.         }
  24. };
  25. int main()
  26. {
  27.         Derived d;
  28.         d.interface();  // Prints "Derived implementation"
  29.     test t;
  30.     t.interface();
  31.         return 0;
  32. }
复制代码
基类为Base,是模板类,子类Drived继续自Base同时模板参数为Drived,基类中有接口
interface而子类中有接口对应实现implementation,基类interface中将this通过static_cast转换为模板参数范例,这里是Drived,并调用该范例的implemention方法。
为什么是static_cast,而不是dynamic_cast?
因为只有继续了Base的范例才气调用interface且这里是向下转型,所以采用static_cast是安全的。
(不太明白)
通过CRTP可以使得类具有雷同于虚函数的效果,同时没有虚函数调用时的开销(虚函数调用时必要通过虚函数指针查找虚函数表进行调用),同时类的对象的体积相比利用虚函数也会减少(不必要存储虚函数指针),但是缺点是无法动态绑定。
2.
  1. template<typename Child>
  2. class Animal
  3. {
  4. public:
  5.         void Run()
  6.         {
  7.                 static_cast<Child*>(this)->Run();
  8.         }
  9. };
  10. class Dog :public Animal<Dog>
  11. {
  12. public:
  13.         void Run()
  14.         {
  15.                 cout << "Dog Run" << endl;
  16.         }
  17. };
  18. class Cat :public Animal<Cat>
  19. {
  20. public:
  21.         void Run()
  22.         {
  23.                 cout << "Cat Run" << endl;
  24.         }
  25. };
  26. template<typename T>
  27. void Action(Animal<T> &animal)
  28. {
  29.         animal.Run();
  30. }
  31. int main()
  32. {
  33.         Dog dog;
  34.         Action(dog);
  35.         Cat cat;
  36.         Action(cat);
  37.         return 0;
  38. }
复制代码
Dog继续自Animal且模板参数为Dog,Cat继续自Animal且模板参数为Cat
Animal,Dog,Cat中都声明了Run,Animal中的Run是通过范例转换后调用模板范例的Run方法实现的。在Action模板参数中吸收Animal范例的引用(或指针)并在此中调用了animal对象的Run方法,由于这里传入的是差别的子类对象,因此Action中的animal也会有差别的行为。
3.添加方法,减少冗余
  1. //Vec3
  2. struct Vector3
  3. {
  4.         float x;
  5.         float y;
  6.         float z;
  7.         Vector3() = default;
  8.         Vector3(float _x, float _y, float _z);
  9.         inline Vector3& operator+=(const Vector3& rhs);
  10.         inline Vector3& operator-=(const Vector3& rhs);
  11.         //....
  12. };
  13. inline Vector3 operator+(const Vector3& lhs, const Vector3& rhs);
  14. inline Vector3 operator-(const Vector3& lhs, const Vector3& rhs);
  15. //....
  16. //Vec2
  17. struct Vector2
  18. {
  19.         float x;
  20.         float y;
  21.         Vector2() = default;
  22.         Vector2(float _x, float _y);
  23.         inline Vector2& operator+=(const Vector2& rhs);
  24.         inline Vector2& operator-=(const Vector2& rhs);
  25.         //....
  26. };
  27. inline Vector2 operator+(const Vector2& lhs, const Vector2& rhs);
  28. inline Vector2 operator-(const Vector2& lhs, const Vector2& rhs);
  29. //....
复制代码
 范例Vector3必要实现+=,-=,+,-等运算符重载。
 范例Vector2必要实现+=,-=,+,-等运算符重载。
此中+=,-=这两个运算符可以采取+,-运算符实现,这时间可以把+=,-=给抽象出来,减少代码冗余。
  1. template<typename T>
  2. struct VectorBase
  3. {
  4.         T& underlying() { return static_cast<T&>(*this); }
  5.         T const& underlying() const { return static_cast<T const&>(*this); }
  6.         inline T& operator+=(const T& rhs)
  7.         {
  8.                 this->underlying() = this->underlying() + rhs;
  9.                 return this->underlying();
  10.         }
  11.         inline T& operator-=(const T& rhs)
  12.         {
  13.                 this->underlying() = this->underlying() - rhs;
  14.                 return this->underlying();
  15.         }
  16.        
  17.         //.....
  18. };
  19. struct Vector3 : public VectorBase<Vector3>
  20. {
  21.         float x;
  22.         float y;
  23.         float z;
  24.         Vector3() = default;
  25.         Vector3(float _x, float _y, float _z)
  26.         {
  27.                 x = _x;
  28.                 y = _y;
  29.                 z = _z;
  30.         }
  31. };
  32. inline Vector3 operator+(const Vector3& lhs, const Vector3& rhs)
  33. {
  34.         Vector3 result;
  35.         result.x = lhs.x + rhs.x;
  36.         result.y = lhs.y + rhs.y;
  37.         result.z = lhs.z + rhs.z;
  38.         return result;
  39. }
  40. inline Vector3 operator-(const Vector3& lhs, const Vector3& rhs)
  41. {
  42.         Vector3 result;
  43.         result.x = lhs.x - rhs.x;
  44.         result.y = lhs.y - rhs.y;
  45.         result.z = lhs.z - rhs.z;
  46.         return result;
  47. }
  48. //......
  49. int main()
  50. {
  51.         Vector3 v0(6.0f, 5.0f, 4.0f);
  52.         Vector3 v2(4.0f, 5.0f, 6.0f);
  53.         v0 += v2;
  54.         v0 -= v2;
  55.         return 0;
  56. }
复制代码
在VectorBase中实现了+=,-=
它们依靠子类的+和-运算符的实现。


免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。




欢迎光临 ToB企服应用市场:ToB评测及商务社交产业平台 (https://dis.qidao123.com/) Powered by Discuz! X3.4