定義一個(gè)虛基類ISpeaker
創(chuàng)新互聯(lián)建站為企業(yè)提供:品牌網(wǎng)站建設(shè)、網(wǎng)絡(luò)營銷策劃、小程序定制開發(fā)、營銷型網(wǎng)站建設(shè)和網(wǎng)站運(yùn)營托管,一站式網(wǎng)絡(luò)營銷整體服務(wù)。實(shí)現(xiàn)不斷獲取潛在客戶之核心目標(biāo),建立了企業(yè)專屬的“營銷型網(wǎng)站建設(shè)”,就用不著再為了獲取潛在客戶而苦惱,相反,客戶會(huì)主動(dòng)找您,生意就找上門來了!class ISpeaker{
protected:
size_t b;
public:
ISpeaker( size_t _v )
: b(_v)
{}
virtual void speak() = 0;
};
有兩個(gè)子類,都實(shí)現(xiàn)了虛函數(shù)speak():
class Dog : public ISpeaker {
public:
Dog()
: ISpeaker(0)
{}
//
virtual void speak() override {
printf("woof! %llu\n", b);
}
};
class Human : public ISpeaker {
private:
size_t c;
public:
Human()
: ISpeaker(1)
, c(2)
{}
virtual void speak() override {
printf("hello! %llu\n", c);
}
};
main方法中把Dog*和Human*類型的指針,退化(強(qiáng)轉(zhuǎn))成ISpeaker*指針,并調(diào)用speak()方法:
int main( int argc, char** _argv ) {Human* pHuman = new Human();
Dog* pDog = new Dog();
//
ISpeaker* speaker1 = (ISpeaker*)pHuman;
ISpeaker* speaker2 = (ISpeaker*)pDog;
//
speaker2->speak();
speaker1->speak();
//
return 0;
}
輸出:
woof! 0
hello! 2
同樣類型的指針(都是ISpeaker*),其函數(shù)表現(xiàn)出不同的行為(輸出不同),稱為多態(tài)
編譯器如何實(shí)現(xiàn)多態(tài)以MSVC編譯器為例
編譯器處理虛類ISpeaker時(shí),生成內(nèi)存模型(結(jié)構(gòu)體)__ispeaker,其成員有虛表指針SpeakerTable* vt
。
Dog繼承ISpeaker,所以對(duì)應(yīng)的虛表類__dog會(huì)包含__ispeaker中的成員;
Human繼承ISpeaker,所以對(duì)應(yīng)的虛表類__human會(huì)包含__ispeaker中的所有數(shù)據(jù),此外還有自己的數(shù)據(jù)size_t c
而后,編譯器為每個(gè)類生成唯一的虛表實(shí)例
__dogSpeakerTable和__humanSpeakerTable是虛表實(shí)例
虛表實(shí)例中的函數(shù)指針指向?qū)?yīng)的函數(shù)
所以Dog和Human,對(duì)應(yīng)的虛表實(shí)例 中的函數(shù)指針指向的函數(shù)
不同。
這就是為什么speaker2->speak();
和speaker1->speak();
的輸出不同。
在內(nèi)存中,__dog和__humen的布局如下:
struct __dog {
const SpeakerTable* vt;
size_t b;
};
struct __human {
const SpeakerTable* vt;
size_t b;
size_t c;
};
因此,想訪問b或者c成員時(shí),是按虛表對(duì)象之后的偏移量來訪問的。
調(diào)用__dog_speak和__human_speak時(shí)會(huì)傳遞對(duì)象__dog和__human作為參數(shù):
int main( int _argc, char** _argv ) {
__dog* dog = createDog();
__human* human = createHuman();
//
__ispeaker* speaker1 = (__ispeaker*)dog;
__ispeaker* speaker2 = (__ispeaker*)human;
//
speaker1->vt->speak(speaker1);
speaker2->vt->speak(speaker2);
return 0;
}
訪問b或c對(duì)象時(shí),基于偏移量:
void __dog_speak( void* _ptr ) {uint8_t* p = (uint8_t*)_ptr;
p+=sizeof(SpeakerTable*);
size_t b = *((size_t*)p);
printf("woof! %llu\n", b);
}
void __human_speak( void* _ptr ) {uint8_t* p = (uint8_t*)_ptr;
p+=sizeof(SpeakerTable*);
p+=sizeof(size_t);
size_t b = *((size_t*)p);
printf("hello! %llu\n", b);
}
例如uint8_t* p = (uint8_t*)_ptr;
拿到__dog對(duì)象的起始偏移,p+=sizeof(SpeakerTable*);
是越過虛表對(duì)象,size_t b = *((size_t*)p);
就找到b對(duì)象了。
參考:
http://showlinkroom.me/2017/08/21/C-%E9%80%86%E5%90%91%E5%88%86%E6%9E%90/
https://www.bilibili.com/video/BV15g4y1a7F3/?spm_id_from=333.337.search-card.all.click&vd_source=0fcfb2f2f346ba4bccf7f3ee3eb4ae69
你是否還在尋找穩(wěn)定的海外服務(wù)器提供商?創(chuàng)新互聯(lián)www.cdcxhl.cn海外機(jī)房具備T級(jí)流量清洗系統(tǒng)配攻擊溯源,準(zhǔn)確流量調(diào)度確保服務(wù)器高可用性,企業(yè)級(jí)服務(wù)器適合批量采購,新人活動(dòng)首月15元起,快前往官網(wǎng)查看詳情吧