📄 00000002.htm
字号:
<HTML><HEAD> <TITLE>BBS水木清华站∶精华区</TITLE></HEAD><BODY><CENTER><H1>BBS水木清华站∶精华区</H1></CENTER> <BR>== Part 3/4 ============================ <BR> <BR>comp.lang.c++ Frequently Asked Questions list (with answers, fortunately). <BR>Copyright (C) 1991-96 Marshall P. Cline, Ph.D. <BR>Posting 3 of 4. <BR>Posting #1 explains copying permissions, (no)warranty, table-of-contents, etc <BR> <BR>============================= <BR>■□ 第14节:程式风格指导 <BR>============================= <BR> <BR>Q81:有任何好的 C++ 程式写作的标准吗? <BR> <BR>感谢您阅读这份文件,而不是再发明自己的一套。 <BR> <BR>但是请不要在 comp.lang.c++ 里问这问题。几乎所有软体工程师,或多或少都把这 <BR>种东西看成是「大玩具」。而且,一些想成为 C++ 程式撰写标准的东西,是由那些 <BR>不熟悉这语言及方法论的人弄出来的,所以最後它只能成为「过去式」的标准。这种 <BR>「摆错位置」的现象,让大家对程式写作标准产生不信任感。 <BR> <BR>很明显的,在 comp.lang.c++ 问这问题的人,是想使自己更精进,不会因自己的无 <BR>知而绊倒,然而一些回答却只是让情况更糟而已。 <BR> <BR>======================================== <BR> <BR>Q82:程式撰写标准是必要的吗?有它就够了吗? <BR> <BR>程式撰写标准不会让不懂 OO 的人变懂;只有训练及经验才有可能。如果它有用处的 <BR>话,那就是抑制住那些琐碎无关紧要的程式片段--当大机构想把零散的程式设计组 <BR>织整合起来时,这些片段常常会出现。 <BR> <BR>但事实上你要的不光是这种标准而已。它们提供的架构让新手少去担心一些自由度, <BR>但是系统化的方法论会比这些好看的标准做得更好。组织机构需要的是一致性的设计 <BR>与实行“哲学”,譬如:强型别或弱型别?用指标还是参考介面? stream I/O 还是 <BR>stdio? C++ 程式该不该呼叫 C 的?反过来呢? ABC 该怎麽用?继承该用为实作的 <BR>技巧还是特异化的技巧?该用哪一种测试策略?一一去检查吗?该不该为每个资料成 <BR>员都提供一致的 "get" 和 "set" 介面?介面该由外往内还是由内往外设计?错误状 <BR>况该用 try/catch/throw 还是传回值来处理?……等等。 <BR> <BR>我们需要的是详细的“设计”部份的「半标准」。我推荐一个三段式标准:训练、谘 <BR>询顾问以及程式库。训练乃提供「密集教学」,谘询顾问让 OO 观念深刻化,而非仅 <BR>仅是被教过而已,高品质的程式库则是提供「长程的教学」。上述三种培训都有很热 <BR>门的市场景况。(【译注】无疑的,这是指美、加地区。)接受过上述培训的组织都 <BR>有如此的忠告:「买现成的吧,不要自己硬干 (Buy, Don't Build.)。」买程式库, <BR>买训练课程,买开发工具,买谘询顾问。想靠自学来达到成功的工具厂商及应用/系 <BR>统厂商,都会发现成功很困难。 <BR> <BR>【译注】这一段十分具有参考价值。不过有些背景资料得提供给各位参考。别忘了: <BR> 作者是美国人,是以该地为背景,且留意一下他所服务的公司是做什麽的.. <BR> ... :-) 唉!国内有这麽多的专业顾问公司吗? :-< <BR> <BR>少数人会说:程式撰写标准只是「理想」而已,但在上述的组织机构中,它仍有其必 <BR>要性。 <BR> <BR>底下的 FAQs 提供一些基本的指导惯例及风格。 <BR> <BR>======================================== <BR> <BR>Q83:我们的组织该以以往 C 的经验来决定程式撰写标准吗? <BR> <BR>No! <BR> <BR>不论你的 C 经验有多丰富,不论你有多高深的 C 能力,好的 C 程式员并不会让你 <BR>直接就成为好的 C++ 程式员。从 C 移到 C++ 并不仅是学习 "++" 的语法语意而已 <BR>,一个组织想达到 OOP 的境界,却未将 "OO" 的精神放进 OOP 里的话,只是自欺罢 <BR>了;会计的资产负债表会把他们的愚蠢显现出来。 <BR> <BR>C++ 程式撰写标准应该由 C++ 专家来调整,不妨先在 comp.lang.c++ 里头问问题( <BR>但是不要用 "coding standard" 这种字眼;只要这样子问:「这种技巧有何优缺点 <BR>?」)。找个能帮你避开陷阱的高手,上个训练课程,买程式库,看看「好的」程式 <BR>库是否合乎你的程式撰写标准。绝对不要光靠自己来制定标准,除非你对它已有某种 <BR>程度的掌握。没有标准总比有烂标准好,因为不恰当的「官方说法」会让不够聪明的 <BR>平民难以追随。现在 C++ 训练课程及程式库,已有十分兴盛的市场。 <BR> <BR>再提一件事:当某个东西炙手可热时,招摇撞骗者亦随之而生;务必三思而後行。也 <BR>要问一下从某处修过课的人,因为老手不见得也是个好教员。最後,选个懂得指导别 <BR>人的从业人员,而不是个对此语言/方法论只有过时知识的全职教师。 <BR> <BR>【译注】善哉斯言! <BR> <BR>======================================== <BR> <BR>Q84:我该在函数中间或是开头来宣告区域变数? <BR> <BR>在第一次用到它的地方附近。 <BR> <BR>物件在宣告的时候就会被初始化(被建构)。如果在初始化物件的地方没有足够的资 <BR>讯,直到函数中间才有的话,你可以在开头处初始个「空值」给它,等以後再「设定 <BR>」其值;你也可以在函数中间再初始个正确的东西给它。以执行效率来说,一开始就 <BR>让它有正确的值,会比先建立它,搞一搞它,之後再重建它来得好。以像 "String" <BR>这种简单的例子来看,会有 350% 的速度差距。在你的系统上可能会不同;当然整个 <BR>系统可能不会降低到 300+%,但是“一定”会有不必要的性能衰退现象。 <BR> <BR>常见的反驳是:「我们会替物件的每个资料提供 "set" 运作行为,则建构时的额外 <BR>耗费就会分散开来。」这比效能负荷更糟,因为你添加了维护的梦靥。替每个资料提 <BR>供 "set" 运作行为就等於对资料不设防:你把内部实作技巧都显露出来了。你隐藏 <BR>到的只有成员物件的实体“名字”而已,但你用到的 List、String 和 float(举例 <BR>来说)型态都曝光了。通常维护会比 CPU 执行时间耗费的资源更多。 <BR> <BR>区域变数应该在靠近它第一次用到之处宣告。很抱歉,这和 C 老手的习惯不同,但 <BR>是「新的」不见得就是「不好的」。 <BR> <BR>======================================== <BR> <BR>Q85:哪一种原始档命名惯例最好? "foo.C"? "foo.cc"? "foo.cpp"? <BR> <BR>如果你已有个惯例,就用它吧。如果没有,看看你的编译器,看它用的是哪一种。典 <BR>型的答案是:".C", ".cc", ".cpp", 或 ".cxx"(很自然的,".C" 副档名是假设该 <BR>档案系统会区分出 ".C" ".c" 大小写)。 <BR> <BR>在 Paradigm Shift 公司,我们在 Makefiles 里用 ".C",即使是在不区分大小写的 <BR>档案系统下(在有区分的系统中,我们用一个编译器选项:「假设 .c 档案都是 C++ <BR>的程式」;譬如:IBM CSet++ 用 "-Tdp",Zortech C++ 用 "-cpp",Borland C++用 <BR>"-P",等等)。 <BR> <BR>======================================== <BR> <BR>Q86:哪一种标头档命名惯例最好? "foo.H"? "foo.hh"? "foo.hpp"? <BR> <BR>如果你已有个惯例,就用它吧。如果没有,而且你的编辑器不必去区分 C 和 C++ 档 <BR>案的话,只要用 ".h" 就行了,否则就用编辑器所要的,像 ".H"、".hh" 或是 <BR>".hpp"。 <BR> <BR>在 Paradigm Shift 公司,我们用 ".h" 做为 C 和 C++ 的原始档案(然後,我们就 <BR>不再建那些纯粹的 C 标头档案)。 <BR> <BR>======================================== <BR> <BR>Q87:C++ 有没有像 lint 那样的指导原则? <BR> <BR>Yes,有一些常见的例子是危险的。 <BR>但是它们都不尽然是「坏的」,因为有些情况下,再差的例子也得用上去。 <BR> * "Fred" 类别的设定运算子应该传回 "*this",当成是 "Fred&"(以允许成串的设 <BR> 定指令)。 <BR> * 有任何虚拟函数的类别,都该有个虚拟解构子。 <BR> * 若一个类别有 {解构子,设定运算子,拷贝建构子} 其一的话,通常三者也都全 <BR> 部需要。 <BR> * "Fred" 类别的拷贝建构子和设定运算子,都该将它们的参数加上 "const":分别 <BR> 是 "Fred::Fred(const Fred&)" 和 "Fred& Fred::operator=(const Fred&)" 。 <BR> * 类别的子物件一定要用初始化串列 (initialization lists) 而不要用设定的方 <BR> 式,因为对使用者自订类别而言,会有很大的效率差距(3x!)。 <BR> * 许多设定运算子都应该先测试:「我们」是不是「他们」;譬如: <BR> Fred& Fred::operator= (const Fred& fred) <BR> { <BR> if (this == &fred) return *this; <BR> //...normal assignment duties... <BR> return *this; <BR> } <BR> 有时候没必要测试,但一般说来,这些情况都是:没有必要由使用者提供外显的 <BR> 设定运算子的时候(相对於编译器提供的设定运算子)。 <BR> * 在那些同时定义了 "+="、"+" 及 "=" 的类别中,"a+=b" 和 "a=a+b" 通常应该 <BR> 做同样的事;其他类似的内建运算子亦同(譬如:a+=1 和 ++a; p[i] 和 *(p+i); <BR> 等等)。这可使用二元运算子 "op=" 之型式来强制做到;譬如: <BR> Fred operator+ (const Fred& a, const Fred& b) <BR> { <BR> Fred ans = a; <BR> ans += b; <BR> return ans; <BR> } <BR> 这样一来,有「建构性」的二元运算甚至可以不是夥伴。但常用的运算子有时可 <BR> 能会更有效率地实作出来(譬如,如果 "Fred" 类别本来就是个 "String",且 <BR> "+=" 必须重新配置/拷贝字串记忆体的话,一开始就知道它的最後长度,可能会 <BR> 比较好)。 <BR> <BR> <BR>============================================== <BR>■□ 第15节:Smalltalk 程式者学习 C++ 之钥 <BR>============================================== <BR> <BR>Q88:为什麽 C++ 的 FAQ 有一节讨论 Smalltalk?这是用来攻击 Smalltalk 的吗? <BR> <BR>世界上「主要的」两个 OOPLs 是 C++ 与 Smalltalk。由於这个流行的 OOPL 已有第 <BR>二大的使用者总数量,许多新的 C++ 程式者是由 Smalltalk 背景跳过来的。这一节 <BR>会回答以下问题: <BR> * 这两个语言的差别? <BR> * 从 Smalltalk 跳到 C++ 的程式者,要知道些什麽,才能精通 C++? <BR> <BR>这一节 *!*不会*!* 回答这些问题: <BR> * 哪一种语言「最好」? <BR> * 为什麽 Smalltalk「很烂」? <BR> * 为什麽 C++「很烂」? <BR>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -