我知道c++有乙個虛函式列表,物件有指向虛函式列表的指標,對於有虛函式的類物件呼叫虛函式時通過虛函式列表裡面的指標實現的。。但是對於普通的非虛函式是怎麼實現呼叫的呢、? 是怎麼找到非虛函式的入口位址? 好像類物件裡面只有類的一些資料成員。。求解惑 求詳細的記憶體層次的變化
2013-09-10 20:39
提問者採納
程式執行時記憶體中有乙個區域【**區】,所有**段都存放在這裡,包括虛函式和非虛函式追問普通函式呼叫時,直接轉換成**去區的位址,生成檔案時就定了
類的虛表可以看成是類的靜態資料成員,類的每個物件有個指標指向這個虛表,即為虛表指標
當虛函式呼叫時,就是從虛表指標找到虛表,進而找到了虛函式的位址
比如:class a };a a;
a.f(); //呼叫f();
我知道編譯時類中函式會在**區生成,還有乙個偏移量來定位什麼的(這不是很懂), 但是a.f是怎麼知道**區f()函式的絕對位址的? 就是想知道執行a.f()時,記憶體裡面發生了什麼變化。
回答
1
2
3
4
5
6
class
a
virtual
void
g() {}
};
1
2
3
4
5
6
class
b :
public
a
virtual
void
g() {}
};
1
2
3
4
5
void
test(a& a)
以上是**
下面是test兩個函式呼叫的彙編**
1
2
3
4
5
6
7
8
9
10
11
12
a.f();
001f6fce mov ecx,dword ptr [a]
001f6fd1 call a::f (01f1433h)
a.g();
001f6fd6 mov eax,dword ptr [a]
001f6fd9 mov edx,dword ptr [eax]
001f6fdb mov esi,esp
001f6fdd mov ecx,dword ptr [a]
001f6fe0 mov eax,dword ptr [edx]
001f6fe2 call eax
001f6fe4 cmp esi,esp
001f6fe6 call __rtc_checkesp (01f12e9h)
由此可見,f函式直接定址(在編譯時就已經確定位址了01f1433h),而g函式通過虛指標定址
追問
恩 很明確,但是覺得類在編譯時,類裡面的函式只是乙個相對位址,但是在連線是才進行重定位為絕對位址,這兩個過程存在乙個位址修改的問題(根據什麼修改的很疑惑) 這樣反彙編後肯定是最後的絕對位址。。希望能夠解惑
謝謝你了 先採納了
提問者評價
非常感謝
類成員函式呼叫
大家都知道c 的虛函式前必須加virtual,但如果一連串的繼承下來,有的忘了加virtual會出現什麼情況呢?為了滿足我的好奇心,做了點實驗然後有了本文,僅僅是好玩,沒有啥實際意義。本文只給出vs2005的情況 首先,如果是單一類,沒加virtual的話那麼好辦,直接call a fun,非sta...
類成員函式呼叫的細節
class concrete void printerror private int val void main 為什麼會出現這種情況呢?原來是,函式定義的時候,就一直存在了。即無聊是否 例項化了乙個物件,print 這個函式,都是存在的。所以 pc print 是可以找到函式的入口的。只是這時候,...
c 呼叫dll函式,匯出類中的成員函式
對於dll的操作,我們可以使用dumpbin檢視dll 和lib。注意寫好dll後 用depends檢視匯出函式時會發現匯出的函式名不是你寫的那樣出現所謂的亂碼入?等 這就注定dll不能通過顯示連線的方式匯入。如果想通過顯示連線的方式匯入可以為類新增乙個友元函式去實現顯示連線建立類得物件 這裡對於匯...