1.2 关键词所带来的差异(A Keyword Distinction)(1)
如果不是为了努力维护与C之间的兼容性,C++(www.cppentry.com)远可以比现在更简单些。举个例子,如果没有8种整数需要支持的话,overloaded function的解决方式将会简单得多。同样道理,如果C++(www.cppentry.com)丢掉C的声明语法,就不需要花脑筋去判断下面这一行其实是pf的一个函数调用操作(invocation)而不是其声明:
- // 不知道下面是个 declaration 还是 invocation
- // 直到看到整数常量 1024 才能决定
- int ( *pf )( 1024 );
而在下面这个声明中,像上面那样的"向前预览(lookahead)"甚至起不了作用:- // meta-language rule :
- // pq 的一个 declaration,而不是 invocation
- int ( *pq )( );
当语言无法区分那是一个声明还是一个表达式(expression)时,我们需要一个超越语言范围的规则,而该规则会将上述式子判断为一个"声明"。
同样地,如果C++(www.cppentry.com)并不需要支持C原有的struct,那么class的观念可以借由关键词class来支持。但绝对令你惊讶的是,从C迁徙到C++(www.cppentry.com),除了效率,另一个最常被程序员询问的问题就是:什么时候一个人应该在C++(www.cppentry.com)程序中以struct取代class?
如果是1986年,我的答案毫不拖泥带水:"绝不"!在我的C++(www.cppentry.com) Primer第一版和第二版中(译注:第三版已于1998年5月出版),关键词struct并未出现在书籍本文,只出现在附录C中,而附录C用来讨论C语言。那时候,这是一个人非万不得已不会指出的一些小小哲学问题中的一个。然而如果能够指出这个问题,你可以获得一些小小(一般公认非常小)的满足。通常问题会被这样指出:"嘿,你知道吗,struct那个关键词,其实没什么用……"。但就像贝尔实验室(译注:Bell Lab.,C++(www.cppentry.com)发源地)的一位同事婉转对我说的,即使是最小的哲学问题也有人需要解答。如果一个C程序员渴望学习C++(www.cppentry.com),当他发现我的书中没有提到struct,一定会相当苦恼。很显然把这个主题含入,可以提供语言移转时的救生索,让程序员攀上高峰时少点折磨。呵,多么哲学啊!
关键词的困扰
那么,让我重新问一次:"什么时候一个人应该使用struct取代class?"答案之一是:当它让一个人感觉比较好的时候。
虽然这个答案并没有达到高技术水平,但它的确指出了一个重要的特性:关键词struct本身并不一定要象征其后随之声明的任何东西。我们可以使用struct代替class,但仍然声明public、protected、private等等存取区段与一个完全public的接口,以及virtual functions和单一继承、多重继承、虚拟继承……早期,似乎每个人都得在一小时的C++(www.cppentry.com)简介中花费整整10分钟看清楚以下两者的相同:
- class cplus_plus_keyword {
- public:
- // mumble ...
- };
和其C对等品:- struct c_keyword {
- // the same mumble
- };
当人们以及在教科书中说到struct时,他们的意思是一个数据集合体,没有private data,也没有data的相应操作(译注:指member function)。亦即纯然的C用法。这种用途应该和C++(www.cppentry.com)的"使用者自定义类型"(user-defined type)用法区别开来。在C这一边,这个关键词的设计理由因其用法而存在;而在C++(www.cppentry.com)那一边,选择struct或class"作为关键词,并用以导入ADT"的理由,是希望从此比较健全。这远比讨论"函数需不需要一个大括号",或是"要不要在变量名称和类型名称中使用下画线(例如IsRight或is_right)"更具精神层次。
在C所支持的struct和C++(www.cppentry.com)所支持的class之间,有一个观念上的重要差异。我的重点很简单:关键词本身并不提供这种差异。也就是说,如果一个人拥有下面的C++(www.cppentry.com)使用者自定义类型,他可以说"喔,那是一个class":
- // struct 名称(或 class 名称)暂时省略
- {
- public:
- operator int()
- virtual void foo();
- // ...
- protected:
- static int object_count;
- // mumble
- };
事实上你可以说上面那东西是个struct,也可以说它是个class。这两种声明的观念上的意义取决于对"声明"本身的检验。
举个例子,在cfront(译注:第一个C++(www.cppentry.com)实现品,由Lippman完成)之中,上述两个关键词在语意分析器(parser)中是以共享的"AGGR"替换的。而在Foundation项目中,Rob Murray的ALF层次结构保留了程序员真正使用的关键词。然而这份信息并未在更内层的编译器中被使用,倒是可以被一个"unparser"工具用来还原程序的ASCII面貌。啊,是的,如果程序经过"unparser"工具处理过后,无法还原原本使用的关键词,程序员一定会很郁闷--即使程序在其他方面是相等的。