C++ 更好地理解命名构造函数习惯用法

C++ 更好地理解命名构造函数习惯用法,c++,C++,我想创建一个以弧度或度数初始化的angle类,我想返回值,而不是angle对象。我发现命名构造函数可能是实现这一点最有效的方法,但我不能100%确定如何针对我的案例进行修改 #pragma once #define _USE_MATH_DEFINES #include <cmath> class Angle { public: static Angle toRadians(double value) { return Angle((value * M

我想创建一个以弧度或度数初始化的angle类,我想返回值,而不是angle对象。我发现命名构造函数可能是实现这一点最有效的方法,但我不能100%确定如何针对我的案例进行修改

#pragma once
#define _USE_MATH_DEFINES
#include <cmath>
class Angle
{
public:
    static Angle toRadians(double value) 
    {
        return Angle((value * M_PI / 180.0f));
    
    }
    static Angle toDegrees(double value) 
    {
        return Angle(value / 180.0f * M_PI);
    }
private:
    double angle;
    Angle(double value) : angle(value) {};

};

std::cout << Angle::toRadians(19.48); // Should print 0.33999014
#pragma一次
#定义使用数学定义
#包括
类角
{
公众:
静态角超辐射(双值)
{
返回角((值*M_PI/180.0f));
}
静态角度到角度(双值)
{
返回角(值/180.0f*M_-PI);
}
私人:
双角度;
角度(双值):角度(值){};
};

std::cout您的
Angle
类缺少不变量。也就是说,除了“它包含一个double”之外,
Angle
类的任意对象都不能说是真的

考虑一下:如果我编写以下函数:

void do_something(Angle delta) {
  // do something
}
std::ostream& operator<<(std::ostream& stream, const Angle& angle) {
  stream << angle.asDegrees() << "deg";
  return stream;
}
如果delta可以包含度数或弧度,而我无法知道它是哪一个,我该如何处理它

信不信由你,这是你与建设者斗争的根源。这是因为构造函数的主要任务是将对象置于其不变状态。没有不变量意味着没有参考点,所以不清楚构造函数应该做什么

因此,让我们设置一个不变量,让我们自信地实现
do_something()
:“角度总是包含弧度”。你甚至可以用“.”来表示更紧的不变量,这个角度总是在
[-pi,pi[
范围内

很明显,您的
toRadians()
toDegrees()
命名构造函数在这种情况下毫无意义。事实上,它们从来没有真正意义过,但现在很明显。我们需要的是从其参数建立不变量的函数。
fromrradians()
fromrdegrees()
会更有意义

class Angle {
public:
    static Angle fromRadians(double value) 
    {
        return Angle(value);    
    }
    
    static Angle fromDegrees(double value) 
    {
        return Angle(value / 180.0 * M_PI);
    }

    double asRadians() const {
      return radians;
    }

    double asDegrees() const {
      return radians / M_PI * 180.0;
    }

private:
  Angle(double value) : radians(value) {}
  double radians;
};
请注意,对于这样实现的类,使用
Angle
类的代码甚至不必知道不变量。API只是说:角度可以由度或弧度构成,可以解释为度或弧度。您可以将不变量设置为地标,在实现类时为您提供指导。O一旦构建了类,它们就没有任何用途了,当然,除非您想更新代码


接下来,如果您希望能够轻松地将角度转储为人类可读的字符串,您可以实现
操作符您的
angle
类缺少一个不变量。也就是说,对于
angle
类的任意对象,除了“它包含一个双精度”之外,没有什么可以说是正确的

考虑一下:如果我编写以下函数:

void do_something(Angle delta) {
  // do something
}
std::ostream& operator<<(std::ostream& stream, const Angle& angle) {
  stream << angle.asDegrees() << "deg";
  return stream;
}
如果delta可以包含度数或弧度,而我无法知道它是哪一个,我该如何处理它

信不信由你,这是你与构造函数斗争的根源。那是因为构造函数的主要工作是将对象置于其不变状态。没有不变意味着没有参考点,因此不清楚构造函数应该做什么

因此,让我们设置一个不变量,让我们自信地实现
dou_something()
“角度总是包含弧度”。你甚至可以使用“.来更严格的不变量,并且该角度总是在
[-pi,pi[
范围内”

很明显,您的
toRadians()
toDegrees()
命名构造函数在这种情况下毫无意义。事实上,它们从来没有真正意义过,但现在很明显。我们需要的是从其参数建立不变量的函数。
fromrradians()
fromrdegrees()
会更有意义

class Angle {
public:
    static Angle fromRadians(double value) 
    {
        return Angle(value);    
    }
    
    static Angle fromDegrees(double value) 
    {
        return Angle(value / 180.0 * M_PI);
    }

    double asRadians() const {
      return radians;
    }

    double asDegrees() const {
      return radians / M_PI * 180.0;
    }

private:
  Angle(double value) : radians(value) {}
  double radians;
};
请注意,对于这样实现的类,使用
Angle
类的代码甚至不必知道不变量。API只是说:角度可以由度或弧度构成,可以解释为度或弧度。您可以将不变量设置为地标,在实现类时为您提供指导。O一旦构建了类,它们就没有任何用途了,当然,除非您想更新代码


接下来,如果希望能够轻松地将角度转储为可读字符串,则可以实现
运算符如果希望函数将度值作为双精度值,并将弧度值作为双精度值返回,则只需生成
双toRadians(双角度)
函数。此处不需要类。
value*M_PI/180.0f
value/180.0f*M_PI
是相同的。和*@doug之间没有优先级差异,但结果可能不同,因为该表达式是从左到右计算的。请尝试使用和see@viidawg你到底为什么要用180.0f的Everything是double,但文字是float。在这种情况下可能没有什么区别,但在其他情况下会导致巨大的偏差。如果您想要一个函数,它将度值作为double,并将弧度值作为double返回,那么只需生成一个
双toRadians(双角度)
函数。此处不需要类。
value*M_PI/180.0f
value/180.0f*M_PI
是相同的。和*@doug之间没有优先级差异,但结果可能不同,因为该表达式是从左到右计算的。请尝试使用和see@viidawg你到底为什么要用180.0f的Everything是double,但literal是float。在这种情况下可能没有什么区别,但在其他情况下会导致巨大的偏差