在C++中,利用C++編譯器在實現虛函數調用時的某些伎倆,我們可以在類外直接調用到類的私人成員函數!!代碼如下,代碼中有詳細的說明。
//hacker.cpp: C++語言的駭客行為<br />#include <iostream><br />class Coo{<br />private:<br /> int d; //特意將d放在最前面,但實際上Coo類的對象記憶體中<br /> //在d前面還有一個指向vtable數組的指標變數<br /> //C++標準沒有規定虛函數如何?,但大部分編譯器都使用vtable,<br /> //並把指向它的指標放在實際資料成員的前面<br /> virtual void foo(); //私人的,並且是虛的,因此會有vtable!<br />public:<br /> Coo():d(100){ }<br />};<br />void Coo::foo(){<br /> std::cout<<d<<" ~~~!!!~~~ "<<std::endl;<br />}<br />int main(){<br /> Coo o;<br /> int *p=(int*)(&o); //p是強制將o的地址轉換為一個整數指標,這樣<br /> //p中存放的就是vtable的記憶體起始地址<br /> int addr=*(int*)(*p); //addr是將p中的內容,再強制當作是一個整數指標,<br /> //然後取出該指標指向的內容,就是函數Coo::foo的地址</p><p> //若Coo::foo不是virtual,則d前面不會有vtable,下面輸出會是d的值100的,<br /> //但現在*p應該會輸出vtable的記憶體位址<br /> std::cout<<"The vtable's address: "<<*p<<std::endl;<br /> //現在輸出的addr就是Coo::foo函數的地址<br /> std::cout<<"The Coo::foo's address: "<<addr<<std::endl;<br /> //為確認這一點,可以定義一個函數指標pfunc,並把addr(轉換成函數指標後)賦給它,<br /> //然後調用這個函數指標,就會導致函數Coo::foo函數的執行<br /> typedef void (*PFUNC)(Coo*);<br /> PFUNC pfunc=(PFUNC)(addr);<br /> pfunc(&o); //hack!直接調用了私人成員函數Coo::foo<br /> return 0;<br />}
注意:這裡沒有建立對象(即沒有this指標)就直接調用了成員函數,沒關係,死不了,只要成員函數裡沒有用到成員資料,它就和一個靜態成員函數一樣。但這裡foo內用到了成員d,怎麼辦?也可以實現,定義函數指標時添加一個Coo*參數(上面就是這麼做的),然後把o的地址傳入,就可以訪問到成員d了。