C++ 虚函数
注:虛函數(shù)和虛繼承是兩個概念,解決的問題也不同;
虛函數(shù):防止多重派生時,使用指針調(diào)用同名函數(shù)時以基類函數(shù)為準(非同名隱藏規(guī)則)
//使用virtual來達到同名隱藏規(guī)則的效果B b(1, 2, 3, 4); A0 *a; a = &b; a->Show();//同名隱藏規(guī)則下的派生類函數(shù)直接輸出自己的函數(shù)虛繼承(虛基類):解決“121”類二義性問題(防止在多重派生的基礎上再次派生而產(chǎn)生二義性)
根據(jù)"賦值(父子)兼容規(guī)則":派生類可以作為父類使用,因為其繼承了基類,但是基類不能夠作為派生類使用;
在兼容規(guī)則下,使用派生類作為基類使用的時候,當遇到基類與派生類中存在同名的函數(shù)的時候,編譯器會以以基類的函數(shù)為準,但是這不免有些使用不便;
為了產(chǎn)生:指定哪個類調(diào)用哪個類的函數(shù)的效果,于是產(chǎn)生了虛函數(shù)的概念;
1> 虛函數(shù)的理解
2> 虛函數(shù)的使用 (配合父子兼容規(guī)則)
3> 虛析構(gòu)函數(shù)
4> 為什么要使用虛函數(shù)?
************************************************************************************************************************************
?
一:基本理解
什么是虛函數(shù)?
某基類中聲明為virtual并在一個或多個派生類中重新定義的成員函數(shù)叫做虛函數(shù);
虛函數(shù)有什么作用?
虛函數(shù)的作用是實現(xiàn)動態(tài)聯(lián)編,也就是在函數(shù)運行階段動態(tài)的選擇合適的成員函數(shù);
在定義了虛函數(shù)后,可以在派生類對虛函數(shù)進行重寫,從而實現(xiàn)統(tǒng)一的接口,不同的執(zhí)行過程。
在派生類中重寫虛函數(shù)的時候,要保持重寫的函數(shù)與原函數(shù)的一致性(包括返回值類型、參數(shù)個數(shù)與類型);
?
虛函數(shù)在定義的時候,基類結(jié)構(gòu)中增加了一個虛函數(shù)指針表virtual table,?該表存放虛函數(shù)的調(diào)用地址,大小由虛函數(shù)個數(shù)決定,該表的首地址由基類內(nèi)部指針vPtr指向。
?如果繼承類中存在同名的函數(shù),則替換虛函數(shù)指針表中的相應同名函數(shù),從而達到輸出本類中的同名函數(shù)的效果。
?
?
二:虛函數(shù)(舉例)
?1> 首先舉一個"父子兼容規(guī)則"的源碼示例
#include <iostream> using namespace std;class A { private:public:void Show() const{cout << "A0::Show" << endl;} };class A1 :public A { private:public:void Show() const{cout << "A1::Show" << endl;} }; class A2 :public A { private:public:void Show() const{cout << "A2::Show" << endl;} };void Func(A &a) {a.Show(); }int main() {A a;A1 a1;A2 a2;Func(a);Func(a1);Func(a2);return 0; }運行結(jié)果很明顯:
?
2> 接下來給出使用虛函數(shù)后的源碼以及運行結(jié)果:
源碼:
#include <iostream> using namespace std;class A { private:public:virtual void Show() const{cout << "A0::Show" << endl;} };class A1 :public A { private:public:void Show() const{cout << "A1::Show" << endl;} }; class A2 :public A { private:public:void Show() const{cout << "A2::Show" << endl;} };void Func(A &a) {a.Show(); }int main() {A a;A1 a1;A2 a2;Func(a);Func(a1);Func(a2);return 0; }<和上述代碼相比僅僅加了一個virtual,當然也可以每個同名函數(shù)前都可以添加virtual函數(shù),但是因為A1和A2是直接繼承于A的,虛函數(shù)指針表 (Virtual Table)是可以被繼承的,所以只要在基類中聲明即可;>
<如果派生類中繼續(xù)派生,則在派生類中和派生類的派生類中對派生類中的同名函數(shù)使用virtual即可>
運行結(jié)果:
* 當然也可以對供調(diào)用的全局函數(shù)傳入指針作為形參:
* 上面的操作似乎已經(jīng)完全ODK了,但是還有一個問題,就是"父子兼容規(guī)則"下析構(gòu)韓函數(shù)的調(diào)用問題:
?
?
三:虛析構(gòu)函數(shù)
1> 未使用虛析構(gòu)函數(shù):
#include <iostream> using namespace std;class A { public:~A(){cout << "A's destruct function!" << endl;} };class A1 :public A { public:~A1(){cout << "A1's destruct function!" << endl;} };void Func(A *a) {delete a; }int main() {A1 *a = new A1;Func(a);return 0; }?運行結(jié)果:?
?
2> 使用虛析構(gòu)函數(shù)
#include <iostream> using namespace std;class A { public:virtual ~A(){cout << "A's destruct function!" << endl;} };class A1 :public A { public:~A1(){cout << "A1's destruct function!" << endl;} };void Func(A *a) {delete a; }int main() {A1 *a = new A1;Func(a);return 0; }運行結(jié)果:
?
?
四:為什么要使用虛函數(shù)?
首先,如果想要顯示派生類中的與基類中同名的函數(shù),直接使用派生類實例化的對象直接調(diào)用不就可以了嗎?
像這樣:
但是,條條大路通羅馬,不同的解決方法會適用于不同的場景:
虛函數(shù)向我們提供了一種不使用實例化的對象通過“X.x()”的形式來顯示函數(shù)的方法(虛函數(shù)是通過直接把實例化的對象作為參數(shù)傳入一個單獨的<公有顯示函數(shù)>進行顯示)。
?
?
?
?
?
?
?
總結(jié)
- 上一篇: 第一次群面——华为败北的经历小结
- 下一篇: 开发者日志