純Swift類的函數(shù)調(diào)用原理,類似于C++的虛函數(shù)表
- 純Swift類的函數(shù)調(diào)用,類似于C++的虛函數(shù)表,是編譯時(shí)決議的。所以專門了解一下vtable還是有必要的。
- 一個(gè)含有虛函數(shù)的類,在創(chuàng)建對(duì)象時(shí)會(huì)額外增加一張?zhí)摫韛table,表中每一項(xiàng)記錄了虛函數(shù)的入口地址,編譯時(shí)對(duì)象會(huì)增加一個(gè)虛指針vpt(四個(gè)字節(jié)),指向虛函數(shù)表的起始位置,將對(duì)象和表關(guān)聯(lián)起來(lái)。
2.下面舉個(gè)栗子,含有虛函數(shù)的單繼承多層次的類關(guān)系:
using namespace std;
class A {
protected:
int a1;
int a2;
public:
virtual void display() { std::cout<<"A:dis() \n"; }
virtual void clone() { std::cout<<"A:clone()"; }
};
class B: public A {
protected:
int b;
public:
virtual void display() { std::cout<<"B:dis() \n"; }
virtual void init() { cout<<"B:init()"; }
};
class C: public B {
protected:
int c;
public:
virtual void display() { std::cout<<"C:dis() \n";
A::display(); }
virtual void execute() { cout<<"C:execute"<<this->a1<<"\n"; }
};
int main(int argc, const char * argv[]) {
C *p = new C();
p->display();
p->execute();
return 0;
}

類和虛表關(guān)系圖.png
- 從上圖可以知道,對(duì)于單繼承,無(wú)論繼承層次多深,都只是增加一個(gè)指針;基類中的虛函數(shù)在vtable中的索引是固定的,不會(huì)隨著繼承層次的增加而改變。例如,display()的索引值始終是0.
- 當(dāng)調(diào)用函數(shù)時(shí),利用指針vfptr間接轉(zhuǎn)換,可得到虛函數(shù)的入口地址:
比如,調(diào)用p->display()
在編譯器內(nèi)進(jìn)行轉(zhuǎn)換,變成:((p->vptr)[0])(p);
其中,0是display()在vtable的索引值,(p->vptr)[0]是它的入口地址。
所以調(diào)用對(duì)象的不同虛函數(shù),其實(shí)是訪問(wèn)虛函數(shù)表,通過(guò)改變不同的索引值,從而訪問(wèn)到函數(shù)的入口地址。