what is "object-oriented programming"(1991 revised version)
bjarne stoustrup 【程序编程相关:基本形状开发(2)】 【推荐阅读:GNOME1.4Beta1发布】at&t bell laboratories 【扩展信息:基本形状开发】 murray hill,new jersey 07974 译者序 不要将本文简单地视为是对c++特征的一个介绍.它的意义在于,一方面介绍了编程风格的演变,以及这种演变背 后的动机 .另一个方面,它特别澄清了基于对象的(ob)与面向对象(oo)的异同,这是具有很大意义的.我们可以看到, 不管是ob还是oo,都不过是一种程序的组织形式. 这在很大程序上指出了oo着眼于解决什么样的问题 (程序如何组织才能有弹性,容易重用与理解),而不解决什么问题(数据结构的设计,算法的设计)等等. 摘要 “面向对象编程”与“数据抽象”已经成为常用的编程术语,然而,很少有人能够就它们的含义取得一致的认识; 本文以ada,c++,module 2,simula与smalltalk等语言为背景对此给出一个非正式的定义.基本的想法是将“支持数 据抽象”等同于定义与使用新数据类型的能力,而将“支持面向对象编程”等同于对类层次的表达能力.同时,还 讨论了通用编程语言为支持此种编程风格而必须提供的机制.文中虽然采用c++来表述问题,但其讨论的范围并不 仅限于这个语言. 1 介绍 并不是所有的语言都是面向对象的.一般认为,apl,ada,clu,c++,loops与smalltalk是面向对象的,我也曾经听说 过关于使用c, pascal,module-2,与chill进行面向对象设计的讨论.那么是否可以尝试使用fortran与cobol来进行 面向对象设计呢?我认为那也一定是可行的.在很多圈子里,“面向对象”已经成为“优秀”的高科技代名词,在 商业出版领域可以看到有以下的三段论: ada是优秀的 面向对象是优秀的 所以ada是面向对象的 本文从通用编程语言的角度出发陈述了“面向对象”技术的概貌: 第2节比较了数据抽象与面向对象之间的异同,也将它们与其他的编程风格做了区分;同时,指出了为了支持不同 的编程风格所需的重要机制. 第3节陈述了为高效地支持数据抽象所需的语言机制. 第4节讨论了支持面向对象所需的设施. 第5节陈述了传统硬件体系结构与操作系统对于数据抽象与面向对象编程施加的限制. 文中例子程序使用c++来书写,这部分是出于介绍c++的目的,部分是因为c++是少数几个同时支持数据抽象,面向 对象程序设计与传统编程风格的语言.本文不讨论为支持特定高层语言特性而涉及的并发性与特殊硬件支持. 2.编程风格(programming paradigms) 面向对象编程是一种用来针对一类问题编写优质代码的编程技术.一个语言称为是“面向对象”的如果它支持 (support)面向对象风格的编程. 在这里存在一个重要的区别.一个语言称为是“支持”某种风格的编程技术的,如果它提供了便于实施(方便地, 安全地与高效地)该种风格编程的手段;反之,如果需要使用额外的技能与手段来获得基于某种风格的编码,则这 个语言就是不“支持”该种编程风格的,我们只能说这个语言“使能”(enable)了某种编程风格.举例来说,人们 可以使用fortran编写结构化程序,使用c语言编写类型安全的程序,在module-2中使用数据抽象技术,但是,这些 任务都具有不必要的困难性,因为这些语言都不“支持”那些编程风格. 对于某种编程风格的支持不仅意味着语言提供明确的并且可以直接使用的编程手段,而且还意味着在编译时间与运 行时间提供某种检查,以防止代码无意中偏离了该种风格.类型检查是一个特别明显的例子,二义性检查与运行时 间检查也可以扩充语言支持特定编程风格的能力.同时,象标准库与编程环境等等都可以增强这种支持. 并不一定说一个语言如果支持了某种特性,则它就一定优于其他没有支持该特性的语言.在这里存在着太多 的反例.重要的不是一个语言具有多少特性,而是它具有的特性是否能够在特定的领域内足以支持特定的编程风 格. 1.所有的特性必须是清晰,优雅地集成进语言的. 2.通过组合使用这些特性必须足以获得解决方案,而不再需要使用其他特性. 3.假冒的与“特殊目的”的特性必须尽可能的少. 4.所有的特性都不能在那些不使用它们的程序中强加上过多的开销. 5.用户只需要了解那些在程序中被明确使用的特性所构成的语言子集就可以编写程序. 最后两点可以概括为“程序员不会被他们不了解的东西伤害”.如果对于一个特性是否有用存在任何疑问,则该特 性就最好被抛弃.在语言中加上一个特性要远比从中或者从其文献中去掉一个容易得多. 以下将罗列一些编程风格以及支持它们的核心语言机制,但对此并不打算讨论得过于深入与繁琐. 2.1 过程化编程 最初的(可能也是目前最常用的)编程风格是: 决定需要那些过程 使用能够得到的最好的算法 设计的重点在于处理过程与执行运算的算法,语言为此提供了将参数传递给函数以及从函数中返回值的机制.与这 种思维方式相关的文献集中讨论了传参的不同方式,区分不同参数的方式,以及各种不同的过程(过程,函数, 宏)等等.fortran是最早的过程语言,algol60,algol68,c与pascal是一些后继的过程语言. 平方根函数是个典型的例子,它简单地产生传入参数的平方根.为此,该函数执行一个简单的数学运算: double sqrt(double arg) { //the code for calculting a square root } void some_function() { double root2 = sqrt(2); } 从程序结构的角度来看,函数理清了算法之间的杂乱关系. 2.2 数据隐藏 随着时间的推移,程序设计的重点从重于过程设计转向重于对数据的组织,这反映了程序规模的增长.数据与直接 操作数据的一集函数合称为一个模块.程序设计的风格变为: 决定需要那些模块 分解程序,使得数据隐藏在不同的模块之中 这种风格被称为“数据隐藏规则”.而在那些不必将数据与与它相关的过程绑定到一起的场合可以只使用过程程序 设计风格.特别地,那些用来设计“好的过程”的技术现在可以应用到模块之内的每个过程之上.最常见的例子是 定义一个堆栈模块,设计时有以下问题需要解决: 1.为堆栈模块提供一个用户接口(例如,函数 push()与pop() ) 2.保证堆栈的表示(例如,一个元素的阵列)只能通过模块的接口来访问 3.保证堆栈在它第一次被访问之前执行过初始化 ... 下一页