| 网站首页 | 业界新闻 | 小组 | 威客 | 人才 | 下载频道 | 博客 | 代码贴 | 在线编程 | 编程论坛
欢迎加入我们,一同切磋技术
用户名:   
 
密 码:  
共有 6325 人关注过本帖
标题:推荐:C++语言常见问题解答
只看楼主 加入收藏
yuyunliuhen
Rank: 6Rank: 6
等 级:贵宾
威 望:20
帖 子:1435
专家分:0
注 册:2005-12-12
收藏
得分:0 
分离介面与实作是做什麽用的? 
 
介面是企业体最有价值的资源。设计介面会比只把一堆独立的类别拼凑起来来得耗时 
,尤其是:介面需要花费更高阶人力的时间。 
 
既然介面是如此重要,它就应该保护起来,以避免被资料结构等等实作细节之变更所 
影响。因此你应该将介面与实作分离开来。 
 
======================================== 
 
Q75:在 C++ 里,我该怎样分离介面与实作(像 Modula-2 那样)? 
 
用 ABC(见下一则 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:41
yuyunliuhen
Rank: 6Rank: 6
等 级:贵宾
威 望:20
帖 子:1435
专家分:0
注 册:2005-12-12
收藏
得分:0 
ABC ("abstract base class") 是什麽? 
 
在设计层面,ABC 对应到抽象的概念。如果你问机械师父说他修不修运输工具,他可 
能会猜你心中想的到底是“哪一种”运输工具,他可能不会修理太空梭、轮船、脚踏 
车、核子潜艇。问题在於:「运输工具」是个抽象的概念(譬如:你建不出一辆「运 
输工具」,除非你知道要建的是“哪一种”)。在 C++,运输工具类别可当成是一个 
ABC,而脚踏车、太空梭……等等都当做它的子类别(轮船“是一种”运输工具)。 
在真实世界的 OOP 中,ABC 观念到处都是。 
 
在程式语言层面,ABC 是有一个以上纯虚拟成员函数(pure virtual)的类别(详见 
下一则 FAQ),你无法替一个 ABC 建造出物件(案例)来。

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:41
yuyunliuhen
Rank: 6Rank: 6
等 级:贵宾
威 望:20
帖 子:1435
专家分:0
注 册:2005-12-12
收藏
得分:0 
「纯虚拟」(pure virtual) 成员函数是什麽? 
 
ABC 的某种成员函数,你只能在衍生的类别中实作它。 
 
有些成员函数只存於观念中,没有任何实质的定义。譬如,假设我要你画个 Shape, 
它位於 (x,y),大小为 7。你会问我「我该画哪一种 shape?」(圆、方、六边…… 
都有不同的画法。)在 C++ 里,我们可以先标出有一个叫做 "draw()" 这样的运作 
行为,且规定它只能(逻辑上)在子类别中定义出来: 
 
         class Shape { 
         public: 
           virtual void draw() const = 0; 
           //...                     ^^^--- "= 0" 指:它是 "pure virtual" 
         }; 
 
此纯虚拟函数让 "Shape" 变成一个 ABC。若你愿意,你可以把 "= 0" 语法想成是: 
该程式码是位於 NULL 指标处。因此,"Shape" 提供一个服务项目,但它现在尚无法 
提供实质的程式码以实现之。这样会确保:任何由 Shape 衍生出的 [具体的] 类别 
之物件,“将会”有那个我们事先规定的成员函数,即使基底类别尚无足够的资讯去 
真正的“定义”它。 

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:41
yuyunliuhen
Rank: 6Rank: 6
等 级:贵宾
威 望:20
帖 子:1435
专家分:0
注 册:2005-12-12
收藏
得分:0 
怎样替整个类别阶层提供列印的功能? 
 
提供一个 friend operator<< 去呼叫 protected 的虚拟函数: 
 
         class Base { 
         public: 
           friend ostream& operator<< (ostream& o, const Base& b) 
             { b.print(o); return o; } 
           //... 
         protected: 
           virtual void print(ostream& o) const;  //或 "=0;" 若 "Base" 是个 ABC 
         }; 
 
         class Derived : public Base { 
         protected: 
           virtual void print(ostream& o) const; 
         }; 
 
这样子所有 Base 的子类别只须提供它们自己的 "print(ostream&) const" 成员函 
数即可(它们都共用 "<<" operator)。这种技巧让夥伴像是有了动态系结的能力。 

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:41
yuyunliuhen
Rank: 6Rank: 6
等 级:贵宾
威 望:20
帖 子:1435
专家分:0
注 册:2005-12-12
收藏
得分:0 
何时该把解构子弄成 virtual? 
 
当你可能经由基底的指标去 "delete" 掉衍生的类别时。 
 
虚拟函数把某物件所属之真正类别所附的程式码,而非该指标/参考本身之类别所附 
的程式给系结上去。 当你说 "delete basePtr",且它的基底有虚拟解构子的话,则 
真正会被呼叫到的解构子,就是 *basePtr 物件之型态所属的解构子,而不是该指标 
本身之型态所附的解构子。一般说来这的确是一件好事。 
 
让你方便起见,你唯一不必将某类别的解构子设为 virtual 的场合是:「该类别“ 
没有”任何虚拟函数」。因为加入第一个虚拟函数,就会替每个物件都添加额外的空 
间负担(通常是一个机器 word 的大小),这正是编译器实作出动态系结的□密;它 
通常会替每个物件加入额外的指标,称为「虚拟指标表格」(virtual table pointer) 
,或是 "vptr" 。 

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:42
yuyunliuhen
Rank: 6Rank: 6
等 级:贵宾
威 望:20
帖 子:1435
专家分:0
注 册:2005-12-12
收藏
得分:0 

虚拟建构子 (virtual constructor) 是什麽? 
 
一种让你能做些 C++ 不直接支援的事情之惯用法。 
 
欲做出虚拟建构子的效果,可用个虚拟的 "createCopy()" 成员函数(用来做为拷贝 
建构子),或是虚拟的 "createSimilar()" 成员函数(用来做为预设建构子)。 
 
         class Shape { 
         public: 
           virtual ~Shape() { }          //详见 "virtual destructors" 
           virtual void draw() = 0; 
           virtual void move() = 0; 
           //... 
           virtual Shape* createCopy() const = 0; 
           virtual Shape* createSimilar() const = 0; 
         }; 
 
         class Circle : public Shape { 
         public: 
           Circle* createCopy()    const { return new Circle(*this); } 
           Circle* createSimilar() const { return new Circle(); } 
           //... 
         }; 
 
执行了 "Circle(*this)" 也就是执行了拷贝建构的行为(在这些运作行为中, 
"*this" 的型态为 "const Circle&")。"createSimilar()" 亦类似,但它乃建构出 
一个“预设的”Circle。 
 
这样用的话,就如同有了「虚拟建构子」(virtual constructors): 
 
         void userCode(Shape& s) 
         { 
           Shape* s2 = s.createCopy(); 
           Shape* s3 = s.createSimilar(); 
           //... 
           delete s2;    // 该解构子必须是 virtual 才行!! 
           delete s3;    // 如上. 
         } 


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:42
yuyunliuhen
Rank: 6Rank: 6
等 级:贵宾
威 望:20
帖 子:1435
专家分:0
注 册:2005-12-12
收藏
得分:0 
有任何好的 C++ 程式写作的标准吗? 
 
感谢您阅读这份文件,而不是再发明自己的一套。 
 
但是请不要在 comp.lang.c++ 里问这问题。几乎所有软体工程师,或多或少都把这 
种东西看成是「大玩具」。而且,一些想成为 C++ 程式撰写标准的东西,是由那些 
不熟悉这语言及方法论的人弄出来的,所以最後它只能成为「过去式」的标准。这种 
「摆错位置」的现象,让大家对程式写作标准产生不信任感。 
 
很明显的,在 comp.lang.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:43
yuyunliuhen
Rank: 6Rank: 6
等 级:贵宾
威 望:20
帖 子:1435
专家分:0
注 册:2005-12-12
收藏
得分:0 
程式撰写标准是必要的吗?有它就够了吗? 
 
程式撰写标准不会让不懂 OO 的人变懂;只有训练及经验才有可能。如果它有用处的 
话,那就是抑制住那些琐碎无关紧要的程式片段--当大机构想把零散的程式设计组 
织整合起来时,这些片段常常会出现。 
 
但事实上你要的不光是这种标准而已。它们提供的架构让新手少去担心一些自由度, 
但是系统化的方法论会比这些好看的标准做得更好。组织机构需要的是一致性的设计 
与实行“哲学”,譬如:强型别或弱型别?用指标还是参考介面? stream I/O 还是 
stdio? C++ 程式该不该呼叫 C 的?反过来呢? ABC 该怎麽用?继承该用为实作的 
技巧还是特异化的技巧?该用哪一种测试策略?一一去检查吗?该不该为每个资料成 
员都提供一致的 "get" 和 "set" 介面?介面该由外往内还是由内往外设计?错误状 
况该用 try/catch/throw 还是传回值来处理?……等等。 
 
我们需要的是详细的“设计”部份的「半标准」。我推荐一个三段式标准:训练、谘 
询顾问以及程式库。训练乃提供「密集教学」,谘询顾问让 OO 观念深刻化,而非仅 
仅是被教过而已,高品质的程式库则是提供「长程的教学」。上述三种培训都有很热 
门的市场景况。(【译注】无疑的,这是指美、加地区。)接受过上述培训的组织都 
有如此的忠告:「买现成的吧,不要自己硬干 (Buy, Don't Build.)。」买程式库, 
买训练课程,买开发工具,买谘询顾问。想靠自学来达到成功的工具厂商及应用/系 
统厂商,都会发现成功很困难。 
 
【译注】这一段十分具有参考价值。不过有些背景资料得提供给各位参考。别忘了: 
         作者是美国人,是以该地为背景,且留意一下他所服务的公司是做什麽的.. 
         ... :-)   唉!国内有这麽多的专业顾问公司吗? :-< 
 
少数人会说:程式撰写标准只是「理想」而已,但在上述的组织机构中,它仍有其必 
要性。 
 
底下的 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:43
yuyunliuhen
Rank: 6Rank: 6
等 级:贵宾
威 望:20
帖 子:1435
专家分:0
注 册:2005-12-12
收藏
得分:0 
我们的组织该以以往 C 的经验来决定程式撰写标准吗? 
 
No! 
 
不论你的 C 经验有多丰富,不论你有多高深的 C 能力,好的 C 程式员并不会让你 
直接就成为好的 C++ 程式员。从 C 移到 C++ 并不仅是学习 "++" 的语法语意而已 
,一个组织想达到 OOP 的境界,却未将 "OO" 的精神放进 OOP 里的话,只是自欺罢 
了;会计的资产负债表会把他们的愚蠢显现出来。 
 
C++ 程式撰写标准应该由 C++ 专家来调整,不妨先在 comp.lang.c++ 里头问问题( 
但是不要用 "coding standard" 这种字眼;只要这样子问:「这种技巧有何优缺点 
?」)。找个能帮你避开陷阱的高手,上个训练课程,买程式库,看看「好的」程式 
库是否合乎你的程式撰写标准。绝对不要光靠自己来制定标准,除非你对它已有某种 
程度的掌握。没有标准总比有烂标准好,因为不恰当的「官方说法」会让不够聪明的 
平民难以追随。现在 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 
我该在函数中间或是开头来宣告区域变数? 
 
在第一次用到它的地方附近。 
 
物件在宣告的时候就会被初始化(被建构)。如果在初始化物件的地方没有足够的资 
讯,直到函数中间才有的话,你可以在开头处初始个「空值」给它,等以後再「设定 
」其值;你也可以在函数中间再初始个正确的东西给它。以执行效率来说,一开始就 
让它有正确的值,会比先建立它,搞一搞它,之後再重建它来得好。以像 "String" 
这种简单的例子来看,会有 350% 的速度差距。在你的系统上可能会不同;当然整个 
系统可能不会降低到 300+%,但是“一定”会有不必要的性能衰退现象。 
 
常见的反驳是:「我们会替物件的每个资料提供 "set" 运作行为,则建构时的额外 
耗费就会分散开来。」这比效能负荷更糟,因为你添加了维护的梦靥。替每个资料提 
供 "set" 运作行为就等於对资料不设防:你把内部实作技巧都显露出来了。你隐藏 
到的只有成员物件的实体“名字”而已,但你用到的 List、String 和 float(举例 
来说)型态都曝光了。通常维护会比 CPU 执行时间耗费的资源更多。 
 
区域变数应该在靠近它第一次用到之处宣告。很抱歉,这和 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
快速回复:推荐:C++语言常见问题解答
数据加载中...
 
   



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

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