📄 [23] inheritance what your mother never told you, c++ faq lite.htm
字号:
<HR>
<P><A name=[23.3]></A>
<DIV class=FaqTitle>
<H3>[23.3] 当基类构造函数调用虚函数时,为什么不调用派生类重写的该虚函数?</H3></DIV>
<P>当基类被构造时,对象还不是一个派生类的对象,所以如果 <TT>Base::Base()</TT>调用了<A
href="http://www.sunistudio.com/cppfaq/virtual-functions.html">虚函数</A>
<TT>virt()</TT>,则 <TT>Base::virt()</TT> 将被调用,即使 <TT>Derived::virt()</TT>(译注:即派生类重写的虚函数)存在。<BR><BR>同样,当基类被析构时,对象已经不再是一个派生类对象了,所以如果 <TT>Base::~Base()</TT>调用了<TT>virt()</TT>,则 <TT>Base::virt()</TT>得到控制权,而不是重写的 <TT>Derived::virt()</TT>
。<BR><BR>当你可以想象到如果 <TT>Derived::virt()</TT> 涉及到派生类的某个成员对象将造成的灾难的时候,你很快就能看到这种方法的明智。详细来说,如果 <TT>Base::Base()</TT>调用了虚函数 <TT>virt()</TT>,这个规则使得 <TT>Base::virt()</TT>被调用。如果不按照这个规则,<TT>Derived::virt()</TT>将在派生对象的派生部分被构造之前被调用,此时属于派生对象的派生部分的某个成员对象还没有被构造,而 <TT>Derived::virt()</TT>却能够访问它。这将是灾难。
<P><SMALL>[ <A
href="http://www.sunistudio.com/cppfaq/strange-inheritance.html#top">Top</A>
| <A
href="http://www.sunistudio.com/cppfaq/strange-inheritance.html#bottom">Bottom</A>
| <A
href="http://www.sunistudio.com/cppfaq/abcs.html">Previous section</A>
| <A
href="http://www.sunistudio.com/cppfaq/private-inheritance.html">Next section</A>
]</SMALL>
<HR>
<P><A name=[23.4]></A>
<DIV class=FaqTitle>
<H3>[23.4] 派生类可以重置(“覆盖”)基类的非虚函数吗?</H3></DIV>
<P>合法但不合理。
<P>有经验的 C++ 程序员有时会重新定义非虚函数(例如,派生类的实现可能可以更有效地利用派生类的资源),或者为了回避<A
href="http://www.sunistudio.com/cppfaq/strange-inheritance.html#[23.5]">隐藏规则</A>。即使非虚函数的指派基于指针/引用的静态类型而不是指针/引用所指对象的动态类型,但其客户可见性必须是一致的。
<P><SMALL>[ <A
href="http://www.sunistudio.com/cppfaq/strange-inheritance.html#top">Top</A>
| <A
href="http://www.sunistudio.com/cppfaq/strange-inheritance.html#bottom">Bottom</A>
| <A
href="http://www.sunistudio.com/cppfaq/abcs.html">Previous section</A>
| <A
href="http://www.sunistudio.com/cppfaq/private-inheritance.html">Next section</A>
]</SMALL>
<HR>
<P><A name=[23.5]></A>
<DIV class=FaqTitle>
<H3>[23.5]
“<TT>Warning: Derived::f(float) hides Base::f(int)</TT>” 是什么意思?</H3></DIV>
<P>意思是:你要完蛋了。
<P>你所处的困境是:如果基类声明了一个成员函数<TT>f(int)</TT>,并且派生类声明了一个成员函数 <TT>f(float)</TT>(名称相同,但参数类型和/或数量不同),那么 <TT>Base</TT> 的 <TT>f(int)</TT>被隐藏(hidden)而不是被重载(overloaded)或被重写(overridden)(即使 基类的<TT>f(int)</TT>是<A
href="http://www.sunistudio.com/cppfaq/virtual-functions.html">虚拟</A>的)
<P>以下是你如何摆脱困境:派生类必须有一个被隐藏成员函数的<TT>using</TT> 声明,例如:
<P>
<DIV
class=CodeBlock><TT> class Base {<BR> public:<BR> void f(int);<BR> };<BR> <BR> class Derived : public Base {<BR> public:<BR> using Base::f; </TT><EM>// This un-hides <TT>Base::f(int)</TT></EM><TT><BR> void f(double);<BR> };
</TT></DIV>
<P>如果你的编译器不支持<TT>using</TT>语法,那么就重新定义基类的被隐藏的成员函数,<A
href="http://www.sunistudio.com/cppfaq/strange-inheritance.html#[23.4]">即使它们是非虚的</A>。一般来说这种重定义只不过使用<TT>::</TT>语法调用了基类被隐藏的成员函数,如,
<P>
<DIV
class=CodeBlock><TT> class Derived : public Base {<BR> public:<BR> void f(double);<BR> void f(int i) { Base::f(i); } </TT><EM>// The redefinition merely calls <TT>Base::f(int)</TT></EM><TT><BR> };
</TT></DIV>
<P><SMALL>[ <A
href="http://www.sunistudio.com/cppfaq/strange-inheritance.html#top">Top</A>
| <A
href="http://www.sunistudio.com/cppfaq/strange-inheritance.html#bottom">Bottom</A>
| <A
href="http://www.sunistudio.com/cppfaq/abcs.html">Previous section</A>
| <A
href="http://www.sunistudio.com/cppfaq/private-inheritance.html">Next section</A>
]</SMALL>
<HR>
<P><A name=[23.6]></A>
<DIV class=FaqTitle>
<H3>[23.6] "virtual table" is an unresolved external 是什么意思?</H3></DIV>
<P>如果你得到一个连接错误"<TT>Error: Unresolved or undefined symbols detected: virtual table for class Fred</TT>",那么可能是你在 <TT>Fred</TT> 类中有一个未定义的<A
href="http://www.sunistudio.com/cppfaq/virtual-functions.html">虚</A>成员函数。<BR><BR>编译器通常会为含有虚函数的类创建一个称为“虚函数表”的不可思议的数据结构(这就是它如何处理<A
href="http://www.sunistudio.com/cppfaq/virtual-functions.html#[20.2]">动态绑定</A>的)。通常你根本不必知道它。但如果你忘了为<TT>Fred</TT> 类定义一个虚函数,则有时会得到这个连接错误。<BR><BR>许多编译器将这个不可思议的“虚函数表”放进定义类的第一个非内联虚函数的编辑单元中。因此如果 <TT>Fred</TT> 类的第一个非内联虚函数是 <TT>wilma()</TT>,那么编译器会将 <TT>Fred</TT> 的虚函数表放在 <TT>Fred::wilma()</TT> 所在的编辑单元里。不幸的是如果你意外的忘了定义 <TT>Fred::wilma()</TT>,那么你会得到一个"<TT>Fred</TT>'s
virtual table is undefined"(<TT>Fred</TT>的虚函数表未定义)的错误而不是“<TT>Fred::wilma()</TT>
is undefined”(<TT>Fred::wilma()</TT>未定义)。
<P><SMALL>[ <A
href="http://www.sunistudio.com/cppfaq/strange-inheritance.html#top">Top</A>
| <A
href="http://www.sunistudio.com/cppfaq/strange-inheritance.html#bottom">Bottom</A>
| <A
href="http://www.sunistudio.com/cppfaq/abcs.html">Previous section</A>
| <A
href="http://www.sunistudio.com/cppfaq/private-inheritance.html">Next section</A>
]</SMALL>
<HR>
<P><A name=bottom></A><A href="mailto:cline@parashift.com"><IMG height=26
alt=E-Mail
src="[23] Inheritance what your mother never told you, C++ FAQ Lite.files/mbox.gif"
width=89> E-mail the author</A><BR>[ <A
href="http://www.sunistudio.com/cppfaq/index.html"><EM>C++ FAQ Lite</EM></A>
| <A
href="http://www.sunistudio.com/cppfaq/index.html#table-of-contents">Table of contents</A>
| <A
href="http://www.sunistudio.com/cppfaq/subject-index.html">Subject index</A>
| <A
href="http://www.sunistudio.com/cppfaq/copy-permissions.html#[1.1]">About the author</A>
| <A
href="http://www.sunistudio.com/cppfaq/copy-permissions.html#[1.2]">©</A>
| <A
href="http://www.sunistudio.com/cppfaq/on-line-availability.html#[2.2]">Download your own copy</A> ]<BR><SMALL>Revised
Apr 8, 2001</SMALL> </P></BODY></HTML>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -