欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

C++之多態(tài)(內(nèi)容不錯(cuò))

 更新時(shí)間:2020年01月30日 21:08:50   作者:熊二不二  
什么是多態(tài)?顧名思義就是同一個(gè)事物在不同場(chǎng)景下的多種形態(tài),需要的朋友可以參考下

編譯環(huán)境:WIN10 VS2017

這篇博客有點(diǎn)長(zhǎng),但都是滿滿的干貨,一定要看到最后,那才是重點(diǎn)。

什么是多態(tài)?

顧名思義就是同一個(gè)事物在不同場(chǎng)景下的多種形態(tài)。

這里寫圖片描述 

下面會(huì)具體的詳細(xì)的介紹。

靜態(tài)多態(tài)

我們以前說(shuō)過(guò)的函數(shù)重載就是一個(gè)簡(jiǎn)單的靜態(tài)多態(tài)

int Add(int left, int right)
{
 return left + right;
}
double Add(double left, int right)
{
 return left + right;
}

int main()
{
 Add(10, 20);
 //Add(10.0, 20.0); //這是一個(gè)問(wèn)題代碼
 Add(10.0,20); //正常代碼
 return 0;
}

這里寫圖片描述 

可以看出來(lái),靜態(tài)多態(tài)是編譯器在編譯期間完成的,編譯器會(huì)根據(jù)實(shí)參類型來(lái)選擇調(diào)用合適的函數(shù),如果有合適的函數(shù)可以調(diào)用就調(diào),沒(méi)有的話就會(huì)發(fā)出警告或者報(bào)錯(cuò)。。。比較簡(jiǎn)單,不做多介紹。

這里寫圖片描述

動(dòng)態(tài)多態(tài)

什么是動(dòng)態(tài)多態(tài)呢?
動(dòng)態(tài)多態(tài): 顯然這和靜態(tài)多態(tài)是一組反義詞,它是在程序運(yùn)行時(shí)根據(jù)基類的引用(指針)指向的對(duì)象來(lái)確定自己具體該調(diào)用哪一個(gè)類的虛函數(shù)。

我在西安臨潼上學(xué),我就以這邊的公交車舉個(gè)栗子?。?/p>

class TakeBus
{
public:
 void TakeBusToSubway()
 {
  cout << "go to Subway--->please take bus of 318" << endl;
 }
 void TakeBusToStation()
 {
  cout << "go to Station--->pelase Take Bus of 306 or 915" << endl;
 }
};
//知道了去哪要做什么車可不行,我們還得知道有沒(méi)有這個(gè)車
class Bus
{
public:
 virtual void TakeBusToSomewhere(TakeBus& tb) = 0; //???為什么要等于0
};

class Subway:public Bus
{
public:
 virtual void TakeBusToSomewhere(TakeBus& tb)
 {
  tb.TakeBusToSubway();
 }
};
class Station :public Bus
{
public:
 virtual void TakeBusToSomewhere(TakeBus& tb)
 {
  tb.TakeBusToStation();
 }
};

int main()
{
 TakeBus tb;
 Bus* b = NULL;
 //假設(shè)有十輛公交車,如果是奇數(shù)就是去地鐵口的,反之就是去火車站的
 for (int i = 1; i <= 10; ++i)
 {
  if ((rand() % i) & 1)
   b = new Subway;
  else
   b = new Station;
 }
 b->TakeBusToSomewhere(tb);
 delete b;
 return 0;
}

這就是一個(gè)簡(jiǎn)單的動(dòng)態(tài)多態(tài)的例子,它是在程序運(yùn)行時(shí)根據(jù)條件去選擇調(diào)用哪一個(gè)函數(shù)。
而且,從上面的例子我們還發(fā)現(xiàn)了我在每一個(gè)函數(shù)前都加了virtual這個(gè)虛擬關(guān)鍵字,想想為什么?如果不加會(huì)不會(huì)構(gòu)成多態(tài)呢?
干想不如上機(jī)實(shí)踐:

class Base
{
public:
 virtual void Funtest1(int i)
 {
  cout << "Base::Funtest1()" << endl;
 }
 void Funtest2(int i)
 {
  cout << "Base::Funtest2()" << endl;
 }
};
class Drived :public Base
{
 virtual void Funtest1(int i)
 {
  cout << "Drived::Fubtest1()" << endl;
 }
 virtual void Funtest2(int i)
 {
  cout << "Drived::Fubtest2()" << endl;
 }
 void Funtest2(int i)
 {
  cout << "Drived::Fubtest2()" << endl;
 }
};
void TestVirtual(Base& b)
{
 b.Funtest1(1);
 b.Funtest2(2);
}
int main()
{
 Base b;
 Drived d;
 TestVirtual(b);
 TestVirtual(d);
 return 0;
}

這里寫圖片描述 

在調(diào)用FuncTest2的時(shí)候我們看出來(lái)他并沒(méi)有給我們調(diào)用派生類的函數(shù),因此我們可以對(duì)動(dòng)態(tài)多態(tài)的實(shí)現(xiàn)做個(gè)總結(jié)。

