📄 virtualfunction.html
字号:
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<link rel="stylesheet" href="css/stdlayout.css" type="text/css">
<link rel="stylesheet" href="css/print.css" type="text/css">
<meta content="text/html; charset=gb2312" http-equiv="content-type">
<title>虚拟函式(Virtual function)</title>
</head>
<body>
<h3><a href="http://caterpillar.onlyfun.net/GossipCN/index.html">From
Gossip@caterpillar</a></h3>
<h1><a href="CppGossip.html">C++
Gossip: 虚拟函式(Virtual function)</a></h1>
之前曾经介绍过函式与运算子的重载(Overload),重载可以使用一个函式名称来执行不同的实作,这是一种“编译时期”就需决定的方式,这是“早期系
结”(Early binding)、“静态系结”(Static
binding),因为在编译时就可以决定函式的呼叫对象,它们的呼叫位址在编译时就可以得知。 <br>
<br>
“虚拟函式”(Virtual function)可以实现“执行时期”的多型支援,是一个“晚期系结”(Late
binding)、“动态系结”(Dynamic binding),也就是指必须在执行时期才会得知所要调用的物件或其上的公开介面。<br>
<br>
在谈虚拟函式之前必须先知道,一个基底类别的物件指标,可以用来指向其衍生类别物件而不会发生错误,例如若基底类别是Foo1,而衍生类别是Foo2,则
下面这个指定是可以接受的: <br>
<div style="margin-left: 40px;"><span style="font-weight: bold; font-family: Courier New,Courier,monospace;">Foo1 *fptr; </span><br style="font-weight: bold; font-family: Courier New,Courier,monospace;">
<span style="font-weight: bold; font-family: Courier New,Courier,monospace;">Foo2 f2; </span><br style="font-weight: bold; font-family: Courier New,Courier,monospace;">
<span style="font-family: Courier New,Courier,monospace;"><span style="font-weight: bold;">f</span></span><span style="font-weight: bold; font-family: Courier New,Courier,monospace;">ptr = &f2;</span><br>
</div>
<br>
多型与动态系结的基础从这开始,它们只有在使用指标或参考时才得以发挥它们的特性,然而由于fptr仍是Foo1类型的指标,它只能存取Foo1中有定义
的成员,目前来说也只能操作Foo1中的成员。<br>
<br>
注意将衍生类别型态的指标指向基底类别的物件基本是不可行的(虽然可以使用型态转换的方式来勉强达成,但并不鼓励),衍生类别的指标并不能存取基底类别的
成员。 <br>
<br>
虚拟函式是一种成员函式,它在基底类别中使用关键字"virtual"宣告(定义),并在衍生类别中重新定义虚拟函式,这将成员函式的操作决议
(Resolution)推迟至执行时期再决定。<br>
<br>
虚拟函式可以实现执行时期的“多型”,也就是“一个介面,多种函式”,一个含有虚拟函式的类别被称为“多型的类别”(Polymorphic
class),当一个基底类别型态的指标指向一个含有虚拟函式的衍生类别,您就可以使用这个指标来存取衍生类别中的虚拟函式,下面这个例子是个简单的示
范: <br>
<br>
<pre>#include <iostream> <br>using namespace std; <br><br>class Foo1 { <br>public: <br> virtual void show() { // 虚拟函式 <br> cout << "Foo1's show" << endl; <br> } <br>}; <br><br>class Foo2 : public Foo1 { <br>public: <br> virtual void show() { // 虚拟函式 <br> cout << "Foo2's show" << endl; <br> } <br>}; <br><br>void showFooByPtr(Foo1 *foo) {<br> foo->show();<br>}<br><br>void showFooByRef(Foo1 &foo) {<br> foo.show();<br>}<br><br>int main() { <br> Foo1 f1; <br> Foo2 f2; <br><br> // 动态系结 <br> showFooByPtr(&f1); <br> showFooByPtr(&f2);<br> cout << endl;<br> <br> // 动态系结 <br> showFooByRef(f1); <br> showFooByRef(f2);<br> cout << endl; <br><br> // 静态系结 <br> f1.show(); <br> f2.show(); <br><br> return 0;<br>}</pre>
<span class="postbody"><br>
执行结果:</span><br>
<table style="text-align: left; width: 100%;" border="0" cellpadding="2" cellspacing="2">
<tbody>
<tr>
<td style="background-color: rgb(0, 0, 0);"><small><span style="color: rgb(255, 255, 255);">Foo1's show<br>
Foo2's show<br>
<br>
Foo1's show<br>
Foo2's show<br>
<br>
Foo1's show<br>
Foo2's show</span></small></td>
</tr>
</tbody>
</table>
<br>
showFooByPtr()与showFooByRef()函式并无法事先知道要操作的是哪一个物件的哪一个公开介面,最后的操作要在执行时期才能决
定。<br>
<br>
衍生类别中重新定义虚拟函式时,virtual可以根据需求加上,如果再接下来的衍生类别仍想进行多型操作,则加上virtual,如果不打算进行多型操
作,则可以不加上。<br>
</body>
</html>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -