C 虛函式表

2021-05-28 12:06:38 字數 1814 閱讀 7396

考慮最簡單的有虛函式的繼承關係:

class f

};class s : public f

};此時,我們可以定義乙個父類的指標,實際指向乙個子類的物件。呼叫func函式的結果是子類的函式。虛函式在這裡是動態繫結的。

f *f = new s();

f->func(); 輸出s func

我們知道子類即使不定義虛函式也會繼承該虛函式表。而且乙個類,除了繼承的虛函式表之外,自行定義的虛函式公用乙個虛函式表。即使繼承的虛函式名稱相同,但是來自於不同的父類,即繼承了多個父類相同的虛函式,依舊是繼承每個父類的虛函式表。

class f

};class m

};class s : public f ,public m

virtual void foo() {}

};在這種情況下,s一共有三個虛函式表,繼承自兩個父類的,每個父類都有乙個,以及自己定義的。 繼承父類的,兩個虛函式表中的func的指標都是指向了類s自己定義的函式。

需要注意的是,編譯的時候,非虛函式會鏈結繫結,類本身會構造虛函式表,子類和父類的虛函式表項可能指向不同的地方。 

假設考慮定義的不是指標的情況。

s s;

f f = s;

f.func(); 輸出f func

f f = s;這裡應該是編譯器預設為我們生成的賦值建構函式。

f物件 s物件的虛函式表是形成了,表項中的指標也已經確定了,指向各自的函式。 賦值建構函式,我們沒有定義,預設的這裡測試的結果是什麼都沒做。無論如何,這裡賦值建構函式與虛函式表無關。

如果是指標的情況,如果是父類的指標指向子類的例項,父類的非虛函式以及和類本身繫結好了,依舊會呼叫父類的函式。但是虛函式要通過虛函式表進行訪問,那麼父類的指標就會訪問到子類的虛函式表,從而呼叫子類的函式。

反過來,如果讓子類的指標指向父類的物件,首先會編譯錯誤,如果強制型別轉換(都是指標嘛),你可能會看到段錯誤。因為子類的記憶體是大於父類的記憶體的,父類的一些資料在子類中順序可能不是你想的那樣了。。

虛函式表指標總是在類的成員變數之前。

乙個單繼承的例子:

class f

virtual void t()

char a;

f():a(1) {}

};class s : public f

//virtual void t() {}

//virtual void m() {}

char b;

s():b(2) {}

};class g : public s

virtual void func2()

g():c(3) {}

double c;

};class l

};int main()

vtableaddr = (int *)((char *)vtableaddr + 4);

printf("a = %d\n",*((char *)vtableaddr));

vtableaddr = (int *)((char *)vtableaddr + 1);

printf("b = %d\n",*((char *)vtableaddr));

vtableaddr = (int *)((char *)vtableaddr + 3);

printf("c = %f\n",*((double *)vtableaddr));

return 0;

我們可以看到乙個類的記憶體布局:首先是虛函式表指標,然後是父類的物件,然後是子類的物件。這裡輸出子類的物件的偏移計算時,需要考慮位元組對齊。由於使用的gcc編譯器,預設對齊係數是4.所以偏移計算如上。

C 虛函式表

一般來說,對於開發者我們只需要知道虛函式的使用方法,以及虛函式表的存在即可。但面試時往往會遇到更細節的問題,比如讓你實現乙個虛函式機制,雖然不太實用,總歸了解些底層知識也是件好事。但如果有人苦苦相逼一定要拿這個刷人,你就去罵他吧,你才是寫編譯器的,你們全家都是寫編譯器的。唉,我有些失態了.1.虛函式...

C 虛函式表

c 中的虛函式的作用主要是實現了多型的機制。關於多型,簡而言之就是用父型別別的指標指向其子類的例項,然後通過父類的指標呼叫實際子類的成員函式。這種技術可以讓父類的指標有 多種形態 這是一種泛型技術。所謂泛型技術,說白了就是試圖使用不變的 來實現可變的演算法。比如 模板技術,rtti技術,虛函式技術,...

C 虛函式表

解析c 的虛函式表 c 中的虛函式的作用主要是實現了多型的機制。關於多型,簡而言之就是用父型別別的指標指向其子類的例項,然後通過父類的指標呼叫實際子類的成員函式。這種技術可以讓父類的指標有 多種形態 這是一種泛型技術。所謂泛型技術,說白了就是試圖使用不變的 來實現可變的演算法。比如 模板技術,rtt...