動(dòng)態(tài)多態(tài)的條件:

●基類中必須包含虛函數(shù),并且派生類中一定要對(duì)基類中的虛函數(shù)進(jìn)行重寫。
●通過(guò)基類對(duì)象的指針或者引用調(diào)用虛函數(shù)。

重寫 :

(a)基類中將被重寫的函數(shù)必須為虛函數(shù)(上面的檢測(cè)用例已經(jīng)證實(shí)過(guò)了)
(b)基類和派生類中虛函數(shù)的原型必須保持一致(返回值類型,函數(shù)名稱以及參數(shù)列表),協(xié)變和析構(gòu)函數(shù)(基類和派生類的析構(gòu)函數(shù)是不一樣的)除外
(c)訪問(wèn)限定符可以不同
那么問(wèn)題又來(lái)了,什么是協(xié)變?
協(xié)變:基類(或者派生類)的虛函數(shù)返回基類(派生類)的指針(引用)
總結(jié)一道面試題:那些函數(shù)不能定義為虛函數(shù)?
經(jīng)檢驗(yàn)下面的幾個(gè)函數(shù)都不能定義為虛函數(shù):
1)友元函數(shù),它不是類的成員函數(shù)
2)全局函數(shù)
3)靜態(tài)成員函數(shù),它沒(méi)有this指針
3)構(gòu)造函數(shù),拷貝構(gòu)造函數(shù),以及賦值運(yùn)算符重載(可以但是一般不建議作為虛函數(shù))

抽象類:

在前面公交車的例子上我提了一個(gè)問(wèn)題:

class Bus
{
public:
 virtual void TakeBusToSomewhere(TakeBus& tb) = 0; //???為什么要等于0
};

在成員函數(shù)(必須為虛函數(shù))的形參列表后面寫上=0,則成員函數(shù)為純虛函數(shù)。包含純虛函數(shù)的類叫做抽象類(也叫接口類),抽象類不能實(shí)例化出對(duì)象。純虛函數(shù)在派生類中重新定義以后,派生類才能實(shí)例化出對(duì)象。純虛函數(shù)是一定要被繼承的,否則它存在沒(méi)有任何意義。

這里寫圖片描述

多態(tài)調(diào)用原理

class Base
{
public:
 virtual void Funtest1(int i)
 {
  cout << "Base::Funtest1()" << endl;
 }
 virtual void Funtest2(int i)
 {
  cout << "Base::Funtest2()" << endl;
 }
 int _data;
};

int main()
{
 cout << sizeof(Base) << endl;
 Base b;
 b._data = 10;
 return 0;
}

這里寫圖片描述 

