對類成員進行特殊操作 2 轉貼

2021-04-01 10:09:26 字數 1857 閱讀 3372

對類成員進行特殊操作(2)

發布者: 北斗龍 (進入北斗龍個人專欄)

評價等級:

2位使用者為此文章評分,平均分為4.0

大家在看了文章1後以經對取得虛函式位址有所了解,但用它作**函式還是有一點問題,因為要使成員函式正確執行,我們必須每次在呼叫這前傳乙個this給ecx(對應的成員函式中沒有操作類成員除外,原因見(文章1)),作為**函式,它可不給你這個機會,那怎麼實現呢?

下面就是一種實現方法:

我們可以在資料段中開乙個陣列,在這個陣列裡存放一些特殊的資料,然後將這個陣列的位址作為**函式的位址,然後這個陣列將被作為**執行。那麼這個陣列對應的**又做些什麼呢?很簡單的:將物件的位址傳入ecx, 然後jmp到真正的**函式。

下面是個例子:

主要部分也就是thunkinit(thunkdata t, void *this, int virfucid);

其次,就是用陣列的位址作為函式位址,呼叫對應的函式時,先執行陣列裡的**,這樣就保證了函式內部的this指標的正確性。

例3

class ccc

~ccc() {};

virtual void print1()

virtual void print2()

virtual void print3(int num)

private:

int m_data1;

};typedef unsigned char thunkdata[14];

void inline thunkinit(thunkdata t, void *this, int virfucid)

// end thunkinit

void print5times1(long fucaddr)

void print5times2(long fucaddr, int num)

void main()

注意:

1. ((void (__stdcall *)(void))(long)fucaddr)();是將fucaddr的位址轉換為long型,然後再將它轉化為(void (__stdcall *)(void))型別函式(如有不明白,請找有關資料),最後呼叫此函式。

2. thunkinit函式可能較難理解,下面是進一步的講解:

t[0] = 0xb9;  //這個操作碼為 mov ecx, 它將把接下來的long立即數,送入ecx

*((long *)(t+1)) = (long) this;  // this, 對應的物件的位址,在執行是將作立即數,送入ecx

*((short int *)(t+5)) = 0x018b;  // mov eax, [ecx] 取得虛函式表的起始位置

t[7] = 0x5;                                    // add eax, 

*((long *)(t+8)) = virfucid*4;  //virfucid*4  計算出存放對應虛函式位址的位址

*((short int *)(t+12)) = 0x20ff;  // jmp [eax]   調轉到以應的虛函式

最後我想加幾句題外話,這些例子都只是簡單的用應,文章1中兩個例子沒有實際意義,旨在為例3做鋪墊。至於有沒有用,我也不知,只是我在一些程式中應用了而己,剛開始只是從其它原碼中拿過來用,也不解其中的原理。但一次在圖書管中看了《程式設計深入引導》(中國水利水電出版社)後,由於它詳細說明了類的實現,並附了對應的彙編原始碼,讓我豁然開朗,經過幾翻測試,終於弄懂了它的原理,覺得做法挺不錯,也就寫了上面這些,文筆較差,還不知能否讓大家看懂。

不過這種做法有點費澀難懂,在附件中的工程dd,演示了「靜態成員函式+物件的靜態指標」做**函式,不過在這裡得注意一點,後面這種做法,整個類只能定義乙個物件(因為物件的靜態指標)。

對類裡成員函式返回私有資料成員的操作

對類裡面的私有指標,自己犯這樣的錯誤 1 對返回指標直接賦值 god.return pointer change n 當然這樣編譯器會報錯。2 妄想通過別的指標賦值 char p god.return pointer p change n 這樣私有成員指標當然沒有被改變到。確做法應該是增加乙個 vo...

理解反射(五)對接受陣列引數的類成員進行反射

class testargument中的內容如下 class testargument 主函式呼叫如下 public class reflecttest2 這裡顯示引數的個數不對,main方法只接受乙個字串陣列引數 我們準備乙個string給他按照道理說應該沒什麼問題,但是jdk1.5為了照顧jdk...

理解反射(五)對接受陣列引數的類成員進行反射

class testargument中的內容如下 class testargument 主函式呼叫如下 public class reflecttest2 這裡顯示引數的個數不對,main方法只接受乙個字串陣列引數 我們準備乙個string給他按照道理說應該沒什麼問題,但是jdk1.5為了照顧jdk...