C++ 使用constpublic成员强制所有实例的不变性是否合理?

C++ 使用constpublic成员强制所有实例的不变性是否合理?,c++,coding-style,constants,immutability,C++,Coding Style,Constants,Immutability,我有一个类——它基本上是一组字段的结构(比如说,类似于一个2-d点;但就这个问题而言,它只是一个合成的例子)——我只想要不可变的实例。显然,我可以将数据成员设置为私有,并且只有getter方法: class Point2d { protected: double x; double y; public: Point2d(double _x, double _y) : x(_x), y(_y) {} double getX() const { return x; }

我有一个类——它基本上是一组字段的结构(比如说,类似于一个2-d点;但就这个问题而言,它只是一个合成的例子)——我只想要不可变的实例。显然,我可以将数据成员设置为私有,并且只有getter方法:

class Point2d {
protected:
   double x;
   double y;

public:
   Point2d(double _x, double _y) : x(_x), y(_y) {}
   double getX() const { return x; }
   double getY() const { return y; }
   double norm() const { return x*x + y*y; }
}
但是,我在想也许这样做更好:

class Point2d {
public:
   const double x;
   const double y;

public:
   Point2d(double _x, double _y) : x(_x), y(_y) {}
   double norm() const { return x*x + y*y; }
   Point2d operator=(const Point2d& p) = delete;
}
Edit:第三种选择是在单个变量的声明中仅使用
const
ness强制实现不变性,类本身是可变的,即

class Point2d {
public:
   double x;
   double y;

public:
   Point2d(double _x, double _y) : x(_x), y(_y) {}
   double norm() const { return x*x + y*y; }
}

// ...

Point2d magicalTransformation(const Point2d& p1, const Point2d& p2);
实施不变性的更合理的方法是什么?

两者都可以

这两者之间很可能没有性能差异,因为
getX()
getY()
被优化为“无”。[您可能希望在
GetY
tho'中使用
returny;
,这可能有助于解决一两个错误]

这主要是风格的问题


当然,您可能还有一个
非const
版本的此类,用于在使用它之前对点进行计算

我不确定是否可以为这个问题提供一个事实,但在我看来,对像Point2D这样的小对象使用get和set是多余的。如果要将这些对象用作常量,只需将它们设置为常量即可。如果要将它们用作变量,则只需重载诸如“+”、“+=”等运算符并使用它们。应该封装作为数据成员的Point2D,而不是Point2D的数据成员。同样,如果要以不变的方式使用它们,只需使用
constpoint2d
。以后可能需要更改(以可变方式使用)Point2D的数据。常量数据成员对此类没有任何用途

这是否合理

对。在我看来,这是一种更好的风格,因为它提高了可读性。
无论如何,我更喜欢一个
const
(不可变)
public
成员,而不是getter方法。实际上,如果以正确的方式声明,每个数据类型都会发送特定的消息。例如:

  • const
    data=>该成员的状态不会改变 一生
  • public
    ==>成员在
    类之外读取
  • protected
    member==>在继承中读取该成员 继承权
  • private
    member==>该成员仅在
    class
    范围内读取
因此,这里的意图是明确的。只要确定成员在其生存期内不会更改,就可以声明该成员
const
。访问说明符应该根据潜在getter方法的使用位置来选择

另外,我真的需要范数方法上的const修饰符吗
const public
成员

对。最好是这样,因为对于
const
对象或其他
const
方法内部,您需要一个
const
正确的版本

编辑
关于修改后的问题。在
中有一个
常量
成员后,
操作符=
将被隐式删除,因此您不必
=删除它。这只是品味的问题。对我来说,它变得多余。
事实上,在g++编译器中,如果尝试使用赋值修改此类对象,编译器将自行生成错误,例如:

error: use of deleted function ‘Point2D& Point2D::operator=(const Point2D&)’
另一条语句是函数声明:

const Point2d findMagicPoint();

返回类型不需要是
const
,因为它无论如何是一个不可修改的右值。e、 g.
findMagicPoint()=格式不正确。

在设计类时,在灵活性和保证之间总是存在紧张关系。强制执行数据成员的常量(这排除了赋值)会导致一个非常严格的类:这会带来成本(失去灵活性),但收益是什么

当然,任何希望冻结实例的用户都可以使用
const
来冻结实例。因此,你没有给用户带来任何“新”功能,但你剥夺了他们的灵活性:值得吗

在这里,我认为您太极端了,因为赋值不起作用,您可能会发现在最常见的操作中使用类的实例时遇到困难(您可以创建它们的数组,但以后不能对数组进行排序)


因此,我建议您只需防止任何修改以外的转让。这足以毫不费力地维护类不变量。

不知道,但是无论您选择什么,您的方法都应该是
const
@juanchopanza:嗯,是的,当然。更正。取决于你问谁-样式只是那样-而不是法则。关于
norm()
const
-修饰符-既然所有数据成员都是常量,为什么编译器不推断它?这是因为继承吗?@ EnPoCulm,这是因为 CistasCase< /Cord>特性在C++中可用。注意,编译器只是查看头文件中函数的声明,以确定它是否正确。正文可以放在任何地方,而编译器可能不够聪明,无法确定数据在正文中保持不变。这将是太多的分析。因此,最好编写一个
const
版本。将再次修改第三个代码示例,使其不仅仅是一个右值。@einpoklum,
const
成员始终是一个更好的选择,因为它概括了对象不可变的事实。在整个代码中,查看哪个
Point2D
被声明为
const
是不切实际的。当作为参数传递时,您可以声明
const Point2D&
,但这不足以传达
Point2D
的值在整个代码库中是不可变的消息。
常量数据成员对此类没有任何用途。
。。。这是即兴的