C++核心——多態(tài)
多態(tài)的基本概念
多態(tài)是C++面向?qū)ο笕筇匦灾?,是利用繼承語法實現(xiàn)的一種編程思想,簡稱調(diào)父用子,調(diào)用父類的函數(shù),實際調(diào)用的是子類的實現(xiàn)
多態(tài)分為兩類
- 靜態(tài)多態(tài): 函數(shù)重載 和 運算符重載屬于靜態(tài)多態(tài),復(fù)用函數(shù)名
- 動態(tài)多態(tài): 派生類和虛函數(shù)實現(xiàn)運行時多態(tài)
靜態(tài)多態(tài)和動態(tài)多態(tài)區(qū)別:
- 靜態(tài)多態(tài)的函數(shù)地址早綁定 - 編譯階段確定函數(shù)地址
- 動態(tài)多態(tài)的函數(shù)地址晚綁定 - 運行階段確定函數(shù)地址
class Animal
{
public:
void speak()
{
cout << "動物在說話" << endl;
}
};
class Cat :public Animal
{
public:
void speak()
{
cout << "小貓在說話" << endl;
}
};
class Dog :public Animal
{
public:
void speak()
{
cout << "小狗在說話" << endl;
}
};
void DoSpeak(Animal &animal)
{
animal.speak();
}
void test01()
{
Cat cat;
DoSpeak(cat);
Dog dog;
DoSpeak(dog);
}
int main() {
test01();
system("pause");
return 0;
}
*********************************************************
(base) BigfishdeMacBook-Pro:學(xué)習(xí)筆記 bigfish$ g++ 02_多態(tài).cpp
(base) BigfishdeMacBook-Pro:學(xué)習(xí)筆記 bigfish$ ./a.out
動物在說話
動物在說話
(base) BigfishdeMacBook-Pro:學(xué)習(xí)筆記 bigfish$
DoSpeak函數(shù)中的參數(shù)是Animal類型,而我的參數(shù)穿的確實貓和狗,不用類型轉(zhuǎn)換直接就可以用,說明兩者可以進(jìn)行類型轉(zhuǎn)換。但是我們本意想的是調(diào)用貓和狗說話的函數(shù),可是依舊調(diào)用Animal的函數(shù),這是因為在程序編譯階段,就已經(jīng)把這個函數(shù)地址綁定在了Animal類的函數(shù)上面了,每次調(diào)用就直接調(diào)用Animal的函數(shù)。其實也很好理解,因為你傳進(jìn)來的參數(shù)類型就是Animal類型。那么如何實現(xiàn)我們想要的效果呢,這個時候就需要虛函數(shù)這個概念,剛接觸的朋友們記住必須得這么用就好了。
虛函數(shù)
虛函數(shù)就是在函數(shù)前加上virtual關(guān)鍵字來形容,使得該函數(shù)在編譯階段不會綁定地址,而是在運行階段根據(jù)傳入的參數(shù)的類型自動綁定地址。那么上面的例子可以做如下改造:
class Animal
{
public:
virtual void speak()
{
cout << "動物在說話" << endl;
}
};
在Animal的speak函數(shù)前加上virtual關(guān)鍵字后再運行,結(jié)果就是我們想好的:
(base) BigfishdeMacBook-Pro:學(xué)習(xí)筆記 bigfish$ g++ 02_多態(tài).cpp
(base) BigfishdeMacBook-Pro:學(xué)習(xí)筆記 bigfish$ ./a.out
小貓在說話
小狗在說話
(base) BigfishdeMacBook-Pro:學(xué)習(xí)筆記 bigfish$
這樣我們就成功實現(xiàn)了多態(tài),即實現(xiàn)了調(diào)父用子。
多態(tài)滿足條件
- 有繼承關(guān)系
- 子類重寫父類中的虛函數(shù)
純虛函數(shù)
純虛函數(shù)語法:virtual 返回值類型 函數(shù)名 (參數(shù)列表)= 0 ;
上面Animal的speak函數(shù)雖然定義了函數(shù)體,可是并沒有調(diào)用,顯得有些多余,而且我們的本意也并不需要這個函數(shù)干具體的事情,所以這個函數(shù)體就沒有必要存在,C++給出了另一個解決方案,就是純虛函數(shù),格式如下:
class Animal
{
public:
virtual void speak() = 0;
virtual ~Anmial()
{}
};
利用這種格式,那么speak就稱為純虛函數(shù),這是這個類就叫做抽象類,這個類無法實例化對象,而且基類必須有虛析構(gòu)函數(shù),這個具體可以參考另一篇博文《C++核心——多態(tài)里的構(gòu)造和析構(gòu)函數(shù)》。當(dāng)然繼承這個類的子類必須重寫純虛構(gòu)函數(shù),不然子類也是抽象了無法實例化對象。