ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

CRTP ( The Curiously Recurring Template Pattern)

2021-06-17 11:03:19  阅读:172  来源: 互联网

标签:setValue double void getValue class Curiously Pattern CRTP public


CRTP ( The Curiously Recurring Template Pattern)

什么是CRTP

  • 继承自模板类
  • 子类将自己作为模板参数传递给父类

如下:

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

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

这样的目的是在父类中可以使用子类。从父类的角度子类就是自己。父类通过static_cast将自己下降到子类来访问子类。

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

** 注意 ** 使用的是static_cast而不是dynamic_cast。

使用场景

一个类提供了一些函数,其他类也可以使用

例如有这样一个类Sensitivity代表了当给定一个值的时候,因为这个给定值的影响,他的产出是多少.

class Sensitivity
{
public:
  double getValue()const;
  void setValue(double value);
};

现在需要一些帮助函数,这样可以缩放或者开平方或者设置负值。

class Sensitivity
{
public:
  double getValue() const;
  void setValue(double value);

  void scale(double multiplicator)
  {
      setValue(getValue() * multiplicator);
  }
  void square()
  {
      setValue(getValue() * getValue());
  }
  void setToOpposite()
  {
      scale(-1);
  };

  // rest of the sensitivity's rich interface...
};

如果我们有另外一个类,同样有一个值,也需要这样三个帮助函数。我们使用CRTP,3个帮助函数可以放到另一个类中:

template <typename T>
struct NumericalFunctions
{
  void scale(double mult);
  void square();
  void setToOpposite();
};

class Sensitivity : public NumericalFunctions<Sensitivity>
{
public:
    double getValue() const;
    void setValue(double value);
    // rest of the sensitivity's rich interface...
};

这样,3个帮助函数需要从sensitivity访问到getValue和setValue这两个函数:


template <typename T>
struct NumericalFunctions
{
    void scale(double multiplicator)
    {
        T& underlying = static_cast<T&>( * this);
        underlying.setValue(underlying.getValue() * multiplicator);
    }
    void square()
    {
        T& underlying = static_cast<T&>( * this);
        underlying.setValue(underlying.getValue() * underlying.getValue());
    }
    void setToOpposite()
    {
        scale(-1);
    };
};

有趣的是虽然CRTP使用的是继承关系,但是和其他继承关系是有所不同的。父类并不是一个接口,子类并不是实现。父类使用子类的函数(getValue和setValue)。子类为父类提供了接口。

静态接口(static interfaces)

但并没有virtural关键字,而且是在编辑阶段进行的。

template <typename T>
class Amount
{
public:
    double getValue() const
    {
        return static_cast<T const&>(* this).getValue();
    }
};

有两个实现,一个返回值,一个设置值。

class Constant42 : public Amount<Constant42>
{
public:
    double getValue() const {return 42;}
};

class Variable : public Amount<Variable>
{
public:
    explicit Variable(int value) : value_(value) {}
    double getValue() const {return value_;}
private:
    int value_;
};

最后我们给客户端提供一个接口

template<typename T>
void print(Amount<T> const& amount)
{
    std::cout << amount.getValue() << '\n';
}
Constant42 c42;
print(c42);
Variable v(43);
print(v);

标签:setValue,double,void,getValue,class,Curiously,Pattern,CRTP,public
来源: https://www.cnblogs.com/ultramanX/p/14892501.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有