CppCoreGuidelines C.134 确保非const的成员数据有同级别的访问层级
C.134: 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。通常是为了调试。一个封装的对象可能有一些非 const
的调试数据。这些数据不算类的不变式,所以属于 A 类。这些数据也不是对象的部分值或有意义的状态。这种情况,A 类部分的数据就当作公开数据处理(或者 protected
,如果只想在派生类中访问)。B 类部分的数据仍然作为 B 类数据对待,要么是 private
要么是 const
。
强化
- 标注非
const
数据成员有不同的访问层级的类