| 网站首页 | 业界新闻 | 小组 | 威客 | 人才 | 下载频道 | 博客 | 代码贴 | 在线编程 | 编程论坛
欢迎加入我们,一同切磋技术
用户名:   
 
密 码:  
共有 6325 人关注过本帖
标题:推荐:C++语言常见问题解答
只看楼主 加入收藏
yuyunliuhen
Rank: 6Rank: 6
等 级:贵宾
威 望:20
帖 子:1435
专家分:0
注 册:2005-12-12
收藏
得分:0 
哪一种原始档命名惯例最好? "foo.C"? "foo.cc"? "foo.cpp"? 
 
如果你已有个惯例,就用它吧。如果没有,看看你的编译器,看它用的是哪一种。典 
型的答案是:".C", ".cc", ".cpp", 或 ".cxx"(很自然的,".C" 副档名是假设该 
档案系统会区分出 ".C" ".c" 大小写)。 
 
在 Paradigm Shift 公司,我们在 Makefiles 里用 ".C",即使是在不区分大小写的 
档案系统下(在有区分的系统中,我们用一个编译器选项:「假设 .c 档案都是 C++ 
的程式」;譬如:IBM CSet++ 用 "-Tdp",Zortech C++ 用 "-cpp",Borland C++用 
"-P",等等)。 
 

Go confidently in the  directions of your dreams,live the life you have imagined!Just do it!
It is no use learning without thinking!
2006-12-23 22:44
yuyunliuhen
Rank: 6Rank: 6
等 级:贵宾
威 望:20
帖 子:1435
专家分:0
注 册:2005-12-12
收藏
得分:0 
哪一种标头档命名惯例最好? "foo.H"? "foo.hh"? "foo.hpp"? 
 
如果你已有个惯例,就用它吧。如果没有,而且你的编辑器不必去区分 C 和 C++ 档 
案的话,只要用 ".h" 就行了,否则就用编辑器所要的,像 ".H"、".hh" 或是 
".hpp"。 
 
在 Paradigm Shift 公司,我们用 ".h" 做为 C 和 C++ 的原始档案(然後,我们就 
不再建那些纯粹的 C 标头档案)。 
 

Go confidently in the  directions of your dreams,live the life you have imagined!Just do it!
It is no use learning without thinking!
2006-12-23 22:44
yuyunliuhen
Rank: 6Rank: 6
等 级:贵宾
威 望:20
帖 子:1435
专家分:0
注 册:2005-12-12
收藏
得分:0 
C++ 有没有像 lint 那样的指导原则? 
 
Yes,有一些常见的例子是危险的。 
但是它们都不尽然是「坏的」,因为有些情况下,再差的例子也得用上去。 
  * "Fred" 类别的设定运算子应该传回 "*this",当成是 "Fred&"(以允许成串的设 
    定指令)。 
  * 有任何虚拟函数的类别,都该有个虚拟解构子。 
  * 若一个类别有 {解构子,设定运算子,拷贝建构子} 其一的话,通常三者也都全 
    部需要。 
  * "Fred" 类别的拷贝建构子和设定运算子,都该将它们的参数加上 "const":分别 
    是 "Fred::Fred(const Fred&)" 和 "Fred& Fred::operator=(const Fred&)" 。 
  * 类别的子物件一定要用初始化串列 (initialization lists) 而不要用设定的方 
    式,因为对使用者自订类别而言,会有很大的效率差距(3x!)。 
  * 许多设定运算子都应该先测试:「我们」是不是「他们」;譬如: 
         Fred& Fred::operator= (const Fred& fred) 
         { 
           if (this == &fred) return *this; 
           //...normal assignment duties... 
           return *this; 
         } 
    有时候没必要测试,但一般说来,这些情况都是:没有必要由使用者提供外显的 
    设定运算子的时候(相对於编译器提供的设定运算子)。 
  * 在那些同时定义了 "+="、"+" 及 "=" 的类别中,"a+=b" 和 "a=a+b" 通常应该 
    做同样的事;其他类似的内建运算子亦同(譬如:a+=1 和 ++a; p[i] 和 *(p+i); 
    等等)。这可使用二元运算子 "op=" 之型式来强制做到;譬如: 
         Fred operator+ (const Fred& a, const Fred& b) 
         { 
           Fred ans = a; 
           ans += b; 
           return ans; 
         } 
    这样一来,有「建构性」的二元运算甚至可以不是夥伴。但常用的运算子有时可 
    能会更有效率地实作出来(譬如,如果 "Fred" 类别本来就是个 "String",且 
    "+=" 必须重新配置/拷贝字串记忆体的话,一开始就知道它的最後长度,可能会 
    比较好)。 
 
 

Go confidently in the  directions of your dreams,live the life you have imagined!Just do it!
It is no use learning without thinking!
2006-12-23 22:44
yuyunliuhen
Rank: 6Rank: 6
等 级:贵宾
威 望:20
帖 子:1435
专家分:0
注 册:2005-12-12
收藏
得分:0 
为什麽 C++ 的 FAQ 有一节讨论 Smalltalk?这是用来攻击 Smalltalk 的吗? 
 
