19 December 2022

C++ 核心指南目录

“Ensure all non-const data members have the same access level”

理由

避免导致错误的逻辑混淆。如果非 const 成员数据的访问层级不一样,我们就不太懂这个类型到底要做什么。这个类型维护一个不变式?还是只不过是一组值的集合?

讨论

核心问题是:哪些代码负责维护变量的有意义和正确的值?

有两种不同的成员数据:

  • A:不参与对象的不变式的成员数据,任何数据值的组合都是合法的。
  • B:参与对象的不变式的成员数据。只有某些值的组合是有意义的。(不然就不叫不变式)。因此,任何访问这些变量的代码都要知道其中的隐含的不变式和语义。而且知道并实现什么样的规则能确保值是正确的。

A 类数据成员只要 public 就可以了(或者,少数情况下,你只想要派生类能看到,设置成 protected)。他们不需要封装。系统中所有代码都可以访问并进行操作。

B 类数据应该是 private 或 const。因为对它们来说,封装很重要。如果他们不是 private,不是 const,意味着对象不能控制自己的状态:该类外部,其他不受限制的代码需要知道类的不变式,并参与维护。如果数据成员是公开的,那么所有使用该类的调用处要维护;如果数据成员是 protected,那么当前以及未来派生类的所有代码要参与维护。这样就会导致代码很脆弱、紧耦合,很快会成为代码维护的噩梦。任何不经意地把数据成员得值设置成无效的或不对的组合的时候,就会破坏对象的不变式,导致后续的使用出问题。

大部分类要么全是 A 要么全是 B:

  • 全 public:如果你在编写一组没有不变式关系的变量的聚合的时候,所有变量应该是公开 public 的。
  • 全 private:如果你写的某个类维护某种不变式关系,那么所有非 const 的变量都应该是 private,需要封装起来。

例外

偶尔的,某些类会混合 A 和 B。通常是为了 debug。一个封装的对象可能有一些非 const 的 debug 数据。这些数据不算类的不变式,所以属于 A 类。这些数据也不是对象的部分值或有意义的状态。这种情况,A 类部分的数据就当作公开数据处理(或者 protected,如果只想在派生类中访问)。B 类部分的数据仍然作为 B 类数据对待,要么是 private 要么是 const。

强化

  • 标注非 const 数据成员有不同的访问层级的类