8?不知道大家有沒(méi)有問(wèn)題,反正我是有疑惑了。以前在對(duì)象模型(https://blog.csdn.net/qq_39412582/article/details/80808754)時(shí)我提到過(guò)怎么來(lái)求一個(gè)類的大小。按照那個(gè)方法,這里應(yīng)該是4才對(duì)啊,為什么會(huì)是8呢?

通過(guò)觀察。我們發(fā)現(xiàn)這個(gè)例子里面和以前不一樣,類成員函數(shù)變成了虛函數(shù),這是不是引起類大小變化的原因呢?
我們假設(shè)就是這樣,然后看看內(nèi)存里是怎么存儲(chǔ)的呢?

這里寫圖片描述 

可以看到它在內(nèi)存里多了四個(gè)字節(jié),那這四個(gè)字節(jié)的內(nèi)容到底是什么呢?

這里寫圖片描述

是不是有點(diǎn)看不懂,我們假設(shè)它是一個(gè)地址去看地址里存的東西的時(shí)候發(fā)現(xiàn)它存的是兩個(gè)地址。
我假設(shè)它是虛函數(shù)的地址,我們來(lái)驗(yàn)證一下:

typedef void (__stdcall *PVFT)(); //函數(shù)指針
int main()
{
 cout << sizeof(Base) << endl;
 Base b;
 b._data = 10;
 PVFT* pVFT = (PVFT*)(*((int*)&b));
 while (*pVFT)
 {
  (*pVFT)();
  pVFT+=1;
 }
 return 0;
}

這里寫圖片描述 

結(jié)果好像和我們的猜想一樣,是一件開心的事。然后我給一張圖總結(jié)一下:

這里寫圖片描述 

在反匯編中我們還可以看到,如果含有虛函數(shù)的類中沒(méi)有定義構(gòu)造函數(shù),編譯器會(huì)自動(dòng)合成一個(gè)構(gòu)造函數(shù)

這里寫圖片描述

這里寫圖片描述

對(duì)于派生類的東西我給個(gè)鏈接仔細(xì)看,人家總結(jié)的超級(jí)贊,我偷個(gè)懶就不寫了,老鐵們包容下啊。

派生類虛表:

1.先將基類的虛表中的內(nèi)容拷貝一份
2.如果派生類對(duì)基類中的虛函數(shù)進(jìn)行重寫,使用派生類的虛函數(shù)替換相同偏移量位置的基類虛函數(shù)
3.如果派生類中新增加自己的虛函數(shù),按照其在派生類中的聲明次序,放在上述虛函數(shù)之后

https://coolshell.cn/articles/12176.html

多態(tài)缺陷

●降低了程序運(yùn)行效率(多態(tài)需要去找虛表的地址)
●空間浪費(fèi)

相關(guān)文章

  • 詳解C語(yǔ)言數(shù)組靈活多變的訪問(wèn)形式

    詳解C語(yǔ)言數(shù)組靈活多變的訪問(wèn)形式

    這篇文章主要介紹了詳解C語(yǔ)言數(shù)組靈活多變的訪問(wèn)形式,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2021-01-01
  • 關(guān)于C/C++中可變參數(shù)的詳細(xì)介紹(va_list,va_start,va_arg,va_end)

    關(guān)于C/C++中可變參數(shù)的詳細(xì)介紹(va_list,va_start,va_arg,va_end)

    可變參數(shù)的函數(shù)原理其實(shí)很簡(jiǎn)單,而va系列是以宏定義來(lái)定義的,實(shí)現(xiàn)跟堆棧相關(guān).我們寫一個(gè)可變函數(shù)的C函數(shù)時(shí),有利也有弊,所以在不必要的場(chǎng)合,我們無(wú)需用到可變參數(shù)。如果在C++里,我們應(yīng)該利用C++的多態(tài)性來(lái)實(shí)現(xiàn)可變參數(shù)的功能,盡量避免用C語(yǔ)言的方式來(lái)實(shí)現(xiàn)
    2013-10-10
  • 用C語(yǔ)言的泛型實(shí)現(xiàn)交換兩個(gè)變量值

    用C語(yǔ)言的泛型實(shí)現(xiàn)交換兩個(gè)變量值

    在日常編程里面經(jīng)常會(huì)遇到交換兩個(gè)變量的內(nèi)容的任務(wù),對(duì)于泛型類型而言有兩種泛型策略來(lái)實(shí)現(xiàn),下面跟著小編一起來(lái)學(xué)習(xí)學(xué)習(xí)。
    2016-08-08
  • c++動(dòng)態(tài)庫(kù)調(diào)用的實(shí)現(xiàn)

    c++動(dòng)態(tài)庫(kù)調(diào)用的實(shí)現(xiàn)

    本文主要介紹了c++動(dòng)態(tài)庫(kù)調(diào)用的實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2022-07-07
  • c語(yǔ)言結(jié)構(gòu)體字節(jié)對(duì)齊的實(shí)現(xiàn)方法

    c語(yǔ)言結(jié)構(gòu)體字節(jié)對(duì)齊的實(shí)現(xiàn)方法

    在c語(yǔ)言的結(jié)構(gòu)體里面一般會(huì)按照某種規(guī)則去進(jìn)行字節(jié)對(duì)齊。本文就來(lái)介紹一下如何實(shí)現(xiàn),具有一定的參考價(jià)值,感興趣的可以了解下
    2021-07-07
  • C++ 系統(tǒng)String類詳解

    C++ 系統(tǒng)String類詳解

    這篇文章主要介紹了C++的系統(tǒng)String類,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2021-11-11
  • C/C++編寫推箱子小游戲

    C/C++編寫推箱子小游戲

    這篇文章主要為大家詳細(xì)介紹了C/C++編寫推箱子小游戲,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2021-06-06
  • C語(yǔ)言中的運(yùn)算符和結(jié)合性問(wèn)題

    C語(yǔ)言中的運(yùn)算符和結(jié)合性問(wèn)題

    這篇文章主要介紹了C語(yǔ)言中的運(yùn)算符和結(jié)合性問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-03-03
  • C++實(shí)現(xiàn)LeetCode(199.二叉樹的右側(cè)視圖)

    C++實(shí)現(xiàn)LeetCode(199.二叉樹的右側(cè)視圖)

    這篇文章主要介紹了C++實(shí)現(xiàn)LeetCode(199.二叉樹的右側(cè)視圖),本篇文章通過(guò)簡(jiǎn)要的案例,講解了該項(xiàng)技術(shù)的了解與使用,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下
    2021-08-08
  • 一文秒懂C語(yǔ)言/C++內(nèi)存管理(推薦)

    一文秒懂C語(yǔ)言/C++內(nèi)存管理(推薦)

    在C++中,內(nèi)存分為:棧、堆、自由存儲(chǔ)區(qū)、全局/靜態(tài)存儲(chǔ)區(qū)、常量存儲(chǔ)區(qū)。這篇文章主要介紹了一文秒懂C語(yǔ)言/C++內(nèi)存管理,需要的朋友可以參考下
    2020-11-11

最新評(píng)論