5.4.2 虛函式詳解
1.虛函式的定義
虛函式就是在基類中被關鍵字virtual說明,並在派生類重新定義的函式。虛函式的作用是允許在派生類中重新定義與基類同名的函式,並且可以通過基類指標或引用來訪問基類和派生類中的同名函式。
虛函式的定義是在基類中進行的,它是在基類中需要定義為虛函式的成員函式的宣告中冠以關鍵字virtual。定義虛函式的格式如下:
virtual 函式型別 函式名(形參表)
在基類中的某個成員函式宣告為虛函式後,此虛函式就可以在乙個或多個派生類中被重新定義。在派生類中重新定義時,其函式型別、函式名、引數個數、引數型別的順序,都必須與基類中的原型完全相同。
//例 5.21 虛函式的使用
#includeusingnamespace
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 虛析構函式的引例
#includeusingnamespace
std;
classb};
class d:public
b};
intmain()
*//*
執行結果是:
呼叫派生類d的析構函式
呼叫基類b的析構函式
顯然本程式的執行結果是符和預想的。但是,如果在主函式中用new運算子建立乙個無名物件
和定義了乙個基類的物件指標,並將無名的物件的位址賦給這個物件指標。當用delete運算子
撤銷無名物件時,系統只執行基類的析構函式,而不執行派生類的析構函式。
例如下面的例子:
*/
//例5.24 虛析構函式的引例2
#includeusingnamespace
std;
classb};
class d:public
b};
intmain() /*
程式執行結果:
呼叫基類b的析構函式
程式結果表示,本程式只執行了基類b的析構函式,而沒有執行派生類d的析構函式。
原因是:當撤銷指標p所指的派生類的無名物件,而呼叫析構函式時,採用了靜態聯編方式,
只呼叫了基類b的析構函式。
那麼如何在撤銷指標p所指的派生類的無名物件,既呼叫基類b的析構函式,也呼叫派生類d的
析構函式呢?
方法是:可以將基類的析構函式宣告為虛析構函式,採用了多型性的動態聯編方式。
虛析構函式沒有型別,也沒有引數,和普通虛函式相比,虛析構函式比較簡單。
其宣告格式:
virtual ~類名()
*/
//例5.25 虛析構函式的使用
#includeusingnamespace
std;
classb};
class d:public
b};
intmain()
/*程式執行結果是:
呼叫派生類d的析構函式
呼叫基類b的析構函式
說明:雖然派生類的析構函式與基類的析構函式名字不相同,但是如果將基類的析構函式
定義為虛函式,則由該基類所派生的所有派生類的析構函式也都自動成為虛函式。
*/
3.虛函式與過載函式的關係
在乙個派生類中重新定義基類的虛函式是函式過載的另一種形式,但它不同於一般函式過載。
當普通的函式過載時,其函式的引數或引數型別有所不同,函式的返回型別也可以不同。但是當過載乙個虛函式時,也就是說在派生類中重新定義虛函式時,要求函式名、返回型別、引數個數、引數的型別和順序與基類的虛函式原型完全相同。如果僅僅返回型別不同,其餘均相同,系統會給出錯誤資訊;若僅僅函式名相同,而引數的個數、型別或順序不同,系統將它作為普通的函式過載,這時虛函式的特性將丟失。
//例5.26 虛函式與過載函式的關係
#includeusingnamespace
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 多重繼承與虛函式的例子
#includeusingnamespace
std;
class
base1
}; class
base2
};class derived:public base1,public
base2
};int
main()
5.虛函式的綜合應用
//例5.28 應用c++的多型性,計算三角形、矩形和圓的面積。
#include#define pi 3.1416using
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...