这样的数字库中,通过将数据成员声明为 protected 或 public 来暴露数据是一个避免麻烦的办法。数据成员几乎总是一个实现细节。即使是在<code><complex></code> 这样的数字库中,通过将数据成员声明为 protected 或 public 来暴露数据是一个避免麻烦的办法。下面我将解释为什么 protected 类型的数据成员像 public 类型的数据成员一样糟糕。
Protected 类型数据成员的问题
当基类的实现发生变化时,能够访问基类 protected 类型数据成员的派生类也需要修改。这叫做耦合,耦合是面向对象的设计方法绝对需要避免的东西。
具体的例子
类complex 一般表示为一对浮点数据成员和一些额外的成员函数。它看上去似乎试图放弃传统的 get() 和 set() 成员函数,而赋予对这些成员的直接访问权。
template <class T> class complex
{
protected: //exposing data members to derived classes
T real;
T imaginary;
//..
};
这看上去像是一个故意的例子;然而,在 Standard Library 中确实存在具有 protected 类型数据成员的类。你可能会感到奇怪这么简单的类的设计会如何改变。一种方式是其他人可能使用一个数组代替了它的两个数据成员,如下所示:
template <class T> class complex
{
protected:
T val[2];
//..
};
或者也有可能是一些人将这两个成员包装为一个tuple类型或者包装成一个对(pair)。在这两种情况下,派生类也需要修改。你可能会争论说这些成员是受保护的,而不是公有的;因此,设计变化就只会影响派生类。问题是 protected 类型的数据成员引诱程序员滥用继承来获得对数据成员的直接访问。
结束语
你应该避免使用 protected 类型的数据成员,因为他们会造成对封装的一个错误的理解。相反,将数据成员声明为 private 类型并定义相应的成员函数来访问它们是必要的。通过使用这种方法,基类设计上的变化就不会影响其它类。此外,它也不会引诱程序员使用继承获得对数据成员的直接访问。最重要的是,基类的所有者可以自由地改变基类的实现,同时又保持原有接口不变,而不至引起检查所有的代码。