C++ 使用constpublic成员强制所有实例的不变性是否合理?
我有一个类——它基本上是一组字段的结构(比如说,类似于一个2-d点;但就这个问题而言,它只是一个合成的例子)——我只想要不可变的实例。显然,我可以将数据成员设置为私有,并且只有getter方法: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; }
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方法。实际上,如果以正确的方式声明,每个数据类型都会发送特定的消息。例如:
data=>该成员的状态不会改变 一生const
==>成员在public
类之外读取
member==>在继承中读取该成员 继承权protected
member==>该成员仅在private
范围内读取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
的值在整个代码库中是不可变的消息。常量数据成员对此类没有任何用途。
。。。这是即兴的