如何改寫乙個類中虛函式的行為

2021-09-27 03:07:27 字數 2280 閱讀 2282

我們都知道c++中的多型是通過虛函式來實現的。

舉個例子:

class base

};class derived1 :public base

};class derived2 :public base

};int main()

上面的例子中,我們通過基類的指標指向不同的子類物件時,也就是做向上轉型的操作,就會產生多型的效果。

回到正題,那麼我們有沒有方法來改變乙個虛函式的行為呢。比如上述例子中,當pbase指向dr1物件時,我們不讓程式輸出"derived1",而是我們自己寫的乙個其他函式的輸出呢,比如下面的,輸出"func"。

void func()

炸一看好像不太可能,怎麼可以改變乙個函式原來的行為呢?是吧!

可是讓我們停下來想想c++中的多型是怎麼實現的。大家都該知道,c++中是通過vtbl和vptr來實現執行時多型的機制。關於vtbl和vptr這裡也不再詳細敘述,因為我們的重點不在這裡,大家可以隨便找點文章來看看。簡單來說,假設我們的乙個類中帶有虛函式,那麼每個這樣的class object中就會有乙個隱藏的vptr。這個vptr指向vtbl,而vtbl裡存放的就是這個object實際應該呼叫到的函式的位址。而這就是重點。

既然知道乙個虛函式是通過object裡vptr指向的乙個vtbl找到相應的函式位址來實現的,那麼我們可能就會順著這個思路想到,假如我們改變這個vtbl裡的函式位址,那麼就可以實現我們的想法。

一般來說,32位機器下,編譯器會在物件的頭4個位元組裡存放我們的vptr(因為32位下指標的大小是4位元組),下面給出乙個簡單的例子來驗證。我會寫出乙個帶虛函式的class和乙個不帶虛函式的class,然後通過觀察class裡成員變數的位址來說明。

class vir

};class nonvirtual

;int main()

下面是在我的機器上的輸出結果:

看到了嗎,不帶有虛函式object的位址就是其物件內第乙個成員a的位址。而帶有虛函式的object位址卻和其成員a的位址相差了4個位元組。而這4個位元組,存放的想必就是vptr了。

好了,那麼知道了這些,離我們實現我們的想法又近了一步,剩餘的工作就是我們如何改變vtbl裡存放的位址呢?

現在我們已經知道了如何找到乙個object內虛函式的位址,那麼如何改寫它裡面的內容呢?

我們想藉著乙個工具,memcpy,大家都很熟悉,將乙個指標指向的內容拷貝到另乙個指標指向的位址裡去,現在我們已經知道了乙個位址,接下來就是獲取我們另外乙個函式的位址。是這樣嗎,還不是,因為我們拷貝的是內容,所以我們拷貝的不是函式的位址,而是函式位址內的內容。這樣我們應該再重新宣告乙個變數,讓這個變數裡的內容,變成我們想要的函式位址。可能有點繞。下面來借助**解釋:

void targetfunc()

using targettype = void(*)();

targettype helpvar;

helpvar = targetfunc;

這裡我已經宣告了乙個變數helpvar,讓它來等於我們最終的目標函式。

targettype* ptarget = &helpvar;
void targetfunc()

using targettype = void(*)();

int main()

如果你對最後為什麼傳的是&ptarget而不是ptarget無法理解的話,建議再把targetfunc和&ptarget列印出來幫助理解。

cout << targetfunc << endl;

cout << ptarget << endl;

cout << *ptarget << endl;

// 輸出

00a414ce

006ffbe0

00a414ce

可以看到,*ptarget也就是ptarget裡的內容才等於targetfunc的值。

最終,我們借助虛函式的實現機制來實現了改變虛函式的行為的想法。其實c++還有太多需要需要我們去學習的東西,例如這個例子,我們雖然知道虛函式的實現機制,可是我們一時半會還是想不出這樣的方法。很多時候你以為你學會了,其實並不是,融會貫通,舉一反三,能夠將所學的應用到我們實際的想法中,不斷的去深入,才是真正的學會。

如何改寫乙個SIP Message中的SDP內容

the message here is either a request or a response.the sample code is as below if message.getcontentlength 0 string contenttype message.getcontenttype...

空類的sizeof,有乙個虛函式的類的sizeof

題目 二 執行下面的 輸出是什麼?class a class b b class c virtual c int tmain int argc,tchar argv 答案是1,1,4 class a 是乙個空型別,它的例項不包含任何資訊,本來求 sizeof 應該是0 但當我們宣告該型別的例項的時候...

如何使用Qt中的乙個類

這裡分析的是qlineedit 1.public types 這是乙個在這個類中可以供我們使用的公共列舉型別。這也就是說,我們可以如下使用這個公共型別 some code qlineedit echomode mode mode mylineedit echomode mode qlineedit ...