条款22:将成员变量声明为private

版权声明:仅供参考与学习交流 https://blog.csdn.net/lym940928/article/details/81948643

条款22:将成员变量声明为private

Declare data members private.

封装

首先,对于成员变量而言,如果成员变量不是public,那么用户唯一能访问对象的办法就是通过成员函数。

  • 使用函数可以使得我们队成员变量的处理有这更精确的控制。

举个例子:

class AccessLevels {
public:
    ...
    int getReadOnly() const { return readOnly; }
    void setReadWrite(int val) { readWrite = val; }
    int getReadWrite() const { return readOnly; }
    void setWriteOnly(int val) { WriteOnly = val; }
private:
    int noAccess;   //对此int没有任何访问操作
    int readOnly;   //对此int做只读访问(read-only)
    int readWrite;  //对此int做读写访问(read-write)
    int writeOnly;  //对此int做唯写访问(write-only)
};

这是其中一个方面,另一个方面则是C++的一个重要特性:

  • 封装!
    如果我们想要通过函数访问成员变量,日后可改某个计算,来替换这个成员变量时,class用户一点也不会知道class的内部实现已经发生了改变。

再举个例子,对于汽车的自动测速程序,当汽车通过时,其速度被计算并填入一个速度收集器之中:

class SpeedDataCollection {
    ...
public:
    void addVal(int speed);         //添加一笔数据
    double averageSoFar() const;    //返回平均速度
    ...
};

对于上面的成员函数averageSoFar,它的实现可以有以下两种方法:

  • 在class内设计一个成员变量,记录至今以来所有速度的平均值。当averageSoFar函数被调用时,直接返回对应的变量即可。
  • 令averageSoFar每次被调用时都重新计算平均值,此函数有权查询收集器中的每一笔速度数据。

对于上面的第一种方法,缺点是会使得SpeedDataCollection对象变大,因为我们必须为用来存放目前平均值、积累总量、数据点数的每一个成员变量都分配空间。优点则是averageSoFar会非常的高效,它可以只是一个返回目前平均值的inline函数。
相反,对于第二种办法则,执行速度慢而SpeedDataCollection对象比较小。

到底哪种办法更好,这需要根据实际情况而定。重点是,因为通过成员函数来访问平均值,我们就相当于对其进行了封装,于是我们得以替换不同的实现方式。

将成员变量隐藏在函数接口之后,可以为“所有可能的实现”提供弹性。例如:
- 可以使得成员变量在被读或被写时轻松的通知其他对象;
- 可以验证class的约束条件以及函数的前提和事后状态;
- 可以在多线程换将中执行同步控制;
- 等等;

这种能力等价于其他语言中的“properties”,尽管额外需要一组小括号。

封装的重要之处在于,如果我们对用户隐藏成员变量(即封装),我们就可以确保class的约束条件总是会得到约束,因为只有成员函数可以影响它们。
我们同时也保留了日后变更实现的权利。如果我们不隐藏它们,即使拥有class原始码,改变任何public事物的能力还是极端受到束缚的,因为这样会破坏太多原始码。
public意味着不封装,而不封装意味着不可改变,特别是广泛使用的classes而言。
因此:
- 被广泛使用的classes是最需要封装的一个族群。

Protected

对于protected成员变量而言,论点也非常的相似。
“语法一致性”和“细微划分的访问控制”这些理由也同样适用于protected数据,就像对public一样。
然而,protected成员变量的封装性并非高于public成员变量。

首先,假设我们有一个public成员变量,而我们最终取消了它,那么所有使用它的客户码都会被破坏!,因此:

  • public成员变量完全没有封装性。

然而,假设我们有一个protected成员变量,而我们最终取消了它,那么所有使用它的derived classes都会被破坏!因此:

  • protected成员变量像public成员变量一样缺乏封装性。

一旦你将一个成员变量声明为public或protected而用户开始使用它,就很难改变这个变量所涉及的一切!总结说来,其实只有两种访问权限:

  • private(提供封装)
  • 其他(不提供任何封装)

最后:

1,切记将成员变量声明为private。这可以赋予客户访问数据的一致性、可细微划分访问控制、允诺约束条件获得保证,并提供class作者以充分的实现弹性。

2,protected并不比public根据封装性。

猜你喜欢

转载自blog.csdn.net/lym940928/article/details/81948643