世界上「主要的」两个 OOPLs 是 C++ 与 Smalltalk。由於这个流行的 OOPL 已有第 
二大的使用者总数量,许多新的 C++ 程式者是由 Smalltalk 背景跳过来的。这一节 
会回答以下问题: 
  * 这两个语言的差别? 
  * 从 Smalltalk 跳到 C++ 的程式者,要知道些什麽,才能精通 C++? 
 
这一节 *!*不会*!* 回答这些问题: 
  * 哪一种语言「最好」? 
  * 为什麽 Smalltalk「很烂」? 
  * 为什麽 C++「很烂」? 
 
这可不是对 Smalltalk 恐怖份子挑□,让他们趁我熟睡时戳我的轮胎(在我很难得 
有空休息的这段时间内 :-) 。 
 

Go confidently in the  directions of your dreams,live the life you have imagined!Just do it!
It is no use learning without thinking!
2006-12-23 22:45
yuyunliuhen
Rank: 6Rank: 6
等 级:贵宾
威 望:20
帖 子:1435
专家分:0
注 册:2005-12-12
收藏
得分:0 
C++ 和 Smalltalk 的差别在哪? 
 
最重要的不同是: 
 
  * 静态型别或动态型别? 
  * 继承只能用於产生子型别上? 
  * 数值语意还是参考语意 (value vs reference semantics)? 
 
头两个差异会在这一节中解释,第三点则是下一节的讨论主题。 
 
如果你是 Smalltalk 程式者,现在想学 C++,底下三则 FAQs 最好仔细研读。 

Go confidently in the  directions of your dreams,live the life you have imagined!Just do it!
It is no use learning without thinking!
2006-12-23 22:45
yuyunliuhen
Rank: 6Rank: 6
等 级:贵宾
威 望:20
帖 子:1435
专家分:0
注 册:2005-12-12
收藏
得分:0 
什麽是「静态型别」?它和 Smalltalk 有多相似/不像? 
 
静态型别(static typing)是说:编译器会“静态地”(於编译时期)检验各运算 
的型态安全性,而不是产生执行时才会去检查的程式码。例如,在静态型别之下,会 
去侦测比对函数引数的型态签名,不正确的配对会被编译器挑出错误来,而非在执行 
时才被挑出。 
 
OO 的程式里,最常见的「型态不符」错误是:欲对某物件启动个成员函数,但该物 
件并未准备好要处理该运算动作。譬如,如果 "Fred" 类别有成员函数 "f()" 但没 
有 "g()",且 "fred" 是 "Fred" 类别的案例,那麽 "fred.f()" 就是合法的, 
"fred.g()" 则是非法的。C++(静态地)在编译期捕捉型别错误,Smalltalk 则(动 
态地)在执行期捕捉。(技术上,C++ 很像 Pascal--“半”静态型别--因为指 
标转型与 union 都能用来破坏型别系统;这提醒了我们:你用指标转型与 union 的 
频率,只能像你用 "goto" 那样。) 
 

Go confidently in the  directions of your dreams,live the life you have imagined!Just do it!
It is no use learning without thinking!
2006-12-23 22:45
yuyunliuhen
Rank: 6Rank: 6
等 级:贵宾
威 望:20
帖 子:1435
专家分:0
注 册:2005-12-12
收藏
得分:0 
「静态型别」与「动态型别」哪一种比较适合 C++? 
 
若你想最有效率使用 C++,请把她当成静态型别语言来用。 
 
