初步認識虛函式(二)

2022-05-15 04:53:37 字數 2569 閱讀 6826

虛函式是如何做到的

如果你沒有看過《inside the c++ object model》這本書,但又急切想知道,那你就應該從這裡開始)

虛函式是如何做到因物件的不同而呼叫其相應的函式的呢?現在我們就來剖析虛函式。我們先定義兩個類

class a

virtual

void fun2()

};class b : public

a

void fun2()

};

由於這兩個類中有虛函式存在,所以編譯器就會為他們兩個分別插入一段你不知道的資料,並為他們分別建立乙個表。那段資料叫做vptr指標,指向那個表。那個表叫做vtbl,每個類都有自己的vtbl,vtbl的作用就是儲存自己類中虛函式的位址,我們可以把vtbl形象地看成乙個陣列,這個陣列的每個元素存放的就是虛函式的位址,請看圖

通過左圖,可以看到這兩個vtbl分別為class a和class b服務。現在有了這個模型之後,我們來分析下面的**

a *p=new

a;p->fun();

毫無疑問,呼叫了a::fun(),但是a::fun()是如何被呼叫的呢?它像普通函式那樣直接跳轉到函式的**處嗎?no,其實是這樣的,首先是取出vptr的值,這個值就是vtbl的位址,再根據這個值來到vtbl這裡,由於呼叫的函式a::fun()是第乙個虛函式,所以取出vtbl中第乙個slot的值即為第乙個虛函式的位址(在不同的編譯器下第乙個vtbl布局不完全相同,在vs2008中第乙個slot的值為指向第乙個虛函式的指標,而其他編譯器中也可能出現第乙個slot中值為type_info物件的指標),這個值就是a::fun()的位址了,最後呼叫這個函式。現在我們可以看出來了,只要vptr不同,指向的vtbl就不同,而不同的vtbl裡裝著對應類的虛函式位址,所以這樣虛函式就可以完成它的任務。

而對於class a和class b來說,他們的vptr指標存放在何處呢?其實這個指標就放在他們各自的例項物件裡。由於class a和class b都沒有資料成員,所以他們的例項物件裡就只有乙個vptr指標。通過上面的分析,現在我們來實作一段**,來描述這個帶有虛函式的類的簡單模型。

#includeusing

namespace

std;

//將上面「虛函式示例**」新增在這裡

class a

virtual

void fun2()

};class b : public

a

void fun2()

};int

main()

用vc或dev-c++編譯執行一下,看看結果是不是輸出3。現在一步一步開始分析

void (*fun)(a*); 這段定義了乙個函式指標名字叫做fun,而且有乙個a*型別的引數,這個函式指標待會兒用來儲存從vtbl裡取出的函式位址

a* p=new b; new b是向記憶體(記憶體分5個區:全域性名字空間,自由儲存區,暫存器,**空間,棧)自由儲存區申請乙個記憶體單元的位址然後隱式地儲存在乙個指標中.然後把這個位址賦值給a型別的指標p.

.long lvptraddr; 這個long型別的變數待會兒用來儲存vptr的值

memcpy(&lvptraddr,p,4); 前面說了,他們的例項物件裡只有vptr指標,所以我們就放心大膽地把p所指的4bytes記憶體裡的東西複製到lvptraddr中,所以複製出來的4bytes內容就是vptr的值,即vtbl的位址

現在有了vtbl的位址了,那麼我們現在就取出vtbl第乙個slot裡的內容

memcpy(&fun,reinterpret_cast(lvptraddr),4); 取出vtbl第乙個slot裡的內容,並存放在函式指標fun裡。需要注意的是lvptraddr裡面是vtbl的位址,但lvptraddr不是指標,所以我們要把它先轉變成指標型別

fun(p); 這裡就呼叫了剛才取出的函式位址裡的函式,也就是呼叫了b::fun()這個函式,也許你發現了為什麼會有引數p,其實類成員函式呼叫時,會有個this指標,這個p就是那個this指標,只是在一般的呼叫中編譯器自動幫你處理了而已,而在這裡則需要自己處理。

delete p; 釋放由p指向的自由空間;

system("pause"); 螢幕暫停;

如果呼叫b::fun2()怎麼辦?那就取出vtbl的第二個slot裡的值就行了

memcpy(&fun,reinterpret_cast(lvptraddr+4),4); 為什麼是加4呢?因為乙個指標的長度是4bytes,所以加4。或者memcpy(&fun,reinterpret_cast(lvptraddr)+1,4); 這更符合陣列的用法,因為lvptraddr被轉成了long*型別,所以+1就是往後移sizeof(long)的長度,就這樣我真的把fun2()調出來了,我還傻乎乎的去定義fun2();

hive的初步認識(二)

管理資料,不同模組的資料最好放在不同的資料庫中,同mysql中的資料庫的概念 內部表 管理表 managed table 表的建立,表的資料的刪除,都是由hive自己決定的,同mysql中的表。內部表在進行刪除的時候,元資料和原始資料都會被刪除 外部表 external table 和內部表對立面,...

二 初步認識LoadRunner工具

loadrunner工具有三個組成分別是 virtual user generator 使用者行為模擬 錄製執行指令碼。controller 上面的錄製乙個使用者操作,這個可以將其轉殖成多個使用者,模擬多個用使用者操作。還用來監控相應時間 吞吐量 資源利用率等 負載生成及監控 1 點選 開始選單 點...

對虛函式 虛表的認識

虛函式 實現多型的機制,多型就是用父型別的指標指向其子類的例項,然後通過父類的指標呼叫實際子類的成員函式。讓父類的指標有 多種形態 一種泛型技術。關鍵字 virtual 虛函式表 此表中,主要是乙個類的虛函式的位址表,這張表解決了繼承 覆蓋的問題,保證其內容真實反映實際的情況。在c 標準規格說明書中...