| 网站首页 | 业界新闻 | 小组 | 威客 | 人才 | 下载频道 | 博客 | 代码贴 | 在线编程 | 编程论坛
欢迎加入我们,一同切磋技术
用户名:   
 
密 码:  
共有 6316 人关注过本帖
标题:推荐:C++语言常见问题解答
只看楼主 加入收藏
yuyunliuhen
Rank: 6Rank: 6
等 级:贵宾
威 望:20
帖 子:1435
专家分:0
注 册:2005-12-12
收藏
得分:0 
学过「纯种」的 OOPL 之後才能学 C++ 吗? 
 
不是(事实上,这样可能反而会害了你)。 
 
(注意:Smalltalk 是个「纯种」的 OOPL,而 C++ 是个「混血」的 OOPL。)读这 
之前,请先读读前面关於 C++ 与 Smalltalk 差别的 FAQs。 
 
OOPL 的「纯粹性」,并不会让转移到 C++ 更容易些。事实上,典型的动态系结与非 
子型别的继承,会让 Smalltalk 程式者更难学会 C++。Paradigm Shift 公司曾教过 
数千人 OO 技术,我们注意到:有 Smalltalk 背景的人来学 C++,通常和那些根本 
没碰过继承的人学起来差不多累。事实上,对动态型别的 OOPL(通常是,但不全都 
是 Smalltalk)有高度使用经验的人,可能会“更难”学好,因为想把过去的习惯“ 
遗忘”,会比一开始就学习静态型别来得困难。 
 
【译注】作者是以「语言学习」的角度来看的。事实上,若先有 Smalltalk 之类的 
         物件导向观念的背景知识,再来学 C++ 就不必再转换 "paradigm"--物件 
         导向的中心思维是不会变的,变的只是实行细节而已。

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 
什麽是 NIHCL?到哪里拿到它? 
 
NIHCL 代表 "national-institute-of-health's-class-library",美国国家卫生局 
物件程式库。取得法:anonymous ftp 到 [128.231.128.7], 
档案:pub/nihcl-3.0.tar.Z 。 
 
NIHCL(有人念作 "N-I-H-C-L",有人念作 "nickel")是个由 Smalltalk 转移过来 
的 C++ 物件程式库。有些 NIHCL 用到的动态型别很棒(譬如:persistent objects 
,持续性物件),也有些地方动态型别会和 C++ 语言的静态型别相冲突,造成紧张 
关系。 
 
详见前面关於 Smalltalk 的 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:47
yuyunliuhen
Rank: 6Rank: 6
等 级:贵宾
威 望:20
帖 子:1435
专家分:0
注 册:2005-12-12
收藏
得分:0 
什麽是数值以及参考语意?哪一种在 C++ 里最好? 
 
在参考语意 (reference semantics) 中,「设定」是个「指标拷贝」的动作(也就 
是“参考”这个词的本意),数值语意 (value semantics,或 "copy" semantics) 
的设定则是真正地「拷贝其值」,而不是做指标拷贝的动作。C++ 让你选择:用设定 
运算子来拷贝其值(copy/value 语意),或是用指标拷贝方式来拷贝指标 
(reference 语意)。C++ 让你能覆盖掉 (override) 设定运算子,让它去做你想要 
的事,不过系统预设的(而且是最常见的)方式是拷贝其「数值」。 
 
参考语意的优点:弹性、动态系结(在 C++ 里,你只能以传指标或传参考来达到动 
态系结,而不是用传值的方式)。 
 
数值语意的优点:速度。对需要物件(而非指标)的场合来说,「速度」似乎是很奇 
怪的特点,但事实上,我们比较常存取物件本身,较不常去拷贝它。所以偶尔的拷贝 
所付出的代价,(通常)会被拥有「真正的物件本身」、而非仅是指向物件的指标所 
带来的效益弥补过去。 
 
有三个情况,你会得到真正的物件,而不是指向它的指标:区域变数、整体/静态变 
数、完全被某类别包含在内 (fully contained) 的成员物件。这里头最重要的就是 
最後一个(也就是「成份」)。 
 
後面的 FAQs 会有更多关於 copy-vs-reference 语意的资讯,请全部读完,以得到 
较平衡的观点。前几则会刻意偏向数值语意,所以若你只读前面的,你的观点就会有 
所偏颇。 
 
设定 (assignment) 还有别的事项(譬如:shallow vs deep copy)没在这儿提到。 

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:47
yuyunliuhen
Rank: 6Rank: 6
等 级:贵宾
威 望:20
帖 子:1435
专家分:0
注 册:2005-12-12
收藏
得分:0 
「虚拟资料」是什麽?怎麽样/为什麽该在 C++ 里使用它? 
 
虚拟资料让衍生类别能改变基底类别的物件成员所属的类别。严格说来,C++ 并不「 
支援」虚拟资料,但可以模拟出来。不漂亮,但还能用。 
 
