Cpp 对象模型探索 / 静态联编和动态联编
一、源碼
#include <iostream>class Father { public:Father(){/*** 該處直接將該對(duì)象清零,意味著虛函數(shù)表指針亦被清零。*/memset(this, 0, sizeof(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;} };int main() {Father father;father.Func1();father.Func2();father.Func3();Father* pfather = new Father();/*** 此處開始崩潰,因?yàn)樘摵瘮?shù)表指針已經(jīng)被清零。*/pfather->Func1();pfather->Func2();pfather->Func3();return 0; }結(jié)果
二、分析
問題,為什么含有虛函數(shù)的類,若是直接申請(qǐng)為實(shí)例對(duì)象,可以調(diào)用虛函數(shù),但是通過指針 new 出的實(shí)例卻崩潰呢?
原因,這里有個(gè)靜態(tài)聯(lián)編和動(dòng)態(tài)聯(lián)編的概念。
? ? ? ?靜態(tài)聯(lián)編的意思是在編譯期間就能確定調(diào)用的函數(shù)的地址,即:call (地址),地址是確定的值。
? ? ? ?動(dòng)態(tài)聯(lián)編的意思是在運(yùn)行期間才能確定調(diào)用的函數(shù)的地址。方法是通過對(duì)象的虛函數(shù)表指針找到虛函數(shù)表,再通過虛函數(shù)表找到虛函數(shù),這也是多態(tài)的實(shí)現(xiàn)機(jī)理。而多態(tài)的實(shí)現(xiàn),只針對(duì)指針或者引用。
? ? ? ?上述代碼中,因?yàn)閷?duì)象“father”不是指針或者引用,所以盡管存在虛函數(shù),但是這些虛函數(shù)在不用在多態(tài)的情況下,其功能和普通函數(shù)是一樣的,所以編譯器直接將其按照靜態(tài)編譯來處理。
? ? ? ?針對(duì)上述代碼中的"pfather",因?yàn)槭?new 出的對(duì)象,所以編譯器要考慮下面多態(tài)的可能性,所以調(diào)用虛函數(shù)是按照動(dòng)態(tài)聯(lián)編的調(diào)用順序來調(diào)用的,即:虛函數(shù)表指針 --> 虛函數(shù)表 --> 虛函數(shù) 。但是,問題出在了“Father”類的構(gòu)造函數(shù)中,因?yàn)樵摌?gòu)造函數(shù)初始化對(duì)象的方法是直接將整個(gè)對(duì)象都初始化為0,這里面也包括虛函數(shù)表指針,所以,走多態(tài)的路來調(diào)用虛函數(shù)直接 Over 了。。所以上述通過 pfather 調(diào)用虛函數(shù)的方法就產(chǎn)生了崩潰。
?
(SAW:Game Over!)
總結(jié)
以上是生活随笔為你收集整理的Cpp 对象模型探索 / 静态联编和动态联编的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Cpp 对象模型探索 / 虚函数表和虚函
- 下一篇: Cpp 对象模型探索 / new 对象时