C 虛函式的詳解

2021-09-08 11:25:55 字數 4326 閱讀 4994

5.4.2 虛函式詳解

1.虛函式的定義

虛函式就是在基類中被關鍵字virtual說明,並在派生類重新定義的函式。虛函式的作用是允許在派生類中重新定義與基類同名的函式,並且可以通過基類指標或引用來訪問基類和派生類中的同名函式。

虛函式的定義是在基類中進行的,它是在基類中需要定義為虛函式的成員函式的宣告中冠以關鍵字virtual。定義虛函式的格式如下:

virtual 函式型別 函式名(形參表)

在基類中的某個成員函式宣告為虛函式後,此虛函式就可以在乙個或多個派生類中被重新定義。在派生類中重新定義時,其函式型別、函式名、引數個數、引數型別的順序,都必須與基類中的原型完全相同。 

//例 5.21 虛函式的使用

#includeusing

namespace

std;

class

b0};

class b1:public

b0};

class b2:public

b1};

intmain()

/*在程式中,語句op->print();

出現了3次,由於op指向的物件不同,每次出現都執行了相應物件的虛函式print

程式執行結果:

b0::print()

b1::print()

b2::print()

說明:(1)若在基類中,只是宣告虛函式原型(需要加上virtual),而在類外定義虛函式時,則不必再加上virtual。

(2)在派生類中重新定義時,其函式型別、函式名、引數個數、引數型別的順序,都必須與基類中的原型完全相同。

(3)c++規定,當乙個成員函式被定義為虛函式後,其派生類中符合重新定義虛函式要求的同名函式都自動稱為虛函式。因此,在派生類中重新定義該虛函式時,關鍵字virtual可寫可不寫。但是為了程式更加清晰,最好在每一層派生類中定義函式時都加上關鍵字virtual。

(4)如果在派生類中沒有對基類的虛函式重新定義,則公有派生類繼承其直接基類的虛函式。

乙個虛函式無論被公有繼承多少次。它仍然保持其虛函式的特性。

例如:class b0;

class b1:public b0;

若在公有派生類b1中沒有重新定義虛函式show,則函式在派生類中被繼承,仍然是虛函式。

(5)虛函式必須是其所在類的成員函式,而不能是友元函式,也不能是靜態成員函式,因為虛函式的呼叫要靠特定的物件來決定該啟用哪個函式。

(6)雖然使用物件名和點運算子的方式也可以呼叫虛函式,但是這種呼叫是在編譯時進行的,是靜態聯編,它沒有利用虛函式的特性。只有通過指標訪問虛函式時才能獲得執行時的多型性。

2. 虛析構函式

在c++中,不能宣告虛建構函式,但是可以宣告虛析構函式。

//例5.23 虛析構函式的引例

#includeusing

namespace

std;

classb};

class d:public

b};

intmain()

*//*

執行結果是:

呼叫派生類d的析構函式

呼叫基類b的析構函式

顯然本程式的執行結果是符和預想的。但是,如果在主函式中用new運算子建立乙個無名物件

和定義了乙個基類的物件指標,並將無名的物件的位址賦給這個物件指標。當用delete運算子

撤銷無名物件時,系統只執行基類的析構函式,而不執行派生類的析構函式。

例如下面的例子:

*/

//例5.24 虛析構函式的引例2

#includeusing

namespace

std;

classb};

class d:public

b};

intmain() /*

程式執行結果:

呼叫基類b的析構函式

程式結果表示,本程式只執行了基類b的析構函式,而沒有執行派生類d的析構函式。

原因是:當撤銷指標p所指的派生類的無名物件,而呼叫析構函式時,採用了靜態聯編方式,

只呼叫了基類b的析構函式。

那麼如何在撤銷指標p所指的派生類的無名物件,既呼叫基類b的析構函式,也呼叫派生類d的

析構函式呢?

方法是:可以將基類的析構函式宣告為虛析構函式,採用了多型性的動態聯編方式。

虛析構函式沒有型別,也沒有引數,和普通虛函式相比,虛析構函式比較簡單。

其宣告格式:

virtual ~類名()

*/

//例5.25 虛析構函式的使用

#includeusing

namespace

std;

classb};

class d:public

b};

intmain()

/*程式執行結果是:

呼叫派生類d的析構函式

呼叫基類b的析構函式

說明:雖然派生類的析構函式與基類的析構函式名字不相同,但是如果將基類的析構函式

定義為虛函式,則由該基類所派生的所有派生類的析構函式也都自動成為虛函式。

*/

3.虛函式與過載函式的關係

在乙個派生類中重新定義基類的虛函式是函式過載的另一種形式,但它不同於一般函式過載。

當普通的函式過載時,其函式的引數或引數型別有所不同,函式的返回型別也可以不同。但是當過載乙個虛函式時,也就是說在派生類中重新定義虛函式時,要求函式名、返回型別、引數個數、引數的型別和順序與基類的虛函式原型完全相同。如果僅僅返回型別不同,其餘均相同,系統會給出錯誤資訊;若僅僅函式名相同,而引數的個數、型別或順序不同,系統將它作為普通的函式過載,這時虛函式的特性將丟失。 

//例5.26 虛函式與過載函式的關係

#includeusing

namespace

std;

class

base;

class derived:public

base;

void

base::func1()

void

base::func2()

void

base::func3()

void

base::func4()

void

derived::func1()

void derived::func2(int

i)void

derived::func4()

intmain()

/*程式執行結果是:

--derived func1--

--base func2--

--base func4--

*/

4. 多重繼承與虛函式 

//例5.27 多重繼承與虛函式的例子

#includeusing

namespace

std;

class

base1

}; class

base2

};class derived:public base1,public

base2

};int

main()

5.虛函式的綜合應用 

//例5.28 應用c++的多型性,計算三角形、矩形和圓的面積。

#include#define pi 3.1416

using

namespace

std;

class shape

shape(double a=0.0,double b=0.0) //

帶預設的建構函式

virtual

void

area()

protected

:

double

x;

double

y;

};class ********:public shape

void

area()

};class square:public shape

void

area()

}; class circle:public shape

void

area()

}; int

main() /*

程式執行結果:

在基類中定義的虛基類為派生類提供乙個公共的介面,以便派生類根據需要重新定義虛函式

三角形的高是:10,底是:6

三角形面積:30

矩形的長是:10,寬是:6

矩形面積:60

圓的半徑是:

圓面積:314.16

*/

C 虛函式和虛函式表詳解

在講解虛函式之前需要先區分一下以下定義 過載,重寫,重定義 過載 同乙個類中函式名相同,函式的引數列表不相同的兩個及兩個以上的函式就是函式過載。注意 函式的返回值不能作為函式是否過載的依據。重寫 是在子類繼承父類的時候,對父類的虛函式進行了覆蓋。重寫會使程式發生動態聯編,產生多型。重定義 是在子類繼...

C 虛函式及虛函式表詳解

多型 的關鍵在於通過基類指標或引用呼叫乙個虛函式時,編譯時不確定到底呼叫的是基類還是派生類的函式,執行時才確定。include using namespace std class a virtual void func2 class b public a int main 在 32 位編譯模式下,程...

c 中的虛函式詳解

廢話少說直接上 用乙個測試來闡述虛函式 include include using namespace std 有虛函式的類 class a virtual void g private int a class b public a private int b b b b b a a a a int...