欲模拟之,基底类别必须有个指标指向成员物件,衍生类别必须提供一个 "new" 到 
的物件,以让原基底类别的指标所指到。该基底类别也要有一个以上正常的建构子, 
以提供它们自己的参考(也是透过 "new"),且基底类别的解构子也要 "delete" 掉 
被参考者。 
 
举例来说,"Stack" 类别可能有个 Array 成员物件(采用指标),衍生类别 
"StretchableStack" 可能会把基底类别的成员资料 "Array" 覆盖成 
"StretchableArray"。想做到的话,StretchableArray 必须继承自 Array,这样子 
Stack 就会有个 "Array*"。Stack 的正常建构子会用 "new Array" 来初始化它的 
"Array*",但 Stack 也会有一个(可能是在 "protected:" 里)特别的建构子,以 
自衍生类别中接收一个 "Array*"; StretchableArray 的建构子会用 
"new StretchableArray" 把它传给那个特别的建构子。 
 
优点: 
  * 容易做出 StretchableStack(大部份的程式都继承下来了)。 
  * 使用者可把 StretchableStack 当成“是一种”Stack 来传递。 
 
缺点: 
  * 多增加额外的间接存取层,才能碰到 Array。 
  * 多增加额外的自由记忆体配置负担(new 与 delete)。 
  * 多增加额外的动态系结负担(原因请见下一则 FAQ)。 
 
换句话说,在“我们”这一边,很轻松就成功做出 StretchableStack,但所有用户 
却都为此付出代价。不幸的,额外负荷不仅在 StretchableStack 会有,连 Stack 
也会。 
 
请看下下一则 FAQ,看看使用者会「付出」多少代价。也请读读下一则 FAQ 以後的 
几则(不看其他的,你将得不到平衡的报导)。 

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:47
yuyunliuhen
Rank: 6Rank: 6
等 级:贵宾
威 望:20
帖 子:1435
专家分:0
注 册:2005-12-12
收藏
得分:0 
虚拟资料和动态资料有何差别? 
 
最容易分辨出来的方法,就是看看颇为类似的「虚拟函数」。虚拟成员函数是指:在 
所有子类别中,它的宣告(型态签名)部份必须保持不变,但是定义(本体)的部份 
可以被覆盖(override)。继承下来的成员函数可被覆盖,是子类别的静态性质 
(static property);它不随任何物件之生命期而动态地改变,同一个子类别的不同 
物件,也不可能会有不同的成员函数的定义。 
 
现在请回头重读前面这一段,但稍作些代换: 
  * 「成员函数」 --> 「成员物件」 
  * 「型态签名」 --> 「型别」 
  * 「本体」     --> 「真正所属的类别」 
这样子,你就看到虚拟资料的定义。 
 
从另一个角度来看,就是把「各个物件」的成员函数与「动态」成员函数区分开来。 
「各个物件」成员函数是指:在任何物件案例中,该成员函数可能会有所不同,可能 
会塞入函数指标来实作出来;这个指标可以是 "const",因为它在物件生命期中不会 
变更。「动态」成员函数是指:该成员函数会随时间动态地改变;也可能以函数指标 
来做,但该指标不会是 const 的。 
 
推而广之,我们得到三种不同的资料成员概念: 
  * 虚拟资料:成员物件的定义(真正所属的类别)可被子类别覆盖,只要它的宣告 
    (型别)维持不变,且此覆盖是子类别的静态性质。 
  * 各物件的资料:任何类别的物件在初始化时,可以案例化不同型式(型别)的成 
    员物件(通常是一个 "wrapper" 包起来的物件),且该成员物件真正所属的类别 
    ,是把它包起来的那个物件之静态性质。 
  * 动态资料:成员物件真正所属的类别,可随时间动态地改变。 
 
它们看起来都差不多,是因为 C++ 都不「直接支援」它们,只是「能做得出来」而 
已;在这种情形下,模拟它们的机制也都一样:指向(可能是抽象的)基底类别的指 
标。在直接提供这些 "first class" 抽象化机制的语言中,这三者间的差别十分明 
显,它们各有不同的语法。 

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:47
yuyunliuhen
Rank: 6Rank: 6
等 级:贵宾
威 望:20
帖 子:1435
专家分:0
注 册:2005-12-12
收藏
得分:0 
我该正常地用指标来配置资料成员,还是该用「成份」(composition)? 
 
成份。 
 
正常情况下,你的成员资料应该被「包含」在合成的物件里(但也不总是如此; 
"wrapper" 物件就是你会想用指标/参考的好例子;N-to-1-uses-a 的关系也需要某 
种指标/参考之类的东西)。 
 
有三个理由说明,完全被包含的成员物件(「成份」)的效率,比自由配置物件的指 
标还要好: 
 
  * 额外的间接层,每当你想存取成员物件时。 
  * 额外的动态配置("new" 於建构子中,"delete" 於解构子中)。 
  * 额外的动态系结(底下会解释)。 

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:47
yuyunliuhen
Rank: 6Rank: 6
等 级:贵宾
威 望:20
帖 子:1435
专家分:0
注 册:2005-12-12
收藏
得分:0 
动态配置成员物件有三个效率因素,它们的相对代价是多少? 
 
这三个效率因素,上一则 FAQ 有列举出来: 
  * 以它本身而言,额外的间接层影响不大。 
  * 动态配置可能是个效率问题(当有许多配置动作时,典型的 malloc 会拖慢速度 
    ;OO 软体会被动态配置拖垮,除非你事先就留意到它了)。 
  * 用指标而非物件的话,会带来额外的动态系结。每当 C++ 编译器能知道某物件「 
    真正的」类别,该虚拟函数呼叫就能“静态”地系结住,能够被 inline。Inline 
    可能有无限大的 (但你可能只会相信有半打的 :-) 最佳化机会,像是 procedural 
    integration、暂存器生命期等等事项。三种情形之下,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:48
yuyunliuhen
Rank: 6Rank: 6
等 级:贵宾
威 望:20
帖 子:1435
专家分:0
注 册:2005-12-12
收藏
得分:0 
"inline virtual" 的成员函数真的会被 "inline" 吗? 
 
Yes,可是... 
 
一个透过指标或参考的 virtual 呼叫总是动态决定的,可能永远都不会被 inline。 
原因:编译器直到执行时(亦即:动态地),才会知道该呼叫哪个程式,因为那一段 
程式,可能会来自呼叫者编译过後才出现的衍生类别。 
 
因此,inline virtual 的呼叫可被 inline 的唯一时机是:编译器有办法知道某物 
件「真正所属的类别」之时,这是虚拟函数呼叫里所要知道的事情。这只会发生在: 
编译器拥有真正的物件,而非该物件的指标或参考。也就是说:不是区域变数、整体 
/静态物件,就是合成物件里的完全包含物件。 
 
注意:inline 和非 inline 的差距,通常会比正常的和虚拟的函数呼叫之差别更为 
显著。譬如,正常的与虚拟的函数呼叫,通常只差两个记忆体参考的动作而已,可是 
inline 与非 inline 函数就会有一个数量级的差距(与数万次影响不大的成员函数 
呼叫相比,函数没有用 inline virtual 的话,会造成 25X 的效率损失! 
[Doug Lea, "Customization in C++," proc Usenix C++ 1990]). 
 
针对此现象的对策:不要陷入编译器/语言厂商之间,对彼此产品的虚拟函数呼叫, 
做永无止尽的性能比较争论(或是广告噱头!)之中。和语言/编译器能否将成员函 
数呼叫做「行内展开」相比,这种比较完全没有意义。也就是说,许多语言编译器厂 
商,拼命强调他们的函数分派方式有多好,但如果他们没做“行内”成员函数呼叫的 
话,整体性能还是会很差,因为 inline--而非分派--才是最重要的性能影响因 
素。 
 
注意:请读读下两则 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:48
yuyunliuhen
Rank: 6Rank: 6
等 级:贵宾
威 望:20
帖 子:1435
专家分:0
注 册:2005-12-12
收藏
得分:0 
看起来我不应该用参考语意了,是吗? 
 
错。 
 
参考语意是个好东西。我们不能抛弃指标,我们只要不让软体的指标变成一个大老鼠 
窝就行了。在 C++ 里,你可以选择该用参考语意(指标/参考)还是数值语意(物 
件真正包含其他物件)的时机。在大型系统中,两者应该取得平衡。然而如果你全都 
用指标来做的话,速度会大大的降低。 
 
接近问题层次的物件,会比较高阶的物件还要大。这些针对「问题空间」抽象化的个 
体本身,通常比它们内部的「数值」更为重要。参考语意应该用於问题空间的物件上 
。 
 
注意:问题空间的物件,通常会比解题空间的更为高阶抽象化,所以相对地问题空间 
的物件通常会有较少的交谈性。因此 C++ 给我们一个“理想的”解决法:我们用参 
考语意,来对付那些需要独立的个体识别 (identity) 者,或是大到不适合直接拷贝 
的物件;其他情形则可选择数值语意。因此,使用频率较高的就用数值语意,因为( 
只有)在不造成伤害的场合下,我们才去增加弹性;必要时,我们还是选择效率! 
 
还有其他关於实际 OO 设计方面的问题。想精通 OO/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:48
yuyunliuhen
Rank: 6Rank: 6
等 级:贵宾
威 望:20
帖 子:1435
专家分:0
注 册:2005-12-12
收藏
得分:0 
参考语意效率不高,那麽我是否应该用传值呼叫? 
 
不。 
 
前面的 FAQ 是讨论“成员物件”(member object) 的,而不是函数参数。一般说来 
,位於继承阶层里的物件,应该用参考或指标来传递,而非传值,因为惟有如此你才 
能得到(你想要的)动态系结(传值呼叫和继承不能安全混用,因为如果把大大的子 
类别物件当成基底的物件来传值的话,它会被“切掉”)。 
 
除非有足以令人信服的反方理由,否则成员物件应该用数值,而参数该用参考传递。 
前几则 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:48
快速回复:推荐:C++语言常见问题解答
数据加载中...
 
   



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

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