# [6] 综述
## FAQs in section [6]:
* [[6.1] C++ 是一种实用的语言吗?](#%5B6.1%5D)
* [[6.2] C++ 是一种完美的语言吗?](#%5B6.2%5D)
* [[6.3] 面向对象(OO)有什么用?](#%5B6.3%5D)
* [[6.4] 泛型(generic)编程有什么用?](#%5B6.4%5D)
* [[6.5] C++ 比 Ada 更好吗?(或 Visual Basic, C, FORTRAN, Pascal, Smalltalk,或其它的语言?)](#%5B6.5%5D)
* [[6.6] 谁在用C++?](#%5B6.6%5D)
* [[6.7] 学习 OO/C++ 需要多长时间?](#%5B6.7%5D)
* [[6.8] 从商业角度看 C++有哪些特征?](#%5B6.8%5D)
* [[6.9] 虚函数(动态绑定)对于OO/C++来说是主要的吗?](#%5B6.9%5D)
* [[6.10] 我来自密苏里州。你能给我一个理由,为什么虚函数(动态绑定)造成很大的不同?](#%5B6.10%5D)
* [[6.11] C++ 是否向下兼容 ANSI/ISO C?](#%5B6.11%5D)
* [[6.12] C++ 标准化了吗?](#%5B6.12%5D)
* [[6.13] 何处能得到 ANSI/ISO C++ 标准的拷贝?](#%5B6.13%5D)
* [[6.14]我可以问哪些“面试问题”来判断面试者真的懂了?](#%5B6.14%5D)
* [[6.15]当FAQ说“这些是_邪恶_的”,是什么意思?](#%5B6.15%5D)
* [[6.16]有时会用到那些“邪恶”的东西么?](#%5B6.16%5D)
* [[6.17]是否知道这些东西的技术定义很重要:“好的OO”,“好的类设计”?](#%5B6.17%5D)
* [[6.18]当人们抱怨说“FAQ”这个词太误导人了,因为它强调问题而不是答案,因此我们需要换一个不同的词,这时我应该怎么对他们说?](#%5B6.18%5D)
## 6.1 C++ 是一种实用的语言吗?
是的。
C++ 是一种实用的工具。[它不完美](#%5B6.2%5D),但是有用。
在软件产业的世界里,C++被看作一种可靠的,成熟的,主流的工具。它得到普遍的工业支持,因而从一种[全面的商业角度](#%5B6.17%5D)来看,它是“优秀”的。
## 6.2 C++ 是一种完美的语言吗?
不是。
C++的原设计目标不是作为完美的面向对象语言的典范。它被设计为一种实用的工具,来解决现实世界的问题。像所有的实用工具一样,它有瑕疵。不过,非完美就无用的,那是纯理论的框架。而不是C++的目标。
## 6.3 面向对象(OO)有什么用?
面向对象技术是我们所知道的开发大型的,复杂的软件应用和系统的最佳方法。
OO:应付大型的,复杂的软件系统时,软件工业是“失败的”。但是这种“失败”实际上归因于我们的_成功_:我们的成功使得用户想得到更多。不幸的是我们创造了市场的饥渴,而“结构化”的分析、设计和编程技术无法满足这种饥渴。因此需要我们创造一种更好的典范。
C++支持面向对象(OO)编程。C++ 也能够被当作传统的编程语言使用(作为“一种更好的 C”)或使用。基本上每种方法都有其优点和缺点。也不要在使用一种方法时期望得到另外一种技术的好处。(最常见的误解是,如果把C++“作为一种更好的C”来使用它,那么就不要期望得到面向对象所带来的好处。)
## 6.4 泛型(generic)编程有什么用?
C++支持泛型编程。泛型编程是一种能够最大化代码复用而又不损失效率的一种开发软件的方法。(这里的“效率”严格来说并非必须,但有了更好。)
泛型组件非常易用,并且一般会隐藏很多复杂性,当然前提是至少要设计得好。另外一个有趣的特性是它们能够使代码运行更快,尤其是当这些组件被更多地 使用时。这是一种很好的情形:当你用这些组件来完成一些繁杂的工作时,你的代码会变得更少更简单,出错的几率也小些,同时代码执行起来还更快。
大多数开发者并没有足够的能力来开发出这些泛型组件,但却能够使用它们。开发这些组件的过程是复杂痛苦的。你不断尝试、挠头、在凌晨3点有了灵感然 后起床,不断地重写代码(不断重写,不断重写)。一句话,要不断迭代。像谚语所说,这是在往5磅容量的口袋里塞10磅东西。不喜欢思考、不喜欢解决难题的 人就不必费这劲了。
幸运的是,泛型组件是,呃,很通用的。所以你所在的单位通常不必开发很多泛型组件。有很多已经做好的泛型组件,例如STL。[Boost](http://www.boost.org/)里面有更多的组件。还有很多其它的库。
## 6.5 C++ 比 Ada 更好吗?(或 Visual Basic, C, FORTRAN, Pascal, Smalltalk, 或其他语言?)
停!这样的问题没有意义。在对这个问题发表不同意见之前请先阅读下文。
99%的情况下,编程语言的选择是[出于商业上的考虑](#%5B6.17%5D), 而不是技术上 的考虑。真正重要的是类似以下方面的商业上的考虑:开发机器的编程环境,目标机器是否包含运行时环境,运行时和/或开发环境的许可/法律问题,是否有受过 训练的开发者,是否有咨询服务,和企业文化/政策。它们扮演的角色一般比编译期性能,运行时性能,静态还是动态类型,静态还是绑定等更为重要。
从纯粹的技术角度争论一种语言比另一种更好的人(他们忽略了商业问题其实更重要),正是暴露了他们自己技术上的缺乏,别听他们的。[商业问题比技术问题更重要](#%5B6.17%5D),任何没有意识到这一点的人注定会做出带来糟糕后果的决策。这些人对雇主来说是危险的。
## 6.6 谁在用 C++?
很多很多公司和政府部门,非常多。
有大量的开发者(并且因此有大量的底层有效支持,包括厂商,工具开发者,培训等等)是[C++的特征](#%5B6.8%5D)之一
## 6.7 学习 OO/C++ 需要多长时间?
一些公司成功地讲授标准的工业界的“短期课程”,将大学一学期的课程压缩到了一个星期40个小时。但是不论你在何处获得培训,要确保课程具有动手项 目,大多数人是在接手项目之后才将概念“凝结成形”,得以学成。即使得到最好的培训,人们也还没能准备好。(译注:指做实际的项目)
精通OO/C++需要6-12个月。如果身边有专家的话,会少些。如果没有一个“好的”通用型的C++类库,则会多一些。成为可以指导别人的专家则需要3年。
有 些人永远不行,除非你是可教的“儒子”并且有个人驱动力。可教的最低要求是,当你错了的时候必须能够承认。驱动力的最低要求是,你必须愿意投入一些额外的 时间。记住,学习一些新的东西比改变你的典范(paradigm)(即改变你思考的方法,改变你对于什么是好的认识,改变你在技术世界中的思维模式)要容易的多。
你应该做两件事:
* 找一个“指导人”
* 看两类书:一类是有关C++中什么是合法的, 另一类是有关 C++中什么是该做的。
你不应该做两件事:
* 不应该去学习 C 作为学习 OO/C++ 的台阶
* 不应该去学习 Smalltalk 作为学习 OO/C++ 的台阶
## 6.8 从商业角度看 C++ 有哪些特征?
从[商业角度](#%5B6.17%5D)看 OO/C++ 有这样一些特征:
* C++ 有[巨大的安装基础](#%5B6.6%5D),这意味着你会有[很多厂商在工具,环境,咨询服务等上提供支持](#%5B6.5%5D),而且你可以在你的履历上加上非常有价值的一条。
* C++ 让开发者为软件块提供简化的接口,以改善这些软件块被使用(重用)时的错误率。
* C++ 通过算符重载让你利用开发者的直觉,降低重用用户的学习曲线。
* C++ 将对软件块的访问局部化,降低更改时的成本。
* C++ 减少安全性和可用性的权衡,改善使用(重用)软件块时的成本。
* C++ 减少安全性和速度的权衡,改善错误率而不丧失性能。
* C++ 给你继承和动态绑定,以便旧的代码调用新的代码,使得针对市场的快速扩展/调整你的软件成为可能。
## 6.9 虚函数(动态绑定)对于 OO/C++来说是主要的吗?
_是的!_
没有虚函数包含了许多模板以实现同样非常好的“泛型编程(译注:也称通用编程,"generic programming")”技术,但虚函数仍然是用C++进行面向对象编程的核心。
从商业角度)。 技术人员通常认为在C和非面向对象的C++之间有很大的区别,但如果没有面向对象,这个区别通常不足以证明培训开发者,新工具等的成本是值得的。换句话 说,如果我被某个经理征询意见,是否从C转向非面向对象的C++(也就是说,转换语言而不转换典范),那么我可能会劝阻他这样做,除非有逼不得已的面向工 具的原因。从商业角度看,面向对象能使系统具有可扩展性和可适应性,但只有C++类的语法而没有面向对象的话,就不会减少维护成本,而实际上会增加培训成 本。
底线:没有虚函数的C++不是面向对象。用类编程而没有动态绑定则称为“基于对象”,而不是“面向对象”。踢出虚函数和踢出OO(译 注:即面向对象)是一回事。所剩下的就是基于对象编程了,和最初的Ada语言类似(顺便说一下,新的Ada语言支持OO而不是基于对象编程了)。
注意:在[泛型编程](#%5B6.4%5D)中不需要虚函数。结合其它情况,这表明你无法通过简单地数虚函数的数量来判断所使用的编程范式
## 6.10 我来自密苏里州。你能给我一个理由,为什么虚函数(动态绑定)造成很大的不同?
总体来说:动态绑定能通过使旧的代码调用新的代码来提高重用。
在 OO(译注:即面向对象)之前,重用是通过使新的代码调用旧的代码来完成的。举例来说,程序员可以写一些代码来调用一些重用的代码,如 `printf()。`
在OO中,重用能够通过使旧的代码调用新的代码来完成。例如,程序员可以写一些代码被非常非常始祖的 框架所调用。而不需要修改始祖的代码。事实上,甚至不需要被重新编译。即使源代码已经遗失了25年,你只有目标文件,那个原始的目标文件将会调用新的扩展 的代码而不会遗失什么。
这是可扩展性,这是OO。
## 6.11 C++ 是否向下兼容 ANSI/ISO C?
差不多。
C++尽可能地兼容C,但不完全。在实践上,主要的区别是,C++需要原型,`f()`声明一个不带参数的函数(在 C 中,`f()`和`f(...)`是相同的)。
还有一些非常微小的差别,象在C++中`sizeof('x')`等于`sizeof(char)`,而在 C 中等于`sizeof(int)`。同样,C++在同一个结构的tag名和其他名称放在同一名字空间内,而在 C 中,需要显式的`struct`(举例来说,`typedef struct Fred Fred;`技巧当然也可以工作,但在C++中是多余的)。
## 6.12 C++ 标准化了吗?
是的。
C++标准被ISO(国际标准化组织)和一些国家标准组织,如ANSI(美国国家标准协会),BSI(英国标准协会),DIN(德国国家标准组织)所定稿和采用。ISO标准在1997年11月14日经投票一致被定稿和采用。
ANSI C++委员会被称为“X3J16”。ISO C++标准小组被称为“WG21”。ANSI/ISO C++标准的主要参与者几乎包含了每个人:有来自澳大利亚,加拿大,丹麦,法国,德国,爱尔兰,日本,荷兰,新西兰,瑞典,英国和美国的代表,连同大约一 百多个公司的代表和感兴趣的个人。主要参与者包括AT&T,爱立信,Digital,Borland,惠普,IBM, Mentor Graphics,微软,Silicon Graphics,Sun Microsystems和西门子。经过大约8年的工作,标准完成了。在1997年11月14日,代表们出席了在莫里森镇的投票,标准被一致认可。
## 6.13 何处能得到 ANSI/ISO C++ 标准的拷贝?
准备好花钱吧——该文档不是免费的。有很多种方法获得这份文档。下面列出了一些:
* 访问[ANSI](http://webstore.ansi.org/),搜索“14882”(或对于C标准来说,搜索“9899”)
* 访问[Tech-Street](http://www.techstreet.com/),搜索“14882”(或对于C标准来说,搜索“9899”)。
* 去任何一家书店,搜索“0470846747”或“The C++ Standard, Incorporating Technical Corrigendum No. 1.”例如,[这里](http://www.amazon.com/exec/obidos/tg/detail/-/0470846747/),[这里](http://www.amazon.com/exec/obidos/tg/detail/-/0470846747/),[这里](http://www.amazon.com/exec/obidos/tg/detail/-/0470846747/)
* 致电给NCITS(信息技术标准国家委员会National Committee for Information Technology Standards,这是原来叫做“X3”的组织的新名字,其发音类似“insights”)。联系人是Monica Vega,202-626-5739 或 202-626-5738。寻求FDC 14882文档。
这里有一些相关文档。虽然是免费的,不过不是标准本身。
* 社区草案#2是免费的,但不是正式的,也过时了,还可能有错误:[这里](ftp://ftp.maths.warwick.ac.uk/pub/c++/std/cd2/)和[这里](ftp://ftp.research.att.com/dist/c++std/WP/CD2/)。
* ISO委员会的新闻发布信息在[这里](http://www.research.att.com/%7Ebs/iso_release.html)。非程序员也能读懂该发布信息。
## 6.14我可以问哪些“面试问题”来判断面试者真的懂了?
这个问题主要是针对想做好面试C++应聘者的非技术性管理人员和人力资源人员。如果你是一名准备去应聘的C++程序员,并且正在翻看本FAQ希望能够提前知道会面试什么问题,并以此来避免_真正_去学习C++,那么你应该感到羞耻:还是花点时间来提高自己的技术吧,这样就不必靠“作弊”来生活了!
回到非技术性管理人员和人力资源人员上:很明显你有足够的自个来判断面试者是否适合你公司的文化。不过有很多假冒内行、装腔作势唬人的家伙,所以你 需要找一些有技术实力的人一起来判断面试者的技术能力是否满足要求。很多公司雇了看上去不错但实际很废柴的人,结果深受其害。这些人虽然知道怎么回答一些 困难的问题,但本质上是不合格的。辨别这些伪专家的唯一办法是找人和你一起,这人要能够提出考验水平的技术问题。单凭自己是不行的。即使我给你一摞“迷惑 人的问题”,还是不能辨别出那些不良分子。
你的技术伙伴可能没有(通常是没有)足够的资格来判断面试者的个性或软实力,所以在决策过程中,请不要放弃你做为最终决定者的权利。但同时也请不要认为你能够通过问一些C++问题,就能获得一些粗略的线索,知道应聘者是否_真的_明白他所说的东西。
已经说过了:_如果_你有足够技术能力来阅读这份FAQ,那么你能够在这里找到很多好的面试问题。这份FAQ包含_很多_好问题来区分良莠。这份FAQ主要探讨程序员应该做什么,而不只是编译器允许程序员做什么。有很多C++里可以做但不应该做的事情。这份FAQ帮助人们区分这两者。
## 6.15当FAQ说“这些是_邪恶_的”,是什么意思?
这表示_这些_是你在大部分时候要避免的,但_不是_在_所有_时候都要避免的。例如,最后当某些东西没有其替代方案邪恶时。你会采用这些”邪恶“的东西。好吧,这是开玩笑的。别太当真。
这个词的真正意图(我听到你说“啊哈,果然_有_隐情!”。你是对的,的确有)是让C++新手摆脱一些旧有的思想。例如,C程序员开 始用C++时常常会过多使用指针、数组和/或#define。本FAQ将这些东西归为“邪恶”,以便给予C++新手一个往正确方向上的有力(同时也是古怪 有趣的)推动。类似“指针很邪恶”这种搞笑说法是为了说服C++新手C++“并非除了傻傻的//注释在其它方面就很像C了”。
现在说点正经的。我并不是说宏或数组或指针是要谋杀或绑架。呃,可能指针会干这些事(开个玩笑!)。所以不要对“邪恶”这个词太过敏感:用这个词只是为了为了听上去有些夸张。所以不要试图寻找有关哪些是“邪恶”或“不邪恶”的精确技术性定义:压根就没有。
还有一件事要注意:被称作“邪恶”的东西(宏、数组、指针等)并非在_所有_情况下_总是_邪恶的。当它们“不是最坏”的选择时,[就用它们](#%5B6.16%5D)。
## 6.16有时会用到那些“邪恶”的东西么?
当然会!
一种尺寸不可能适用所有情况。停!现在,找个尖头的笔在你的眼镜内侧写上:“_软件开发_就是_做决策_。“思考”(think)不是一个4个字母的单词。在软件中很少有“从不”和“总是”之类实施起来不需要动脑子的规则,没有那些在所有情况下都适用的规则,没有那种放之四海皆准的规则。
所以最终你_将会_使用那些“邪恶”的技术。如果你觉得这个词不舒服,那么换成“很多时候不推荐”(不过可别辞职改行当作家:像那种[软蛋](http://www.dictionary.com/search?q=milquetoast)类型的术语只会让人睡着:-)。
译注:这里的“软蛋”术语指”很多时候不推荐“这种听上去不够”硬“的表达。
## 6.17是否知道这些东西的技术定义很重要:“好的OO”,“好的类设计”?
可能你不喜欢,但简短的回答是,“不”(注意这个回答是给实践者而不是理论家的)。
专业的软件设计者根据这些来做评估:业务需求(时间,金钱和风险)以及技术需求(例如是不是“好的OO”或“好的类设计”)。这要困难很多,因为除 了技术因素,还涉及到业务问题(期限,人员的技术能力,知道公司的发展方向以便决定如何灵活设计,是否愿意考虑将来可能的变化(指实际可能发生而不只是理 论上可能)等等。)。然而,这样作出的决策_更加_可能带来好的效益。
做为一名开发者,你对老板要负有一种信任上的责任,要只投资那种能够带来可观回报的方面。如果除了技术问题之外不再问业务问题,你作出的决策就可能带来不可预知的商业结果。
不管喜不喜欢,这意味着实际上你可能最好还是不要去定义诸如“好的类设计”和“好的OO”这类术语。实际上我相信这些精确的、纯技术的定义可能会非 常危险,可能会浪费公司钱财,最终甚至会把人们的工作也搭进去。听上去有些夸张,但这是有一个很好的理由的:如果这些术语以一种精确、纯技术的方式来定 义,那么开发者可能就会好心办坏事,而忽略业务上的考虑,因为他们想要达到这些纯技术定义的“良好”标准。
_任何_纯技术定义的“良好”,例如好的“OO”或“好的设计”或是任何其它不需考虑期限、业务目标(即投资方向)、预期的未来变化、企 业在未来的投资意愿方面的文化、做维护工作的团队的技术水平等事情的东西,都是危险的。因为这回诱使程序员相信他们做的决定是“正确”的,而实际却_可能_导致_灾难性_后果。或者也可能虽然没有带来糟糕的商业后果,但关键是:当你在做决定时忽略了业务,那么最终结果会是随机的,有点无法预期。这就不好了。
事实很简单,业务问题高于技术问题。任何有关“好”的定义,如果不承认这点,那这个定义就是糟糕的。
## 6.18当人们抱怨说“FAQ”这个词太误导人了,因为它强调问题而不是答案,因此我们需要换一个不同的缩写词,这时我应该怎么对他们说?
告诉他们成长起来。
有人希望能够把”FAQ“换一个词,比如要能够强调答案而不是问题。但单词或短语是根据其用法来定义的。很多人已经理解了“FAQ”这个词本身的含义了。最好把它当作是一个名字,而不是缩写词。做为一个单词来说,“FAQ”已经表示一份常见问题_和_答案的列表了。
这并不是鼓励用词时不加考虑。相反,关键是清晰的交流需要使用人们已经理解的词汇。争论我们是否应该为“FAQ”换个词很蠢,而且浪费时间。如果这个词还没有为大家所熟知的话,那就是另外一回事了。但当很多人都已经理解了再去更换,那就没有意义了。
举个(不太完美)的类比,大家已经广泛接受'\n'做为换行符了,可现在仍然有少数程序员和某种计算机打交道,这些计算机有实际“换行”的打字终端。没人会在乎这个的。这就是个换行符,别在为之烦恼了。同理,'\r'是回车符,即使你的机器没有这种东西。接受它吧。
另一个(不完美)的类比是RAII。感谢Andy Koenig等人的伟大工作,“RAII”在C++社区已经广为人知了。“RAII”代表了一种非常有价值的概念,并且你应该经常用它。_但是_,如果你把“RAII”做为一个首字母缩写词来分解,并且如果你仔细研究组成这个缩写词的各个单词,你会意识到这些词并不能完美代表其含义。但谁在乎呢?!?重要的是概念,“RAII”只不过是其背后概念的一个称呼。
> 细节:如果你把RAII分解成各个单词(Resource Acquisition Is Initialization获取资源即初始化),你可能会认为RAII是指在初始化时获取资源。然而,RAII的威力并非来自将_获取_和_初始化_绑在一起,而使在于将_回收资源_和_析构_联 系在一起。更精确的缩写可能是“RRID”(Resource Reclamation Is Destruction资源回收即析构),或者DIRR(Destruction Is Resource Reclamation析构即回收资源),但既然大家已经广泛理解了RAII,使用这个词就比抱怨术语更重要。RAII是一种思想的名称,其做为一个缩写 词的精确性就不那么重要了。
> 所以还是把“FAQ”当作一个名字,其含义已被广泛接受了。单词的意义是由其用法定义的。
对应原文最后更新2009年1月2日 翻译最后更新2009年3月28日
- C++ FAQ Lite
- [1] 复制许可
- [2] 在线站点分发本文档
- [3] C++-FAQ-Book 与 C++-FAQ-Lite
- [6] 综述
- [7] 类和对象
- [8] 引用
- [9] 内联函数
- [10] 构造函数
- [11] 析构函数
- [12] 赋值算符
- [13] 运算符重载
- [14] 友元
- [15] 通过 <iostream> 和 <cstdio>输入/输出
- [16] 自由存储(Freestore)管理
- [17] 异常和错误处理
- [18] const正确性
- [19] 继承 — 基础
- [20] 继承 — 虚函数
- [21] 继承 — 适当的继承和可置换性
- [22] 继承 — 抽象基类(ABCs)
- [23] 继承 — 你所不知道的
- [24] 继承 — 私有继承和保护继承
- [27] 编码规范
- [28] 学习OO/C++
- [31] 引用与值的语义
- [32] 如何混合C和C++编程
- [33] 成员函数指针
- [35] 模板
- [36] 序列化与反序列化
- [37] 类库