荔园在线

荔园之美,在春之萌芽,在夏之绽放,在秋之收获,在冬之沉淀

[回到开始] [上一篇][下一篇]


发信人: Second (石开), 信区: Program
标  题: Part of C++ FAQ Lite[23]--继承(你所不知道的)
发信站: 荔园晨风BBS站 (Thu Jun  7 05:52:43 2001), 转信

译文出处: 东日制作室——东日文档
[23] 继承 — 你所不知道的
(Part of C++ FAQ Lite, Copyright ? 1991-96, Marshall Cline, cline@parashift.
com)
----------------------------------------------------------------------------
----
FAQs in section [23]:
[23.1] 当基类构造函数调用虚函数时,为什么不调用派生类重写的该虚函数?
[23.2] 派生类可以重置(“覆盖”)基类的非虚函数吗?
[23.3] “Warning: Derived::f(float) hides Base::f(int)” 是什么意思?
[23.4] "virtual table" is an unresolved external 是什么意思?
----------------------------------------------------------------------------
----
[23.1] 当基类构造函数调用虚函数时,为什么不调用派生类重写的该虚函数?
当基类被构造时,对象还不是一个派生类的对象,所以如果 Base::Base() 调用了虚函

virt(),则 Base::virt() 将被调用,即使 Derived::virt() (译注:即派生类重写的

函数)存在。
同样,当基类被析构时,对象已经不再是一个派生类对象了,所以如果 Base::~Base()

调用了 virt(),则 Base::virt() 得到控制权,而不是重写的 Derived::virt()。
当你可以想象到如果 Derived::virt() 涉及到派生类的某个成员对象将造成的灾难的时
候,
你很快就能看到这种方法的明智。详细来说,如果 Base::Base() 调用了虚函数 virt(
),
这个规则使得 Base::virt()被调用。如果不按照这个规则,Derived::virt()将在派生
对象
的派生部分被构造之前被调用,此时属于派生对象的派生部分的某个成员对象还没有被
构造,
而 Derived::virt() 却能够访问它。这将是灾难。
----------------------------------------------------------------------------
----
[23.2] 派生类可以重置(“覆盖”)基类的非虚函数吗?
合法但不合理。
有经验的 C++ 程序员有时会重新定义非虚函数(例如,派生类的实现可能可以更有效地

利用派生类的资源),或者为了回避隐藏规则。即使非虚函数的指派基于指针/引用的静

态类型而不是指针/引用所指对象的动态类型,但其客户可见性必须是一致的。
----------------------------------------------------------------------------
----
[23.3] “Warning: Derived::f(float) hides Base::f(int)” 是什么意思?
意思是:你要完蛋了。
你所处的困境是:如果基类声明了一个成员函数 f(int),并且派生类声明了一个成员函

数 f(float)(名称相同,但参数类型和/或数量不同),那么 Base 的 f(int)被隐藏
(hidden)而不是被重载(overloaded)或被重写(overridden)(即使 Base f(int)

是虚拟的)
以下是你如何摆脱困境:派生类必须有一个被隐藏成员函数的 using 声明,例如:
    class Base {
    public:
      void f(int);
    };
    class Derived : public Base {
    public:
      using Base::f;    // This un-hides Base::f(int)
      void f(double);
    };
如果你的编译器不支持 using 语法,那么就重新定义基类的被隐藏的成员函数,即使
它们是非虚函数。一般来说这种重定义只不过使用 :: 语法调用了基类被隐藏的成员函

数,如,
    class Derived : public Base {
    public:
      void f(double);
      void f(int i) { Base::f(i); }  // The redefinition merely calls Base::
f(int)
    };
----------------------------------------------------------------------------
----
[23.4] "virtual table" is an unresolved external 是什么意思?
如果你得到一个连接错误“Error: Unresolved or undefined symbols detected: vir
tual
table for class Fred”,那么可能是你在 Fred 类中有一个未定义的虚成员函数。
编译器通常会为含有虚函数的类创建一个称为“虚函数表”的不可思议的数据结构(这
就是它
如何处理动态绑定的)。通常你根本不必知道它。但如果你忘了为 Fred 类定义一个虚
函数,
则有时会得到这个连接错误。
许多编译器将这个不可思议的“虚函数表”放进定义类的第一个非内联虚函数的编辑单
元中。
因此如果 Fred 类的第一个非内联虚函数是 wilma(),那么编译器会将 Fred 的虚函数
表放
在 Fred::wilma() 所在的编辑单元里。不幸的是如果你意外的忘了定义 Fred::wilma(
),
那么你会得到一个“Fred's virtual table is undefined”(Fred的虚函数表未定义)

错误而不是“Fred::wilma() is undefined”(Fred::wilma()未定义)。


--
                            既然热爱生命
                            那么,
                            一切都在意料之中。

※ 来源:·荔园晨风BBS站 bbs.szu.edu.cn·[FROM: 192.168.28.16]


[回到开始] [上一篇][下一篇]

荔园在线首页 友情链接:深圳大学 深大招生 荔园晨风BBS S-Term软件 网络书店