将成员变量声明为private

切记声明数据成员为private。它为客户提供了访问数据的一致,细微划分的访问控制,允许约束条件获得保证,而且为类的作者提供了实现上的弹性。

     protec并不比public更具有封装性


不应该将数据成员声明为public的三个理由

一、语法一致性

        如果数据成员不是public的,客户访问一个对象的唯一方法就是通过成员函数。如果在public接口中的每件东西都是函数,客户就不必绞尽脑汁试图记住当他们要访问一个类的成员时是否需要使用圆括号,他们只要使用就可以了,因为每件东西都是一个函数。


二、精确控制成员变量的处理

       如果你让一个数据成员为public,每一个人都可以读写访问它,但是如果你使用函数去得到和设置它的值,你就能实现禁止访问,只读访问和读写访问,甚至只写访问:

  1. class AccessLevels {
  2. public:
  3. ...
  4. int getReadOnly() const { return readOnly; }
  5. void setReadWrite(int value) { readWrite = value; }
  6. int getReadWrite() const { return readWrite; }
  7. void setWriteOnly(int value) { writeOnly = value; }
  8. private:
  9. int noAccess; // no access
  10. int readOnly; // read-only access
  11. int readWrite; // read-write access
  12. int writeOnly; // write-only access
  13. };
三、封装:

       如果你通过一个函数实现对数据成员的访问,你可以以后改以某个计算来替换这个数据成员,使用你的类的人不会有任何察觉。

例如,假设你正在写一个自动测速程序,当汽车通过,其速度便被计算并填入一个速度收集器内:

  1. class SpeedDataCollection {
  2. ...
  3. public:
  4. void addValue(int speed); // 添加一笔新数据
  5. double averageSoFar() const; // 返回平均速度
  6. ...
  7. };    

        现在考虑成员函数averageSoFar的实现:办法之一是在类中用一个数据成员来实时变化迄今为止收集到的所有速度数据的平均值。无论何时averageSoFar被调用,它需返回那个数据成员的值。另一个方法是在每次调用averageSoFar时重新计算,通过分析集合中每一个数据值做成这些事情。

        谁能说哪一个最好?在内存非常紧张的机器(如,一台嵌入式路边侦测设装置)上,或是一个很少需要平均值的应用程序中,每次都计算平均值可能是较好的解决方案;在一个频繁需要平均值的应用程序中,速度比较重要,且内存不成问题,保持一个实时变化的平均值更为可取。重点在于通过一个成员函数访问平均值(也就是说将它“封装”),你能替换这两个不同的实现(也包括其他你可能想到的)。

        封装可能比它最初显现出来的更加重要。如果你对你的客户隐藏你的数据成员(也就是说,封装它们),你就能确保类的约束条件总能被维持,因为只有成员函数能影响它们。此外,你预留了日后变更实现的权利如果你不隐藏你将很快发现,即使你拥有类的源代码,你改变任何一个public的东西的能力也是非常有限的,因为有太多的客户代码将被破坏。public意味着没有封装,没有封装意味着不可改变,尤其是被广泛使用的类。被广泛使用的类是最需要封装的,因为它们可以从一种更好的实现中得益。



为什么不应该声明protected数据成员?

        反对protected数据成员的理由和public数据成员是类似的。关于语法一致性和细微划分之访问控制等理由显然也适用于protected数据,就连封装性上protected数据成员也不比public数据成员更好。

        某些东西的封装性与“当其内容改变时可能造成的代码破坏量“成反比。所谓改变,也许是从类中移除它(就像上述的averageSoFar)。

        假设我们有一个public数据成员,随后移除它,所有使用了它的客户代码都被破坏,其数量通常大得难以置信,因此public数据成员是完全未封装的。但是,假设我们有一个protected数据成员,随后我们移除了它。现在有多少代码会被破坏呢?所有使用了它的派生类都被破坏,典型情况下,代码的数量还是大得难以置信,因此protected数据成员就像public数据成员一样没有封装。在这两种情况下,如果数据成员发生变化,被破坏的客户代码的数量都大得难以置信。一旦你声明一个数据成员为public或protected,而且客户开始使用它,就很难再改变与这个数据成员有关的任何事情。有太多的代码不得不被重写,重测试,重文档化,或重编译。

       从封装的观点来看,实际只有两个访问层次:private(提供了封装)与其他(没有提供封装)

猜你喜欢

转载自blog.csdn.net/u010248077/article/details/80918576