C++ 极富弹性,你可以(藉由指标转型、union 或 #define)让她「长得」像 
Smalltalk。但是不要这样做。这提醒了我们:少用 #define。 
 
有些场合,指标转型和 union 是必要的,甚至是很好的做法,但须谨慎为之。指标 
转型等於是叫编译器完全信赖你。错误的指标转型可能会毁坏堆积、在别的物件记忆 
体中乱搞、呼叫不存在的运作行为、造成一般性错误(general failure)。这是很 
糟糕的事。如果你避免用与这些相关的东西,你的 C++ 程式会更安全、更快,因为 
能在编译期就检测的东西,就不必留到执行期再做。 
 
就算你喜欢动态型别,也请避免在 C++ 里使用,或者请考虑换另一个将型态检查延 
迟到执行期才做的语言。C++ 将型态检验 100% 都放在编译时期;她没有任何执行期 
型态检验的内建机制。如果你把 C++ 当成一个动态型别的 OOPL 来用,你的命运将 
操之汝手。 

Go confidently in the  directions of your dreams,live the life you have imagined!Just do it!
It is no use learning without thinking!
2006-12-23 22:46
yuyunliuhen
Rank: 6Rank: 6
等 级:贵宾
威 望:20
帖 子:1435
专家分:0
注 册:2005-12-12
收藏
得分:0 
怎样分辨某个 C++ 物件程式库是否属於动态型别的? 
 
提示 #1:当所有东西都衍生自单一的根类别(root class),通常叫做 "Object"。 
提示 #2:当容器类别 container classes,像 List、Stack、Set 等,都不是 
          template 版的。 
提示 #3:当容器类别(List、Stack、Set 等)把插入/取出的元素,都视为指向 
          "Object" 的指标时。(你可以把 Apple 放进容器中,但当你取出时,编 
          译器只知道它是衍生自 Object,所以你得用指标转型将它转回 Apple* ; 
          你最好祈祷它真的是个 Apple,否则你会脑充血的。) 
 
你可用 "dynamic_cast"(於 1994 年才加入的)来使指标转型「安全些」,但这种 
动态测试依旧是“动态”的。这种程式风格是 C++ 动态型别的基本要素,你可以呼 
叫函数:「把这个 Object 转换成 Apple,或是给我个 NULL,如果它不是 Apple的 
话」,你就得到动态型别了:直到执行时期才知道会发生什麽事。 
 
若你用 template 去实作出容器类别,C++ 编译器会静态侦测出 99% 的型态资讯( 
"99%" 并不是真的;有些人宣称能做到 100%,而那些需要持续性 (persistence) 的 
人,只能得到低於 100% 的静态型别检验)。重点是:C++ 透过 template 来做到泛 
型(genericity),而非透过继承。 

Go confidently in the  directions of your dreams,live the life you have imagined!Just do it!
It is no use learning without thinking!
2006-12-23 22:46
yuyunliuhen
Rank: 6Rank: 6
等 级:贵宾
威 望:20
帖 子:1435
专家分:0
注 册:2005-12-12
收藏
得分:0 
在 C++ 里怎样用继承?它和 Smalltalk 有何不同? 
 
有些人认为继承是用来重用程式码的。在 C++ 中,这是不对的。说明白点,「继承 
不是『为』重用程式码而设计的。」 
 
【译注】这一个分野相当重要。否则,C++ 使用者就会感染「继承发烧症」 
         (inheritance fever)。 
 
C++ 继承的目的是用来表现介面一致性(产生子类别),而不是重用程式码。C++ 中 
,重用程式码通常是靠「成份」(composition) 而非继承。换句话说,继承主要是用 
来当作「特异化」(specialization) 的技术,而非实作上的技巧。 
 
这是与 Smalltalk 主要的不同之处,在 Smalltalk 里只有一种继承的型式(C++ 有 
"private" 继承--「共享程式码,但不承袭其介面」,有 "public" 继承--表现 
"kind-of" 关系)。Smalltalk 语言非常(相对於只是程式的习惯)允许你置放一个 
override 覆盖(它会去呼叫个「我看不懂」的运作行为),以达到「隐藏住」继承 
下来的运作行为的“效果”。更进一步,Smalltalk 可让观念界的 "is-a" 关系“独 
立於”子类别阶层之外(子型别不必也是子类别;譬如,你可以让某个东西是一个 
Stack,却不必继承自 Stack 类别)。 
 
相反的,C++ 对继承的限制更严:没办法不用到继承就做出“观念上的 is-a”关系 
(有个 C++ 的解决方法:透过 ABC 来分离介面与实作)。C++ 编译器利用公共继承 
额外附的语意资讯,以提供静态型别。 

Go confidently in the  directions of your dreams,live the life you have imagined!Just do it!
It is no use learning without thinking!
2006-12-23 22:46
yuyunliuhen
Rank: 6Rank: 6
等 级:贵宾
威 望:20
帖 子:1435
专家分:0
注 册:2005-12-12
收藏
得分:0 
Smalltalk/C++ 不同的继承,在现实里导致的结果是什麽? 
 
Smalltalk 让你做出不是子类别的子型别,做出不是子型别的子类别,它可让 
Smalltalk 程式者不必操心该把哪种资料(位元、表现型式、资料结构)放进类别里 
面(譬如,你可能会把连结串列放到堆叠类别里)。毕竟,如果有人想要个以阵列做 
出的堆叠,他不必真的从堆叠继承过来;喜欢的话,他可以从阵列类别 Array 中继 
承过来,即使 ArrayBasedStack 并“不是”一种阵列!) 
 
在 C++ 中,你不可能不为此操心。只有机制(运作行为的程式码),而非表现法( 
资料位元)可在子类别中被覆盖掉,所以,通常你“不要”把资料结构放进类别里比 
较好。这会促成 Abstract Base Classes (ABCs) 的强烈使用需求。 
 
我喜欢用 ATV 和 Maseratti 之间的差别来比喻。ATV(all terrain vehicle,越野 
车)很好玩,因为你可以「到处逛」,任意开到田野、小溪、人行道等地。另一方面 
,Maseratti 让你能高速行驶,但你只能在公路上面开。就算你喜欢「自由表现力」 
,偏偏喜欢驶向丛林,但也请不要在 C++ 里这麽做;它不适合。 
 

Go confidently in the  directions of your dreams,live the life you have imagined!Just do it!
It is no use learning without thinking!
2006-12-23 22:46
快速回复:推荐:C++语言常见问题解答
数据加载中...
 
   



关于我们 | 广告合作 | 编程中国 | 清除Cookies | TOP | 手机版

编程中国 版权所有,并保留所有权利。
Powered by Discuz, Processed in 0.023394 second(s), 7 queries.
Copyright©2004-2024, BCCN.NET, All Rights Reserved