📄 [23] inheritance what your mother never told you, c++ faq lite.htm
字号:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3c.org/TR/1999/REC-html401-19991224/loose.dtd">
<!-- saved from url=(0057)http://www.sunistudio.com/cppfaq/strange-inheritance.html -->
<HTML><HEAD><TITLE>[23] Inheritance what your mother never told you, C++ FAQ Lite</TITLE>
<META http-equiv=Content-Type content="text/html; charset=gb2312">
<META http-equiv=Content-Language content=zh-cn>
<META content=strange-inheritance.html name=FILENAME>
<META content="[23] Inheritance what your mother never told you, C++ FAQ Lite"
name=ABSTRACT>
<META content=cline@parashift.com name=OWNER>
<META content="Marshall Cline, cline@parashift.com" name=AUTHOR>
<META content="MSHTML 6.00.2462.0" name=GENERATOR>
<META content=FrontPage.Editor.Document name=ProgId><LINK rev=made
href="mailto:cline@parashift.com"><LINK
href="[23] Inheritance what your mother never told you, C++ FAQ Lite.files/cpp-faq.css"
type=text/css rel=stylesheet></HEAD>
<BODY>
<H1><A name=top></A>[23] 继承 — 你所不知道的<BR><SMALL><SMALL>(Part of <A
href="http://www.sunistudio.com/cppfaq/index.html"><EM>C++ FAQ Lite</EM></A>, <A
href="http://www.sunistudio.com/cppfaq/copy-permissions.html#[1.2]">Copyright ©
1991-2001</A>, <A href="http://www.parashift.com/" target=OutsideTheFAQ>Marshall
Cline</A>, <A
href="mailto:cline@parashift.com">cline@parashift.com</A>)</SMALL></SMALL></H1>
<P>简体中文版翻译:<A href="http://www.sunistudio.com/nicrosoft">申旻</A>,<A
href="mailto:nicrosoft@sunistudio.com">nicrosoft@sunistudio.com</A>(<A
href="http://www.sunistudio.com/">东日制作室</A>,<A
href="http://www.sunistudio.com/asp/sunidoc.asp">东日文档</A>)</P>
<HR>
<H3>FAQs in section [23]:</H3>
<UL>
<LI><A
href="http://www.sunistudio.com/cppfaq/strange-inheritance.html#[23.1]">[23.1]
基类的非虚函数调用虚函数可以吗?</A> <IMG alt=NEW!
src="[23] Inheritance what your mother never told you, C++ FAQ Lite.files/new.gif">
<LI><A
href="http://www.sunistudio.com/cppfaq/strange-inheritance.html#[23.2]">[23.2]
上面那个FAQ让我糊涂了。那是使用虚函数的另一种策略吗?</A> <IMG alt=NEW!
src="[23] Inheritance what your mother never told you, C++ FAQ Lite.files/new.gif">
<LI><A
href="http://www.sunistudio.com/cppfaq/strange-inheritance.html#[23.3]">[23.3]
当基类构造函数调用虚函数时,为什么不调用派生类重写的该虚函数?</A>
<LI><A
href="http://www.sunistudio.com/cppfaq/strange-inheritance.html#[23.4]">[23.4]
派生类可以重置(“覆盖”)基类的非虚函数吗?</A>
<LI><A
href="http://www.sunistudio.com/cppfaq/strange-inheritance.html#[23.5]">[23.5]
“<TT>Warning: Derived::f(float) hides Base::f(int)”</TT>是什么意思?</A>
<LI><A
href="http://www.sunistudio.com/cppfaq/strange-inheritance.html#[23.6]">[23.6]
"virtual table" is an unresolved external 是什么意思?</A> </LI></UL>
<P>
<HR>
<P><A name=[23.1]></A>
<DIV class=FaqTitle>
<H3>[23.1] 基类的非虚函数调用虚函数可以吗? <IMG alt=NEW!
src="[23] Inheritance what your mother never told you, C++ FAQ Lite.files/new.gif"></H3></DIV><SMALL><EM>[Recently
created (on 4/01). <A
href="http://www.sunistudio.com/cppfaq/strange-inheritance.html#[23.2]">Click
here to go to the next FAQ in the "chain" of recent changes<!--rawtext:[23.2]:rawtext--></A>.]</EM></SMALL>
<P>可以。有时(<I>并非总是!</I>)这是一个好主意。例如,假设所有<TT>Shape</TT>(图形)对象有一个公共的打印算法。但这个算法依赖于它们的面积并且它们都有不同的方法来计算面积。在这种情况下,<TT>Shape</TT>的<TT>area()</TT>方法(译注:得到<TT>Shape</TT>面积的成员函数)必须是virtual的(可能是纯虚(pure-virtual)的),但<TT>Shape::print()</TT>可以在<TT>Shape</TT>中被定义为非虚(non-virtual)的,<A
href="http://www.sunistudio.com/cppfaq/strange-inheritance.html#[23.4]">前提是所有派生类不会需要不同的打印算法</A>。</P>
<DIV
class=CodeBlock><TT> #include "Shape.hpp"<BR> <BR> void Shape::print() const<BR> {<BR> float a = this->area(); </TT><EM>// <TT>area()</TT> 为纯虚</EM><TT><BR> </TT><EM>// ...</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.2]></A>
<DIV class=FaqTitle>
<H3>[23.2] 上面那个FAQ让我糊涂了。那是使用虚函数的另一种策略吗? <IMG alt=NEW!
src="[23] Inheritance what your mother never told you, C++ FAQ Lite.files/new.gif"></H3></DIV><SMALL><EM>[Recently
created (on 4/01). <A
href="http://www.sunistudio.com/cppfaq/private-inheritance.html#[24.2]">Click
here to go to the next FAQ in the "chain" of recent changes<!--rawtext:[24.2]:rawtext--></A>.]</EM></SMALL>
<P>是的,那是不同的策略。是的,那的确是使用虚函数的两种不同的基本方法:</P>
<OL>
<LI>假设你遇到了上一个FAQ所描述的情况:每一个派生类都有一个结构完全一样,只有一小块不同的方法。因此算法是相同的,但实质不相同。在这种情况下,你最好在基类写一个全面的算法作为<TT>public:</TT>方法(有时是非虚的),然后在派生类中写那不同的一小块。这一小块在基类中声明(通常是<TT>protected:</TT>的,纯虚的,当然至少是<TT>virtual</TT>的),并且最终在每个派生类中被定义。这种情况下最紧要的问题是包含全面的算法的<TT>public:</TT>方法是否应该是<TT>virtual</TT>的。答案是,<A
href="http://www.sunistudio.com/cppfaq/strange-inheritance.html#[23.4]">如果你认为某些派生类可能需要覆盖它</A>,就让它成为<TT>virtual</TT>的。
<LI>假设你遇到了上一个FAQ完全相反的情况,每一个派生类都有一个结构完全不同,但有一小块的大多数(如果不是全部的话)相同的方法。在这种情况下,你最好将全面的算法放在最终在派生类中定义的<TT>public:</TT>
<TT>virtual</TT>之中,并且将一小块可以被只写一次的公共代码(避免代码重复)隐藏在某处(任何地方!)。一般放在基类的<TT>protected:</TT>部分,但不是必须的,也可能不是最好的。找个地方隐藏它们就行了。注意,由于<TT>public:</TT>用户不需要/不想做它们做的事情,如果在基类中隐藏它们,通常应该使它们是<TT>protected:</TT>的。假定它们是<TT>protected:</TT>的,那么可能不应该是<TT>virtual</TT>的:如果派生类不喜欢它们之一的行为,可以不必调用这个方法。
</LI></OL>
<P>强调一下,以上列表中的是“既/又”情况,而不是“二者选一”的。换句话说,在任何给定的类上,不必在两种策略中选择。既有一个符合策略 #1
的方法<TT>f()</TT>,又有一个符合策略 #2 的方法<TT>g()</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>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -