C++虛函數(shù)和多態(tài)超詳細(xì)分析
1.什么是虛函數(shù)
C++類中用virtual
修飾的函數(shù)叫做虛函數(shù),構(gòu)造函數(shù)沒(méi)有虛構(gòu)造函數(shù),存在虛析構(gòu)函數(shù),C++所有虛函數(shù)都是一個(gè)指針去存儲(chǔ)的,所以具有虛函數(shù)的類,內(nèi)存會(huì)增加一個(gè)指針大小的內(nèi)存
#include<iostream> #include<string> using namespace std; class MM { public: //虛函數(shù)指針是同一個(gè),所以無(wú)論該類中有多少個(gè)虛函數(shù), //占用的內(nèi)存就只是一個(gè)指針的大小 virtual void print() { cout << "我是第一個(gè)虛函數(shù)" << endl; } virtual void printData() { cout << "我是第二個(gè)虛函數(shù)" << endl; } protected: }; class son:public MM { public: void print() { //該函數(shù)也是虛函數(shù), //父類中同名函數(shù)是虛函數(shù) //所以子類該函數(shù)也是虛函數(shù) } protected: }; int main() { cout << sizeof(MM) << endl; cout << "...................." << endl; //虛函數(shù)表的理解,下面帶圖解 MM mm; long long** p = (long long**)&mm; using Func = void(*)(); Func f1 = (Func)p[0][0]; Func f2 = (Func)p[0][1]; f1(); f2(); return 0; }
2.純虛函數(shù)
純虛函數(shù)也是虛函數(shù)的一種,只是沒(méi)有函數(shù)體,下面請(qǐng)看怎么表示沒(méi)有函數(shù)體
純虛函數(shù)——>虛函數(shù)=0;
具有一個(gè)或者多個(gè)虛函數(shù)的類叫做抽象類
- 抽象類不能構(gòu)建對(duì)象
- 但是可以構(gòu)建函數(shù)指針
#include<iostream> using namespace std; class MM { public: virtual void print() = 0; }; int main() { //MM mm; //抽象類不能構(gòu)建對(duì)象 MM* pmm = nullptr; return 0; }
3.c++多態(tài)
多態(tài)指的是因?yàn)橹羔樀牟煌馁x值操作所導(dǎo)致的同一行為的不同結(jié)果。多態(tài)的這個(gè)概念東西不太重要,重要的是什么樣的情況調(diào)用什么樣的行為
- 正常指針和正常對(duì)象調(diào)用行為,就近原則
- 父類指針被子類對(duì)象初始化
- 函數(shù)有
virtual
看對(duì)象類型 - 函數(shù)沒(méi)有
virtual
看指針類型 final
關(guān)鍵字 禁止子類重寫父類方法override
顯示說(shuō)明當(dāng)前函數(shù)是重寫函數(shù)
多態(tài)三個(gè)必要性條件:
- 父類中存在虛函數(shù)
- 存在不正常指針的引用(不正常賦值關(guān)系)
public
繼承
#include<iostream> using namespace std; class MM { public: void print() { cout << "父類" << endl; } virtual void printData() { cout << "MM" << endl; } }; class son :public MM { public: void print() { cout << "子類" << endl; } void printData() { cout << "son" << endl; } }; int main() { MM* pmm = new son; pmm->print(); pmm->printData(); return 0; }
4.純虛函數(shù)和ADT過(guò)程
ADT:abstract data type
抽象數(shù)據(jù)類型,主要是通過(guò)繼承抽象類中,子類必須要實(shí)現(xiàn)父類的抽象方法,子類才可以創(chuàng)建對(duì)象。
#include<iostream> #include<string> using namespace std; class data { public: string name; int age; }; class MM { public: virtual bool empty() = 0; virtual int size() = 0; }; class List:public MM { public: bool empty() { return 0; } int size() { return NULL; } }; int main() { MM* pmm = new List; pmm->empty(); pmm->size(); }
5.虛析構(gòu)函數(shù)
virtual
修飾的析構(gòu)函數(shù)就是虛析構(gòu)函數(shù),當(dāng)存在子類對(duì)象初始化父類指針的時(shí)候,父類析構(gòu)函數(shù)就要是虛析構(gòu)函數(shù),否則只會(huì)釋放父類,存在內(nèi)存泄漏問(wèn)題
#include<iostream> using namespace std; class MM { public: virtual ~MM() { cout << "父類" << endl; } }; class son:public MM { public: ~son() { cout << "子類" << endl; } }; int main() { MM* pmm = new son; delete pmm; return 0; }
6.dynamic_cast類型轉(zhuǎn)換
- 上行轉(zhuǎn)換 子類到父類 和
staic_cast
差不多 - 下行轉(zhuǎn)換 父類到子類
dynamic_cast
更為安全 - 交叉轉(zhuǎn)換 多繼承
#include<iostream> using namespace std; class MM { public: virtual void print() { cout << "MM" << endl; } }; class son:public MM { public: void print() { cout << "son" << endl; } }; class A { public: virtual void print(){} }; class B { public: virtual void print() {} }; class C:public A,public B { public: void print() { cout << "c" << endl; } }; int main() { MM* partent = new MM; son* Son = new son; //上行轉(zhuǎn)換----->沒(méi)有必要 MM* p = static_cast<MM*>(Son); MM* pp = dynamic_cast<MM*>(Son); MM* ppp = Son; //可以 //下行轉(zhuǎn)換 son* x = dynamic_cast<son*>(partent); //安全,父類沒(méi)有virtual會(huì)報(bào)錯(cuò)---->多態(tài) if(!x) { printf("error"); } //下行轉(zhuǎn)換不安全,不會(huì)申請(qǐng)成功 A* a = new A; B* b = dynamic_cast<B*>(a); b->print(); return 0; }
7.成員函數(shù)指針
#include<iostream> #include<functional> using namespace std; class MM { public: void print() { cout << "king" << endl; } static void printData() { cout << "MM" << endl; } }; int main() { void(*p)() = &MM::printData; p(); //必須通過(guò)對(duì)象調(diào)用 void(MM::*pp)() = &MM::print; MM mm; (mm.*pp)(); //函數(shù)適配器,讓函數(shù)調(diào)用形態(tài)可以適用于別的形態(tài) auto f = bind(&MM::print, &mm); f(); return 0; }
到此這篇關(guān)于C++虛函數(shù)和多態(tài)超詳細(xì)分析的文章就介紹到這了,更多相關(guān)C++虛函數(shù)和多態(tài)內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Visual Studio 2022無(wú)法打開源文件的解決方式
這篇文章主要介紹了Visual Studio 2022無(wú)法打開源文件的解決方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-01-01數(shù)據(jù)結(jié)構(gòu)之帶頭結(jié)點(diǎn)的單鏈表
單鏈表是一種鏈?zhǔn)酱嫒〉臄?shù)據(jù)結(jié)構(gòu),用一組地址任意的存儲(chǔ)單元存放線性表中的數(shù)據(jù)元素。鏈表中的數(shù)據(jù)是以結(jié)點(diǎn)來(lái)表示的,每個(gè)結(jié)點(diǎn)的構(gòu)成:數(shù)據(jù)域(數(shù)據(jù)元素的映象)?+?指針域(指示后繼元素存儲(chǔ)位置),元素就是存儲(chǔ)數(shù)據(jù)的存儲(chǔ)單元,指針就是連接每個(gè)結(jié)點(diǎn)的地址數(shù)據(jù)2023-07-07C++實(shí)現(xiàn)動(dòng)態(tài)線性表
這篇文章主要為大家詳細(xì)介紹了C++實(shí)現(xiàn)動(dòng)態(tài)線性表,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2020-05-05Qt編寫地圖實(shí)現(xiàn)實(shí)時(shí)動(dòng)態(tài)軌跡效果
實(shí)時(shí)動(dòng)態(tài)軌跡主要是需要在地圖上動(dòng)態(tài)顯示GPS的運(yùn)動(dòng)軌跡,也是編寫地圖時(shí)一個(gè)重要的功能。本文將利用Qt實(shí)現(xiàn)這一功能,需要的可以參考一下2022-02-02C++語(yǔ)法中的函數(shù)重載和默認(rèn)參數(shù)
這篇文章主要介紹了C++語(yǔ)法中的函數(shù)重載和默認(rèn)參數(shù),本文從語(yǔ)法角度通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-03-03C語(yǔ)言?超詳細(xì)模擬實(shí)現(xiàn)單鏈表的基本操作建議收藏
單鏈表是后面要學(xué)的雙鏈表以及循環(huán)鏈表的基礎(chǔ),要想繼續(xù)深入了解數(shù)據(jù)結(jié)構(gòu)以及C語(yǔ)言,我們就要奠定好這塊基石!接下來(lái)就和我一起學(xué)習(xí)吧2022-03-03