⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 [20] inheritance virtual functions, c++ faq lite.htm

📁 c++faq。里面有很多关于c++的问题的解答。
💻 HTM
📖 第 1 页 / 共 2 页
字号:
<P>相比而言,虚成员函数是动态确定的(在运行时)。也就是说,成员函数(在运行时)被动态地选择,该选择基于对象的类型,而不是指向该对象的指针/引用的类型。这被称作“动态绑定”。大多数的编译器使用以下的一些的技术:如果对象有一个或多个虚函数,编译器将一个<BR>隐藏的指针放入对象,该指针称为“virtual-pointor”或“v-pointer”。这个v-pointer指向一个全局表,该表称为“虚函数表(virtural-table)”或“v-table”。<BR><BR>编译器为每个含有至少一个虚函数的类创建一个v-table。例如,如果Cirle类有虚函数d<TT>draw()</TT>、<TT>move()</TT> 
<TT>resize()</TT>,那么将有且只有一个和Cricle类相关的v-table,即使有一大堆Circle对象。并且每个&nbsp;Circle对象的&nbsp;v-poiner将指向&nbsp;Circle的这个&nbsp;v-table。该&nbsp;v-table自己有指向类的各个虚函数的指针。例如,Circle&nbsp;的v-table&nbsp;会有三个指针:一个指向<TT>Circle::draw()</TT>,一个指向&nbsp;<TT>Circle::move()</TT>,还有一个指向<TT>Circle::resize()</TT>。<BR><BR>在分发一个虚函数时,运行时系统跟随对象的&nbsp;v-pointer找到类的&nbsp;v-table,然后跟随v-table中适当的项找到方法的代码。<BR><BR>以上技术的空间开销是存在的:每个对象一个额外的指针(仅仅对于需要动态绑定的对象),加上每个方法一个额外的指针(仅仅对于虚方法)。时间开销也是有的:和普通函数调用比较,虚函数调用需要两个额外的步骤(得到v-pointer的值,得到方法的地址)。由于编译器在编译时就通过指针类型解决了非虚函数的调用,所以这些开销不会发生在非虚函数上。<BR><BR>注意:由于没有涉及诸如多继承,虚继承,RTTI等内容,也没有涉及诸如page 
fault,通过指向函数的指针调用函数等空间/时间论的内容,所以以上讨论是相当简单的。如果你想知道其他的内容,请询问&nbsp;<EM><A 
href="news:comp.lang.c++"><TT>comp.lang.c++</TT></A></EM>;而不要给我发E-MAIL! 
<P><SMALL>[&nbsp;<A 
href="http://www.sunistudio.com/cppfaq/virtual-functions.html#top">Top</A> 
|&nbsp;<A 
href="http://www.sunistudio.com/cppfaq/virtual-functions.html#bottom">Bottom</A> 
|&nbsp;<A 
href="http://www.sunistudio.com/cppfaq/basics-of-inheritance.html">Previous&nbsp;section</A> 
|&nbsp;<A 
href="http://www.sunistudio.com/cppfaq/proper-inheritance.html">Next&nbsp;section</A> 
]</SMALL> 
<HR>

<P><A name=[20.4]></A>
<DIV class=FaqTitle>
<H3>[20.4] 析构函数何时该时虚拟的?</H3></DIV>
<P>当你可能通过基类指针删除派生类对象时。
<P>虚函数绑定到对象的类的代码,而不是指针/引用的类。如果基类有虚析构函数,<TT>delete&nbsp;basePtr</TT>时(译注:即基类指针),*basePtr&nbsp;的对象类型的析构函数被调用,而不是该指针的类型的析构函数。这通常是一件好事情。
<P><EM>TECHNO-GEEK WARNING; PUT YOUR PROPELLER HAT ON.</EM> 
<BR>从技术上来说,如果你打算允许其他人通过基类指针调用对象的析构函数(通过<TT>delete</TT>这样做是正常的),并且被析构的对象是有重要的析构函数的派生类的对象,就需要让基类的析构函数成为虚拟的。如果一个类有显式的析构函数,或者有成员对象,该成员对象或基类有重要的析构函数,那么这个类就有重要的析构函数。(注意这是一个递归的定义(例如,某个具有重要析构函数的类,它有一个成员对象(它有基类(该基类有成员对象(它有基类(该基类有显式的析构函数))))))<BR><EM>END 
TECHNO-GEEK WARNING; REMOVE YOUR PROPELLER HAT</EM> 
<P>如果你对以上的规则理解有困难,试试这个简单的:类应该有虚析构函数,除非这个类没有虚函数。原理:如果有虚函数,说明你想通过基类指针来使用派生对象,并且你所可能做的事情之中,可能包含了调用析构函数(通常通过<TT>delete</TT>隐含完成)。一旦你在类中加上了一个虚函数,你就已经需要为每一个对象支付空间代价(每个对象一个指针;注意这是理论上的编译器特性;实际上每个编译器都是这样做的),所以这时使析构函数成为虚拟的通常不会额外付出什么。
<P><SMALL>[&nbsp;<A 
href="http://www.sunistudio.com/cppfaq/virtual-functions.html#top">Top</A> 
|&nbsp;<A 
href="http://www.sunistudio.com/cppfaq/virtual-functions.html#bottom">Bottom</A> 
|&nbsp;<A 
href="http://www.sunistudio.com/cppfaq/basics-of-inheritance.html">Previous&nbsp;section</A> 
|&nbsp;<A 
href="http://www.sunistudio.com/cppfaq/proper-inheritance.html">Next&nbsp;section</A> 
]</SMALL> 
<HR>

