虛表與虛指標

2022-09-23 17:27:12 字數 3797 閱讀 9821

網上各種關於這個的文章,但是我卻找了很久才找到我想要的東西,小小的總結一下。因為我心中一直有個疑問:虛表存在什麼地方,是類還是物件裡面?虛指標又存在什麼地方,是類還是物件?鍥而不捨終於在第一篇文章找到我想要的東西。

1.c++類中的過載

看看下面的**:

[html]

#include       

using namespace std;    

class vehicle 

void showmember() 

protected:    

float speed; 

int total; 

};    

class car:public vehicle    

void showmember() 

protected:    

int aird; 

};    

void main()    

#include     

using namespace std;  

class vehicle

void showmember()

protected:  

float speed;

int total;

};  

class car:public vehicle  

void showmember()

protected:  

int aird;

};  

void main()  

在c++中是允許派生類過載基類成員函式的,對於不同類的物件,呼叫其類的成員函式的時候,系統是知道如何找到其類的同名成員。上面**中的a.showmember()呼叫的是vehicle::showmember(),而b.showmember()呼叫的是

[html]

car::showmemeber()。 

#include       

using namespace std;    

class vehicle 

void showmember() 

protected:    

float speed; 

int total; 

};    

class car:public vehicle    

void showmember() 

protected:    

int aird; 

};    

void test(vehicle &temp)    

void main()    

car::showmemeber()。

#include     

using namespace std;  

class vehicle

void showmember()

protected:  

float speed;

int total;

};  

class car:public vehicle  

void showmember()

protected:  

int aird;

};  

void test(vehicle &temp)

void main()  

物件a與b分辨是基類和派生類的物件,而函式test的形參卻只是vehicle類的引用,按照類繼承的特點,系統把car類物件看做是乙個 vehicle類物件,因為car類的覆蓋範圍包含vehicle類,所以test函式的定義並沒有錯誤,我們想利用test函式達到的目的是,傳遞不同類物件的引用,分別呼叫不同類的,過載了的,showmember成員函式,但是程式的執行結果卻出乎人們的意料,系統分不清楚傳遞過來的基類物件還是派生類物件,無論是基類物件還是派生類物件呼叫的都是基類的showmember成員函式。

解決上面這個問題就是利用多型了。

2.多型中的虛表與虛位址

對c++ 了解的人都應該知道虛函式(virtual function)是通過一張虛函式表(virtual table)來實現的。簡稱為v-table。在這個表中,主是要乙個類的虛函式的位址表,這張表解決了繼承、覆蓋的問題,保證其容真實反應實際的函式。

[html] 

class a 

; class a

;   (1)sizeof(a)=4,這個4應該是個指標大小,代表虛指標,虛指標是個函式指標,指向虛函式表裡面的位置,虛表裡面存放的是虛函式的位址。

(2)a a;sizeof(a)=4,虛指標存在於每個物件中,因為類不是乙個可以儲存的地方。

(3)c++的編譯器應該是保證虛函式表的指標存在於物件例項中最前面的位置(這是為了保證取到虛函式表的有最高的效能——如果有多層繼承或是多重繼承的情況下)。 這意味著我們通過物件例項的位址得到這張虛函式表,然後就可以遍歷其中函式指標,並呼叫相應的函式。

(4)虛表是整個類共用的,他的大小取決於你定義的虛函式的個數,以及編譯器的策略.一般存在於記憶體的某個地方,你不需要去管他。

這裡我還有乙個問題,為什麼下面這個程式等於1:

[html] 

class a 

;   

int main() 

class a; 

int main()

3.虛函式表

(1)如何獲取虛函式表的位址

假設我們有這樣的乙個類:

[html]

class base ; 

class base ;

按照上面的說法,我們可以通過base的例項來得到虛函式表。 下面是實際例程:

[html] 

typedef void(*fun)(void); 

base b; 

fun pfun = null; 

cout << "虛函式表位址:" << (int*)(&b) << endl; 

cout << "虛函式表 — 第乙個函式位址:" << (int*)*(int*)(&b)<< endl; 

// invoke the first virtualfunction 

pfun = (fun)*((int*)*(int*)(&b)); 

pfun(); 

typedef void(*fun)(void);

base b;

fun pfun = null;

cout << "虛函式表位址:" << (int*)(&b) << endl;

cout << "虛函式表 — 第乙個函式位址:" << (int*)*(int*)(&b)<< endl;

// invoke the first virtualfunction

pfun = (fun)*((int*)*(int*)(&b));

pfun();

實際執行經果如下:(windows xp+vs2003,  linux 2.6.22 + gcc 4.1.3)

虛函式表位址:0012fed4

虛函式表 — 第乙個函式位址:0044f148

base::f

通過這個示例,我們可以看到,我們可以通過強行把&b轉成int *,取得虛函式表的位址,然後,再次取址就可以得到第乙個虛函式的位址了,也就是base::f(),這在上面的程式中得到了驗證(把int*強制轉成了函式指標)。通過這個示例,我們就可以知道如果要呼叫base::g()和base::h(),其**如下:

(fun)*((int*)*(int*)(&b)+0);  //base::f()

(fun)*((int*)*(int*)(&b)+1);  // base::g()

(fun)*((int*)*(int*)(&b)+2);  // base::h()

虛表 虛指標

虛函式在c 中的實現機制就是用虛表和虛指標,但是具體是怎樣的呢?從more effecive c 其中一篇文章裡面可以知道 是每個類用了乙個虛表,每個類的物件用了乙個虛指標。具體的用法如下 cpp view plain copy class a class b public a a,b的實現省略 因...

虛函式,虛表,虛表指標

分享一篇文章,詳細解釋了為什麼通過基類指標指向基類物件或派生類物件,就可以呼叫相應類的虛函式。自 一 概述 為了實現c 的多型,c 使用了一種動態繫結的技術。這個技術的核心是虛函式表 下文簡稱虛表 本文介紹虛函式表是如何實現動態繫結的。二 類的虛表 每個包含了虛函式的類都包含乙個虛表。我們知道,當乙...

虛繼承 虛表 虛指標

c 實現多型的方法 其實很多人都知道,虛函式在c 中的實現機制就是用虛表和虛指標,但是具體是怎樣的呢?從more effecive c 其中一篇文章裡面可以知道 是每個類用了乙個虛表,每個類的物件用了乙個虛指標。具體的用法如下 class a class b public a a,b的實現省略 因為...