2011-09-26 82 views
-1
#include <iostream> 
using namespace std; 
typedef void (*pFun)(void); 
class A 
{ 
private:  
    int a; 
    int b; 
    virtual void outPrint() 
    { 
     cout << b << endl; 
    } 
public: 
    A() 
    { 
     a = 3;  
     b = 4; 
    } 
}; 

int main() 
{ 
    A obj; 
    cout << *((int*)(&obj)+1) << endl; 
    pFun pFunc;  
    pFunc = (pFun)*((int*)*(int*)(&obj)); 
    pFunc(); 
    system("pause"); 
    return 0; 
} 

當我調用pFunc(),結果我認爲應該是4,但實際上它是一個隨機數。 我調試程序,發現pFunc指向outPrint函數。我不知道爲什麼,PLZ幫我爲什麼結果不符合我的預期?

+0

你使用什麼編譯器? –

+0

vs2010,你的意思是它可能與編譯器有一些關係? – cloud

+0

是的,成員變量/方法在內存中的排序方式取決於編譯器。 –

回答

2

似乎你認爲對象obj的地址可以解釋爲你定義類型的函數的地址。

它不能。

我不完全確定你爲什麼會有這樣的假設開始。你可能會假設動態調度的內部實現。但是請注意:您期望被調用的A::outPrint接受1個參數(this,未明確定義),而您的typedef不採用參數。所以,即使地址轉換工作正常,並且您獲得的地址是成員函數的地址(這是一個開始),您的呼叫是不正確的。

如果更改的typedef:

typedef void (*pFun)(A*); 

,並調用

pFunc(&obj); 

可能的工作。然而,根據我的理解,每個規範的行爲是不確定的。

+0

我想我明白了,非常感謝你 – cloud

1

將1添加到int*僅在遍歷int[]的情況下具有已定義的行爲。

其他情況下,沒有定義應該發生什麼。由於未定義成員的最終內存位置,因此定義了實現。

試着用一種不利用編譯器細節而是利用標準的方法來解決問題。另外,在這種情況下,按照這種方式獲得函數地址,將其作爲一個靜態方法(沒有對象)進行調用,只能爲您提供幾個令人頭痛的問題。

0

我不太確定你到底想要做什麼。它看起來像你試圖直接操縱指針以獲取方法的地址,但由於6種不同的原因,這是一個非常糟糕的主意。有可能獲得一個指向類方法的指針,但它不綁定到對象,所以你需要小心。

我建議你對指針和C++類有一個根本性的誤解,在你安全地管理這些之前必須糾正這些錯誤。大多數人不需要函數指針,幾乎沒有人需要方法指針。

+0

想你給我你的建議,我會記住它 – cloud

0

您正在依賴各種「未定義行爲」,因此結果取決於您正在運行的編譯器和平臺。

(int *)& obj + 1(更好的是如果你寫((int *)&obj)+1以避免誤解)不一定是b成員。成員之間可能會有填充,並且&obj可能與&(obj.a)不同,它們是obj多態對象(所以可能是它具有位於其頂部的vtable指針)。

如果是這種情況,*(int*)&obj是作爲int處理的vtable地址。將它轉換爲int*(假設int和指針具有相同的大小),它指向第一個vtable條目(最有可能是outPrint的地址),因此是「隨機數」。

相關問題