一.虛函式表
1.虛函式:類的成員函式前面加上virtual關鍵字。
3.虛函式表就像一張地圖,指明了要呼叫的虛函式。
二.虛函式表的小知識
1.乙個類中只要含有虛函式,則一定會生成一張虛表。
(2)乙個類中不含有虛函式,則其物件的監視視窗如下(可以看到a類的物件a就只含有成員變數,沒有虛表指標):
2.物件裡面並不是存放整個虛表的,物件裡面只存放了乙個指向虛表的指標。(由上面圖可以看出,物件裡面只存放乙個虛表指標_vfptr)
如果乙個物件裡面存放整個虛表,不僅會使該物件變得很大,而且會使得與其同類的所有物件裡面都存放乙個虛表,但是每個物件的虛表都是相同的,為了節省空間還有提高效率,應該讓同類的所有物件指向同乙個虛表,這樣只需要每個物件裡面存放乙個指向虛表的指標就可以了。3.同型別的所有物件共用一塊虛表。
例如:在靜態區定義乙個a的物件a3,在棧上定義兩個a的物件a1和a2,通過監視視窗可以看到a的所有物件a1,a2,a3裡面的虛表指標的內容都相同,都是0x003acc74,表明他們的虛表的位址都相同,所以他們共用同一塊虛表。
三.通過自己編寫的程式列印虛表
1.由上面的圖可以知道,虛表指標放在物件的頭上(在32位的平台上是頭上4個位元組,在64位的平台上是頭上8個位元組)。
2.下面以32位平台為例:
3.若給定乙個物件,我們可以先取物件的前面4個位元組,然後解引用取出頭上4個位元組的內容(即虛表的位址),讓這個虛表以4位元組為單位(因為虛表裡面存放的是虛函式的位址,在32位下是4個位元組),依次往後遍歷,直到遇到0就結束(虛表是以0作為結束標誌)。
4.我們可以將虛表裡面的內容看做int,最後只要以%p的形式列印虛表的內容就可。
5.將虛表的內容看作int,則虛表就相當於乙個存放int的陣列,即int *table.
6.如果給定了虛表int *table,則可以按照下面的方式列印:
void printvftable(int *table)
cout << endl;
}
7.呼叫列印虛表傳的引數如下:
int main()
8.執行結果如下:
(1)定義乙個函式指標,因為a類裡面所有的虛函式返回值都是void,而且無引數,所以函式指標可以定義為:
typedef void(*vfunc)();
(2)列印虛表函式的**進行如下修改:
void printvftable(int *table)
cout << endl;
}
(3)執行結果如下:
四.在64位平台下列印虛表
1.在64位下如果採用上面的方式列印虛表會出現錯誤。因為在64位平台下指標佔8個位元組,而在32位平台下,指標佔四個位元組。
2.所以在64位平台下:應該取物件的頭上8個位元組,解引用取出裡面的內容,然後再按照8位元組為單位遍歷虛表即可。
3.我們直到long long佔8個位元組,因此可以將**進行如下修改:(這個只能在64位的平台執行)
void printvftable(long long *table)
cout << endl;
}int main()
4.執行結果如下:
五.在32位和64位平台都可以執行列印虛表
1.我們知道在32位乙個指標佔4個位元組,在64位平台下,乙個指標佔8個位元組,我們只要解引用出來的是乙個指標型別就可以達到在32位下面每次都按照4位元組遍歷,在64位平台下,每次都按照8位元組遍歷。
2.將**進行如下修改:
void printvftable(int**table)
cout << endl;
}int main()
3.上面的**在64位和32位平台都可以執行。
(1)在64位平台下:
(2)在32位平台下:
C 虛函式表
考慮最簡單的有虛函式的繼承關係 class f class s public f 此時,我們可以定義乙個父類的指標,實際指向乙個子類的物件。呼叫func函式的結果是子類的函式。虛函式在這裡是動態繫結的。f f new s f func 輸出s func 我們知道子類即使不定義虛函式也會繼承該虛函式表...
C 虛函式表
一般來說,對於開發者我們只需要知道虛函式的使用方法,以及虛函式表的存在即可。但面試時往往會遇到更細節的問題,比如讓你實現乙個虛函式機制,雖然不太實用,總歸了解些底層知識也是件好事。但如果有人苦苦相逼一定要拿這個刷人,你就去罵他吧,你才是寫編譯器的,你們全家都是寫編譯器的。唉,我有些失態了.1.虛函式...
C 虛函式表
c 中的虛函式的作用主要是實現了多型的機制。關於多型,簡而言之就是用父型別別的指標指向其子類的例項,然後通過父類的指標呼叫實際子類的成員函式。這種技術可以讓父類的指標有 多種形態 這是一種泛型技術。所謂泛型技術,說白了就是試圖使用不變的 來實現可變的演算法。比如 模板技術,rtti技術,虛函式技術,...