有了虛函數(shù),基類指針可以按照基類的方式來做事,也可以按照派生類的方式來做事,它有多種形態(tài),或者說有多種表現(xiàn)方式,我們將這種現(xiàn)象稱為多態(tài)(Polymorphism)。使用虛函數(shù)非常簡(jiǎn)單,只需要在函數(shù)聲明前面增加 virtual 關(guān)鍵字。函數(shù)定義處可以加也可以不加。
通過指針調(diào)用普通的成員函數(shù)時(shí)會(huì)根據(jù)指針的類型(通過哪個(gè)類定義的指針)來判斷調(diào)用哪個(gè)類的成員函數(shù),這并不適用于虛函數(shù),虛函數(shù)是根據(jù)指針的指向來調(diào)用的,指針指向哪個(gè)類的對(duì)象就調(diào)用哪個(gè)類的虛函數(shù)。
只需要在虛函數(shù)的聲明處加上 virtual 關(guān)鍵字,函數(shù)定義處可以加也可以不加為了方便,可以只將基類中的函數(shù)聲明為虛函數(shù),這樣所有派生類中具有遮蔽關(guān)系的同名函數(shù)都將自動(dòng)成為虛函數(shù)。當(dāng)在基類中定義了虛函數(shù)時(shí),如果派生類沒有定義新的函數(shù)來遮蔽此函數(shù),那么將使用基類的虛函數(shù)。只有派生類的虛函數(shù)覆蓋基類的虛函數(shù)(函數(shù)原型相同)才能構(gòu)成多態(tài)(通過基類指針訪問派生類函數(shù))
構(gòu)造函數(shù)不能是虛函數(shù)。對(duì)于基類的構(gòu)造函數(shù),它僅僅是在派生類構(gòu)造函數(shù)中被調(diào)用,這種機(jī)制不同于繼承。也就是說,派生類不繼承基類的構(gòu)造函數(shù),將構(gòu)造函數(shù)聲明為虛函數(shù)沒有什么意義。析構(gòu)函數(shù)可以聲明為虛函數(shù),而且有時(shí)候必須要聲明為虛函數(shù)
5 . 構(gòu)成多態(tài)的條件
必須存在繼承關(guān)系
繼承關(guān)系中必須有同名的虛函數(shù),并且它們是覆蓋關(guān)系(函數(shù)原型相同)。
存在基類的指針,通過該指針調(diào)用虛函數(shù)
純虛函數(shù)沒有函數(shù)體,只有函數(shù)聲明,在虛函數(shù)聲明的結(jié)尾加上=0,表明此函數(shù)為純虛函數(shù)。=0并不表示函數(shù)返回值為0,它只起形式上的作用,告訴編譯系統(tǒng)“這是純虛函數(shù)”,包含純虛函數(shù)的類稱為抽象類(Abstract Class)之所以說它抽象,是因?yàn)樗鼰o法實(shí)例化,也就是無法創(chuàng)建對(duì)象。原因很明顯,純虛函數(shù)沒有函數(shù)體,不是完整的函數(shù),無法調(diào)用,也無法為其分配內(nèi)存空間。抽象類通常是作為基類,讓派生類去實(shí)現(xiàn)純虛函數(shù)。派生類必須實(shí)現(xiàn)純虛函數(shù)才能被實(shí)例化。
抽象基類除了約束派生類的功能,還可以實(shí)現(xiàn)多態(tài) 一個(gè)純虛函數(shù)就可以使類成為抽象基類,但是抽象基類中除了包含純虛函數(shù)外,還可以包含其它的成員函數(shù)(虛函數(shù)或普通函數(shù))和成員變量。只有類中的虛函數(shù)才能被聲明為純虛函數(shù),普通成員函數(shù)和頂層函數(shù)均不能聲明為純虛函數(shù)
typeid
typeid 的操作對(duì)象可以是普通變量、對(duì)象、內(nèi)置類型(int、float等)、自定義類型(結(jié)構(gòu)體和類),還可以是一個(gè)表達(dá)式
typeid 會(huì)把獲取到的類型信息保存到一個(gè) type_info 類型的對(duì)象里面,并返回該對(duì)象的常引用;當(dāng)需要具體的類型信息時(shí),可以通過成員函數(shù)來提取。
const type_info &nInfo = typeid(n)
3 type_info 類的幾個(gè)成員函數(shù)
name() 用來返回類型的名稱。
raw_name() 用來返回名字編碼(Name Mangling)算法產(chǎn)生的新名稱
hash_code() 用來返回當(dāng)前類型對(duì)應(yīng)的 hash 值
- C++ 標(biāo)準(zhǔn)規(guī)定,type_info 類至少要有如下所示的 4 個(gè) public 屬性的成員函數(shù),其他的擴(kuò)展函數(shù)編譯器開發(fā)者可以自由發(fā)揮,不做限制。
- 原型:const char* name() const;
返回一個(gè)能表示類型名稱的字符串。但是C++標(biāo)準(zhǔn)并沒有規(guī)定這個(gè)字符串是什么形式的,例如對(duì)于上面的objInfo.name()語(yǔ)句,VC/VS 下返回“class Base”,但 GCC 下返回“4Base”。- 原型:bool before (const type_info& rhs) const;
判斷一個(gè)類型是否位于另一個(gè)類型的前面,rhs 參數(shù)是一個(gè) type_info 對(duì)象的引用。但是C++標(biāo)準(zhǔn)并沒有規(guī)定類型的排列順序,不同的編譯器有不同的排列規(guī)則,程序員也可以自定義。要特別注意的是,這個(gè)排列順序和繼承順序沒有關(guān)系,基類并不一定位于派生類的前面。- 原型:bool operator== (const type_info& rhs) const;
重載運(yùn)算符“==”,判斷兩個(gè)類型是否相同,rhs 參數(shù)是一個(gè) type_info 對(duì)象的引用。- 原型:bool operator!= (const type_info& rhs) const;
重載運(yùn)算符“!=”,判斷兩個(gè)類型是否不同,rhs 參數(shù)是一個(gè) type_info 對(duì)象的引用。
- typeid 運(yùn)算符經(jīng)常被用來判斷兩個(gè)類型是否相等