Cpp 对象模型探索 / 继承关系下的虚函数手动调用
一、多態機理
#include <iostream>class Father { public:virtual void Func1(){std::cout << "Fahter::Func1()" << std::endl;}virtual void Func2(){std::cout << "Fahter::Func2()" << std::endl;}virtual void Func3(){std::cout << "Fahter::Func3()" << std::endl;}private:size_t count_; };class Son : public Father { public:virtual void Func2(){std::cout << "Son::Func2()" << std::endl;} };using FUNC = void (*)();int main() {Father *pfather = new Father;Son *pson = new Son;// 得到指向虛函數表指針的地址。long *pvptr_father = (long *)pfather;long *pvptr_son = (long *)pson;// 得到指向虛函數表的指針。 long *vptr_father = (long *)(*pvptr_father); long *vptr_son = (long *)(*pvptr_son); FUNC func1_father, func2_father, func3_father;func1_father = (FUNC) * (vptr_father + 0); // 得到虛函數 Father::Func1() 的地址。func2_father = (FUNC) * (vptr_father + 1); // 得到虛函數 Father::Func2() 的地址。func3_father = (FUNC) * (vptr_father + 2); // 得到虛函數 Father::Func2() 的地址。func1_father();func2_father();func3_father();std::cout << std::endl;FUNC func1_son, func2_son, func3_son;func1_son = (FUNC) * (vptr_son + 0); // 得到虛函數 Father::Func1() 的地址。func2_son = (FUNC) * (vptr_son + 1); // 得到虛函數 Son::Func2() 的地址。func3_son = (FUNC) * (vptr_son + 2); // 得到虛函數 Father::Func2() 的地址。func1_son();func2_son();func3_son();return 0; }結果:
Fahter::Func1() Fahter::Func2() Fahter::Func3()Fahter::Func1() Son::Func2() Fahter::Func3()二、分析
? ? ? ?上圖介紹了C++多態的實現機理。注意:虛函數表屬于類,虛函數表指針屬于對象。
? ? ? ?子類繼承父類時,會得到和父類相同的虛函數表,該表記載著代碼區中屬于該類的虛函數的起始地址。當子類沒有重寫虛函數時,程序調用子類的虛函數,就相當于調用父類的虛函數。當子類重寫了父類的虛函數時,相當于將子類的虛函數表中的相應虛函數的地址修改為子類虛函數的首地址,從而完成了多態!
三、對象切割
Son sn; Father fa = sn; fa.Func1(); fa.Func2(); fa.Func3();結果:
Fahter::Func1() Fahter::Func2() Fahter::Func3()? ? ? ?對于多態,使用指針或者引用,用父類調用子類的函數達到工廠模式的目的。倘若用子類直接賦值給父類,會有什么結果呢。上述代碼就展示了最后的結果,并沒有調用子類的函數,而是直接調用了父類的函數。
? ? ? ?原因是直接用子類給父類對象賦值,子類中的屬于父類部分內容會被編譯器自動切割出來并拷貝給了父類。
? ? ? ?實際上上述操作一共干了兩件事情,
? ? ? ?1、生成 Father 對象。
? ? ? ?2、用 sn 來初始化 Father 對象。顯然,編譯器并沒有將 sn 的虛函數表指針覆蓋掉 fa 的虛函數表指針。
四、總結
1、類只有包含了虛函數才存在虛函數表(只有一個),同屬于一個類的對象共享虛函數表,但是有各自的vptr(虛函數表指針)。
2、父類含有虛函數,子類就會有一個虛函數表,但是子類的虛函數表只是和父類的虛函數表中的內容相同,所在的內存位置不同。
3、多態是子類賦值給父類的指針或者引用。若直接對象賦值,是對象切割的范疇。
?
(SAW:Game Over!)
總結
以上是生活随笔為你收集整理的Cpp 对象模型探索 / 继承关系下的虚函数手动调用的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 数据结构与算法 / 排序算法(2)
- 下一篇: 数据结构与算法 / 排序算法(3)