Thinking in C++ (1-9) C++为什么会成功

来源:互联网 发布:粉笔直播课淘宝 编辑:程序博客网 时间:2024/05/19 06:14

C++为什么会成功

C++之所以会这么成功,一部分当归功于C++设计的目标不仅仅是将C转变成一个面向对象的语言(尽管这就是它的设计初衷),而且还针对当今的开发者(尤其是那些已经在C上进行了大量投资的开发者)解决了很多其他问题。传统意义上,OOP编程语言受限于这样一种思路:我们必须丢弃过去的一切从头开始,学习一系列新的理论,新的语法,并声称从长远角度讲,丢弃一切由过程语言所带来的陈旧的包袱,将产生积极的效应。从长远角度上讲,这也许是正确的,但是就近期而言,这些所谓的包袱还是有价值的。最有价值的东西并不是现有的代码架构(如果有成熟的技术手段,代码可以使用工具自动迁移到新的版本),而是现有的知识体系。如果你是一个经验丰富的C程序员,但是你必须丢弃你在C语言上的所有成就从而适应一门新的语言,你的工作效率立刻就会下降,而且会持续几个月,直到你接受了新语言的各种思想。但是如果你可以利用现有的C语言的知识体系,你可以在你原先的知识的基础上,顺利地走进面向对象的世界,并且继续保持原有的工作效率。由于每个人对于编程都有自己独特的思维模型,尽管不需要面对学习一门全新的语言,但是在现有的完整的语言体系下加入而外的开支,这种迁移依然显得很难进行。所以简而言之,C++的成功的秘诀在经济:迁移到OOP依然需要成本,只是C++有可能[1]将成本控制的更低。

C++设计的目标是为了提高生产率。生产率与多种因素相关,但是语言设计的初衷是尽可能多地为你提供帮助,尽量可能多的提供宽松的规则和丰富的功能。C++的设计初衷是让其成为一门实用型语言,它的设计思路取决于如何为用户最大限度地提供方便。(至少从C语言的角度上看是这样的)

一个更优秀的C语言

如果你在C++环境中继续使用C编写代码,你仍然会直接得到好处,因为C++弥补了C语言中的很多缺陷,并且提供了更好的类型检查和编译时分析。编译器强迫你声明函数以便在调用它们的时候进行检查。预处理器的使用(值代换和宏)将被严格限制, 这样可以排除很多由其带来的难于寻找的bugC++有一个新功能叫做“引用(reference)”它为我们带来了更方便的途径以查询/调用函数参数和返回值的地址。C++通过一个新功能函数重载(function overloading)提高了名字管理的效率。名字空间(namespace)同样提高了语言对名字控制的能力。提高C原有的安全性能的小功能还有很多。

平滑过渡

学习一门新的语言的问题在于生产率。没有一个公司愿意承担一个优秀的软件工程师由于学习一门新的语言而突然降低了生产率。C++是对C语言的扩展,并没有使用全新的语法和编程模型。它允许你继续编写现有的C语言代码,与此同时,通过你的学习和对C++的理解不断加深,逐渐地把新的特征应用到现有代码中。这也许是C++如此成功的最主要原因之一。

另外,你所有现有的C代码都可以被C++兼容,但是由于C++编译器要求更加苛刻,因此在重新编译这些代码时,你可能会发现一些潜在的错误。

效率

有时牺牲程序运行速度换取程序员的生产率是可行的。举例说,一个商业模型,它的寿命可能很短,于是更快速的创建这些模型就比模型的运行速度更快更加重要了。然而,大多数应用程序需要某种程度的高效,所以C++常常过分强调效率的重要性。这是因为C程序员都是非常注重效率的,他们很难容忍程序的体积笨重和运行缓慢。在现有的程序效率低下时,C++中的一些新功能也能起到提高效率的作用。

