注册 | 登录
收藏 | 帮助
热门文章
编辑推荐
相关文章  
模块复用——c++类、dll和com
获取ACCESS2000数据库中的所有表
C++语言常见问题解答(1)
C++语言常见问题解答(3)
C++语言常见问题解答(4)
在c++程序中重启自己的一种方法
您现在的位置: 顶尖设计 >> IT学院 >> 编程开发 >> C >> 文章正文
C++语言常见问题解答(2)
作者:中译者:叶秉哲  来源:永远的UNIX  点击:  更新:2006-12-19
简介:
话,太难了。 
 
        class Wilma { 
        protected: 
          void fredCallsWilma() 
            { cout << "Wilma::fredCallsWilma()\n"; wilmaCallsFred(); } 
          virtual void wilmaCallsFred() = 0; 
        }; 
 
        class Fred : private Wilma { 
        public: 
          void barney() 
            { cout << "Fred::barney()\n"; Wilma::fredCallsWilma(); } 
        protected: 
          virtual void wilmaCallsFred() 
            { cout << "Fred::wilmaCallsFred()\n"; } 
        }; 
 
======================================== 
 
Q71:我应该用指标转型方法,把「私有」衍生类别转成它的基底吗? 
 
当然不该。 
 
以私有衍生类别的运作行为、夥伴来看,从它上溯到基底类别的关系为已知的,所以 
从 PrivatelyDer* 往上转换成 Base*(或是从 PrivatelyDer& 到 Base&)是安全的 
;强制转型是不需要也不鼓励的。 
 
然而用 PrivateDer 的人应该避免这种不安全的转换,因为此乃立足於 PrivateDer 
的 "private" 决定,这个决定很容易在日後不经察觉就改变了。 
 
======================================== 
 
Q72:保护继承 (protected inheritance) 和私有继承有何关连? 
 
相似处:两者都能覆盖掉私有/保护基底类别的虚拟函数,两者都不把衍生的类别视 
为“一种”基底类别。 
 
不相似处:保护继承可让衍生类别的衍生类别知道它的继承关系(把实行细节显现出 
来)。它有好处(允许保护继承类别的子类别,藉这项关系来使用保护基底类别), 
也有代价(保护继承的类别,无法既想改变这种关系,而又不破坏到进一步的衍生类 
别)。 
 
保护继承使用 ": protected" 这种语法: 
 
        class Car : protected Engine { 
          //... 
        }; 
 
======================================== 
 
Q73:"private" 和 "protected" 的存取规则是什麽? 
 
拿底下这些类别当例子: 
 
        class B                    { /*...*/ }; 
        class D_priv : private   B { /*...*/ }; 
        class D_prot : protected B { /*...*/ }; 
        class D_publ : public    B { /*...*/ }; 
        class UserClass            { B b; /*...*/ }; 
 
没有一个子类别能存取到 B 的 private 部份。 
在 D_priv 内,B 的 public 和 protected 部份都变成 "private"。 
在 D_prot 内,B 的 public 和 protected 部份都变成 "protected"。 
在 D_publ 内,B 的 public 部份还是 public,protected 还是 protected 
 (D_publ is-a-kind-of-a B) 。 
Class "UserClass" 只能存取 B 的 public 部份,也就是:把 UserClass 从 B 那 
儿封起来了。 
 
欲把 B 的 public 成员在 D_priv 或 D_prot 内也变成 public,只要在该成员的名 
字前面加上 "B::"。譬如:想让 "B::f(int,float)" 成员在 D_prot 内也是 public 
的话,照这样写: 
 
        class D_prot : protected B { 
        public: 
          B::f;    //注意:不是写成 "B::f(int,float)" 
        }; 
 
 
====================================== 
■□ 第13节:抽象化(abstraction) 
====================================== 
 
Q74:分离介面与实作是做什麽用的? 
 
介面是企业体最有价值的资源。设计介面会比只把一堆独立的类别拼凑起来来得耗时 
,尤其是:介面需要花费更高阶人力的时间。 
 
既然介面是如此重要,它就应该保护起来,以避免被资料结构等等实作细节之变更所 
影响。因此你应该将介面与实作分离开来。 
 
======================================== 
 
Q75:在 C++ 里,我该怎样分离介面与实作(像 Modula-2 那样)? 
 
用 ABC(见下一则 FAQ)。 
 
======================================== 
 
Q76:ABC ("abstract base class") 是什麽? 
 
在设计层面,ABC 对应到抽象的概念。如果你问机械师父说他修不修运输工具,他可 
能会猜你心中想的到底是“哪一种”运输工具,他可能不会修理太空梭、轮船、脚踏 
车、核子潜艇。问题在於:「运输工具」是个抽象的概念(譬如:你建不出一辆「运 
输工具」,除非你知道要建的是“哪一种”)。在 C++,运输工具类别可当成是一个 
ABC,而脚踏车、太空梭……等等都当做它的子类别(轮船“是一种”运输工具)。 
在真实世界的 OOP 中,ABC 观念到处都是。 
 
在程式语言层面,ABC 是有一个以上纯虚拟成员函数(pure virtual)的类别(详见 
下一则 FAQ),你无法替一个 ABC 建造出物件(案例)来。 
 
======================================== 
 
Q77:「纯虚拟」(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 衍生出的 [具体的] 类别 
之物件,“将会”有那个我们事先规定的成员函数,即使基底类别尚无足够的资讯去 
真正的“定义”它。 
 
【译注】此处「定义」、「宣告」二词要分辨清楚! 
 
======================================== 
 
Q78:怎样替整个类别阶层提供列印的功能? 
 
提供一个 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)。这种技巧让夥伴像是有了动态系结的能力。 
 
======================================== 
 
Q79:何时该把解构子弄成 virtual? 
 
当你可能经由基底的指标去 "delete" 掉衍生的类别时。 
 
虚拟函数把某物件所属之真正类别所附的程式码,而非该指标/参考本身之类别所附 
的程式给系结上去。 当你说 "delete basePtr",且它的基底有虚拟解构子的话,则 
真正会被呼叫到的解构子,就是 *basePtr 物件之型态所属的解构子,而不是该指标 
本身之型态所附的解构子。一般说来这的确是一件好事。 
 
让你方便起见,你唯一不必将某类别的解构子设为 virtual 的场合是:「该类别“ 
没有”任何虚拟函数」。因为加入第一个虚拟函数,就会替每个物件都添加额外的空 
间负担(通常是一个机器 word 的大小),这正是编译器实作出动态系结的□密;它 
通常会替每个物件加入额外的指标,称为「虚拟指标表格」(virtual table pointer) 
,或是 "vptr" 。 
 
======================================== 
 
Q80:虚拟建构子 (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;    // 如上. 
        } 
 
不论该 Shape 是 Circle、Square,甚或其他还不存在的 Shape 种类,这函数都能 
正确执行。 

上一页  [1] [2] [3] 






  • 上一篇文章:
  • 下一篇文章:
  • 分享此文:该页面添加到 Mister Wong 添加到雅虎Yahoo!收藏 Add to:Del.icio.us Post to Furl Digg this 添加到Google书签 reddit spurl blogmarks 365Key 评论  收藏  分享  打印
     我来说两句
    姓名:       验证码:   
    主页: 
    评分: 1分 2分 3分 4分 5分
    本频道近期热评文章:
      关于我们 | 联系我们 | 站点地图 | 广告投放 | 友情链接 | 在线留言 | 版权申明
    版权所有 © 2004-2007 顶尖设计(bobd.cn)
    未经授权禁止转载,摘编,复制本站内容或建立镜像. 沪ICP备07504942号 
    网络110
    报警服务