1.3 实现的隐藏
把程序员划分为类创建者(创建新数据类型的人)和客户程序员[1](在应用程序中使用数据类型的类的用户)是有益的。客户程序员的目标是去收集一个装满类的工具箱,用于快速应用开发。类创建者的目标是去建造类,这个类只暴露对于客户程序员是必需的东西,其他的都隐藏起来。为什么呢?因为如果是隐藏的东西,客户程序员就不能使用它,这意味着,这个类的创建者可以改变隐藏的部分,而不用担心会影响其他人。被隐藏的部分通常是对象内部的管理功能,容易受到粗心或无知的客户程序的损害,所以隐藏实现会减少程序错误。隐藏的概念怎么强调都不过分。
在任何关系中,确定一个所有的参与者都遵从的边界是重要的。当我们创建一个库时,也就与客户程序员建立了关系。他们也是程序员,但是他们是通过使用我们的库来组装应用程序,也可能建立更大的库。
如果类的所有成员对于任何人都能用,那么客户程序员就可以用这个类做其中的任何事情,不存在强制规则。虽然我们可能实际上不希望客户程序员直接操纵这个类的某些成员,但是因为没有访问控制,所以就没有办法保护它,所有的东西都暴露无遗。
访问控制的第一个理由是为了防止客户程序员插手他们不应当接触的部分,也就是对于数据类型的内部实施方案是必需的部分,而不是用户为了解决他们的特定问题所需要的接口部分。这实际上是对用户的很好服务,因为这使得他们容易看到哪些部分对于他们是重要的,哪些部分是可以忽略的。
访问控制的第二个理由是允许库设计者去改变这个类的内部工作方式,而不必担心这样做会影响客户程序员。例如,库设计者可能为了容易开发而用简单的方法实现了一个特殊的类,但后来发现需要重写这个类以使得它运行得更快。如果接口和实现是严格分离和被保护的,那么库设计者就可以很容易完成重写任务,用户只需要重新连接就可以了。
C++语言使用了三个明确的关键字来设置类中的边界:public、private和protected。它们的使用和含义相当简明。这些访问说明符(access specifier)确定谁能用随后的定义。public意味着随后的定义对所有人都可用。相反,private关键字则意味着,除了该类型的创建者和该类型的内部成员函数之外,任何人都不能访问这些定义。private在我们与客户程序员之间筑起了一道墙。如果有人试图访问一个私有成员,就会产生一个编译时错误。protected与private基本相似,只有一点不同,即继承的类可以访问protected成员,但不能访问private成员。我们将在稍后部分介绍继承。
[1]对于这个术语,我要感谢我的朋友Scott Meyers(名著《Effective C++》的作者—编辑注)。