對類成員進行特殊操作(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...