使用C++语言,你不仅仅拥有同C语言同样的底层编程能力(在C++程序中同样可以直接嵌入汇编语言),但是据一些传说显示出,一个面向对象的C++程序与C语言编写的程序的效率之差只有±10%,甚至可能更小[2]。相对而言,面向对象的程序的设计思想实际上要比C语言更高效。

系统更易表达和理解

为解决特定问题所设计出的类可以更好的表达系统。这意味着你编写代码时,在问题空间中就描述了你的解决方案(“插入电子钥匙自动启动设备”),而不是按计算机的思路,也就是在解空间描述问题(“手动调整设备芯片以启动设备”)。你可以通过更高级的理念来解决问题,每一行代码可以做比原来更多的事情。

易于表达所带来的另外的好处就是易于维护,如果报道可信,维护在程序的整个生命周期中占据了大量的成本。如果一个程序更移动,那么它就更易于维护。这也可以降低文档的创建和维护工作的成本。

空前强大的库

创建程序最快捷的方法就是使用现有的代码——库。C++的主要成就之一就是拥有更易用的库。这得益于库的数据类型的转变(类),使用库的一项功能就意味着为语言添加了一个新的数据类型。由于C++编译器负责监视库的使用(保证正确的初始化和清理,确保函数正确的调用),你就可以把焦点放在库的功能上,而并不是这些功能是如何实现的。

使用C++的名字空间功能,名字可以真对部分程序隐藏起来。这样你就可以自由的使用库,而不用担心在C中经常会出现的名字冲突问题了。

利用模板复用源代码

通常有一些意义重大的类,它们需要源代码做出修改才能高效的复用。C++模板(template)这一功能可以让源代码自动的适应,这使得这些源代码成为了复用库代码的极其强大的工具。使用模板功能创建的数据类型可以毫不费力的对其他数据类型进行操作。模板可以对客户端程序员隐藏代码复用的复杂度,所以说模板功能非常的振奋人心。

错误处理

C语言中对异常的处理可以说是臭名昭著,人们通常都会忽视它,即使考虑也是束手无策。如果你创建了一个大型的复杂的程序,那么没有什么比存在一个错误而你又不知道它在哪里更糟的事情了。C++中的异常处理(exception handling)(这一卷中简要介绍,在第二卷中详细讨论,可以在www.BruceEckel.com下载到)可以确保错误必须受到重视,并且必须对其进行某种处理。

大型程序设计

多数传统的语言在内部对于程序的规模和复杂度都有一定的限制。比如说BASIC,它可以迅速为一些简单的常见的问题提供解决方案,但是如果代码长度超过几页纸之后,或者在其主要领域以外涉及到一些新的范畴时,使用BASIC就有陷入沼泽地的感觉。C语言也一样有这样的局限性。举例说,当一个程序超出50,000行时,名字冲突将开始困扰你——所有的函数名和变量名已经使用殆尽。另一个问题就是C语言自身的一个缺陷——一些小小的错误常常会被冗长的代码所淹没。

并没有证据清晰地告诉程序员哪个语言是你失败的罪魁祸首,即使有的话,他也不会当回事。他不会说“我的BASIC程序太大了,我要用C重新写一遍!”而是去尝试在已有的代码上硬塞进去一些新功能。于是额外的成本不知不觉地添加进来了。

C++设计的目的就是为了适应大规模应用程序,此时,我们可以忽略小程序与大程序之间的差别。在你编写hello-world这样的应用程序时,显然不需要OOP,模板,名字空间,异常处理这些C++的新特征,但是这些功能却始终是可用的,随时等待你的差遣。同样的,编译器善于排除难缠的bug,对于大小程序一视同仁。


[1] 我说“有可能”是因为,考虑到C++复杂度,迁移到Java可能更为节省。但是语言的选择涉及到许多因素,在这本书中我假设你选择了C++

[2] 请参见《C/C++使用者》刊物上的Dan Saks专栏,那里有对C++中库的性能的考查。

 
原创粉丝点击