<P><A name=[20.5]></A>
<DIV class=FaqTitle>
<H3>[20.5] 什么是“虚构造函数(<TT>virtual</TT> constructor)”?</H3></DIV>
<P>一种允许你做一些&nbsp;C++&nbsp;不直接支持的事情的用法。
<P>你可能通过虚函数&nbsp;<TT>virtual</TT> <TT>clone()</TT>(对于拷贝构造函数)或虚函数 
<TT>virtual</TT> <TT>create()</TT>(对于<A 
href="http://www.sunistudio.com/cppfaq/ctors.html#[10.4]">默认构造函数</A>),得到虚构造函数产生的效果。 

<P>
<DIV 
class=CodeBlock><TT>&nbsp;class&nbsp;Shape&nbsp;{<BR>&nbsp;public:<BR>&nbsp;&nbsp;&nbsp;virtual&nbsp;~Shape()&nbsp;{&nbsp;}&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TT><EM>//&nbsp;<A 
href="http://www.sunistudio.com/cppfaq/virtual-functions.html#[20.4]">虚析构函数</A></EM><TT><BR>&nbsp;&nbsp;&nbsp;virtual&nbsp;void&nbsp;draw()&nbsp;=&nbsp;0;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TT><EM>//&nbsp;<A 
href="http://www.sunistudio.com/cppfaq/abcs.html#[22.4]">纯虚函数</A></EM><TT><BR>&nbsp;&nbsp;&nbsp;virtual&nbsp;void&nbsp;move()&nbsp;=&nbsp;0;<BR>&nbsp;&nbsp;&nbsp;</TT><EM>//&nbsp;...</EM><TT><BR>&nbsp;&nbsp;&nbsp;virtual&nbsp;Shape*&nbsp;clone()&nbsp;&nbsp;const&nbsp;=&nbsp;0;&nbsp;&nbsp;&nbsp;</TT><EM>//&nbsp;使用拷贝构造函数</EM><TT><BR>&nbsp;&nbsp;&nbsp;virtual&nbsp;Shape*&nbsp;create()&nbsp;const&nbsp;=&nbsp;0;&nbsp;&nbsp;&nbsp;</TT><EM>//&nbsp;使用<A 
href="http://www.sunistudio.com/cppfaq/ctors.html#[10.4]">默认构造函数</A></EM><TT><BR>&nbsp;};<BR>&nbsp;<BR>&nbsp;class&nbsp;Circle&nbsp;:&nbsp;public&nbsp;Shape&nbsp;{<BR>&nbsp;public:<BR>&nbsp;&nbsp;&nbsp;Circle*&nbsp;clone()&nbsp;&nbsp;const&nbsp;{&nbsp;return&nbsp;new&nbsp;Circle(*this);&nbsp;}<BR>&nbsp;&nbsp;&nbsp;Circle*&nbsp;create()&nbsp;const&nbsp;{&nbsp;return&nbsp;new&nbsp;Circle();&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<BR>&nbsp;&nbsp;&nbsp;</TT><EM>//&nbsp;...</EM><TT><BR>&nbsp;}; 
</TT></DIV>
<P>在&nbsp;<TT>clone()</TT>&nbsp;成员函数中,代码&nbsp;<TT>new&nbsp;Circle(*this) 
</TT>调用&nbsp;<TT>Circle 
</TT>的拷贝构造函数来复制<TT>this</TT>的状态到新创建的<TT>Circle</TT>对象。在&nbsp;<TT>create()</TT>成员函数中,代码&nbsp;<TT>new&nbsp;Circle()</TT>&nbsp;调用<TT>Circle</TT>的<A 
href="http://www.sunistudio.com/cppfaq/ctors.html#[10.4]">默认构造函数</A>。<BR><BR>用户将它们看作“虚构造函数”来使用它们:<BR>
<DIV 
class=CodeBlock><TT>&nbsp;void&nbsp;userCode(Shape&amp;&nbsp;s)<BR>&nbsp;{<BR>&nbsp;&nbsp;&nbsp;Shape*&nbsp;s2&nbsp;=&nbsp;s.clone();<BR>&nbsp;&nbsp;&nbsp;Shape*&nbsp;s3&nbsp;=&nbsp;s.create();<BR>&nbsp;&nbsp;&nbsp;</TT><EM>//&nbsp;...</EM><TT><BR>&nbsp;&nbsp;&nbsp;delete&nbsp;s2;&nbsp;&nbsp;&nbsp;&nbsp;</TT><EM>//&nbsp;在此处,你可能需要<A 
href="http://www.sunistudio.com/cppfaq/virtual-functions.html#[20.4]">虚析构函数</A></EM><TT><BR>&nbsp;&nbsp;&nbsp;delete&nbsp;s3;<BR>&nbsp;} 
</TT></DIV>
<P>这个函数将正确工作,而不管&nbsp;<TT>Shape</TT>&nbsp;是一个<TT>Circle</TT>,<TT>Square</TT>,或是其他种类的&nbsp;<TT>Shape</TT>,甚至它们还并不存在。
<P>注意:成员函数<TT>Circle</TT>'s <TT>clone()</TT>的返回值类型故意与成员函数<TT>Shape</TT>'s 
<TT>clone()</TT>的不同。这种特征被称为“协变的返回类型”,该特征最初并不是语言的一部分。如果你的编译器不允许在<TT>Circle</TT>类中这样声明<TT>Circle*&nbsp;clone()&nbsp;const</TT>(如,提示“The 
return type is different”或“The member function's type differs from the base 
class virtual function by return type 
alone”),说明你的编译器陈旧了,那么你必须改变返回类型为<TT>Shape*。</TT> 
<P><SMALL>[&nbsp;<A 
href="http://www.sunistudio.com/cppfaq/virtual-functions.html#top">Top</A> 
|&nbsp;<A 
href="http://www.sunistudio.com/cppfaq/virtual-functions.html#bottom">Bottom</A> 
|&nbsp;<A 
href="http://www.sunistudio.com/cppfaq/basics-of-inheritance.html">Previous&nbsp;section</A> 
|&nbsp;<A 
href="http://www.sunistudio.com/cppfaq/proper-inheritance.html">Next&nbsp;section</A> 
]</SMALL> 
<HR>

<P><A name=bottom></A><A href="mailto:cline@parashift.com"><IMG height=26 
alt=E-Mail src="[20] Inheritance virtual functions, C++ FAQ Lite.files/mbox.gif" 
width=89>&nbsp;E-mail the author</A><BR>[&nbsp;<A 
href="http://www.sunistudio.com/cppfaq/index.html"><EM>C++ FAQ Lite</EM></A> 
|&nbsp;<A 
href="http://www.sunistudio.com/cppfaq/index.html#table-of-contents">Table&nbsp;of&nbsp;contents</A> 
|&nbsp;<A 
href="http://www.sunistudio.com/cppfaq/subject-index.html">Subject&nbsp;index</A> 
|&nbsp;<A 
href="http://www.sunistudio.com/cppfaq/copy-permissions.html#[1.1]">About&nbsp;the&nbsp;author</A> 
|&nbsp;<A 
href="http://www.sunistudio.com/cppfaq/copy-permissions.html#[1.2]">&copy;</A> 
|&nbsp;<A 
href="http://www.sunistudio.com/cppfaq/on-line-availability.html#[2.2]">Download&nbsp;your&nbsp;own&nbsp;copy</A>&nbsp;]<BR><SMALL>Revised 
Apr 8, 2001</SMALL> </P></BODY></HTML>

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -