注意C++中物件指標,慎用void*
由於不同C++編譯器對C++物件模型的結構可能是不一樣的。比如說,VC++系列是將虛擬函式表指標放在物件首地址,而GCC系列的編譯器則是將虛擬函式表指標放在物件地址尾部。
那麼下面我將詳細講講GCC編譯器下的物件模型(含虛擬函式表指標)。
先看下面這個例子:
using namespace std;
class A
{
private:
int a;
public:
A(void) : a(0)
{
}
virtual void Hello(void)
{
cout << "Hello, world!" << endl;
}
};
class B : public A
{
private:
int b;
public:
B(void) : b(1)
{
}
virtual void Hello(void)
{
cout << "B!" << endl;
}
};
上面的示例中,A物件的地址中存放兩個4位元組的資料,一個是變數a,另一個是虛擬函式表指標。變數a放在低地址;虛擬函式表指標放在高地址,那麼方便起見,我這樣表示——A objA = { a, vptr }。而B的物件首先是存放類A域的所有成員,然後是B自己的資料成員——B objB = { a, vptr, b }。
那麼這樣的安排就有助於編譯器處理這樣的情況了——
A *p = &b;
b->Hello();
那麼如果是多繼承或是虛繼承會怎樣呢?
碰到這種情況,GCC或其相容C++編譯器會同時判斷左運算元的型別以及有運算元的型別。根據左運算元的型別來判斷左運算元的指標指向有運算元物件的哪個偏移地址。如果是其他型別的指標(如void*),則指向物件的首地址。
下面請看一下詳細的測試程式碼:
using namespace std;
class A
{
private:
int a;
public:
A(void) : a(0)
{
}
virtual void Hello(void)
{
cout << "Hello, world!" << endl;
}
};
class AA
{
private:
int aa;
public:
AA(void) : aa(100)
{
}
virtual void Hi(void)
{
cout << "Hi, therte!" << endl;
}
};
class B : public A
{
private:
int b;
public:
B(void) : b(1)
{
}
virtual void Hello(void)
{
cout << "B!" << endl;
}
};
class C : virtual public A
{
private:
int c, d;
public :
C(void) : c(2), d(3)
{
}
void Hello(void)
{
cout << "C!" << endl;
}
};
class E : public A, public AA
{
private:
int e;
public:
E(void) : e(8)
{
}
void Hello(void)
{
cout << "E!" << endl;
}
void Hi(void)
{
cout << "Hi!" << endl;
}
};
extern "C" void test(void);
int main(void)
{
A a;
B b;
C c;
E e;
unsigned long s[10];
int i=0;
for(; i<sizeof(a) >> 2; i++)
s[i] = ((unsigned long*)&a)[i];
a.Hello();
for(i=0; i<sizeof(b) >> 2; i++)
s[i] = ((unsigned long*)&b)[i];
A *p = &b;
p->Hello();
for(i=0; i<sizeof(c) >> 2; i++)
s[i] = ((unsigned long*)&c)[i];
p = &c;
void* q = (C*)&c;
p->Hello();
for(i=0; i<sizeof(e) >> 2; i++)
s[i] = ((unsigned long*)&e)[i];
AA *pp = &e;
p = &e;
q = &e;
return 0;
}
在main函式中,上面的p和q兩個指標的值是不同的,儘管它們指向同一個物件。p指向了物件c的A類域的偏移處;而q則是指向了p 的首地址。那麼下面的pp和p及q也是不同,這裡的p和q都是指向首地址,因為類A域在物件e的起始處,而pp則是指向了e的AA類域的偏移處。
大家可以利用以上程式碼進行除錯,有個感性認識。
所以在C++中,甚用void*指標指向一個物件,否則當再次進行型別轉換時,呼叫相關函式可能會發生意想不到的情況。那麼這個時候還是利用模板,通過範型來解決型別問題,這樣做更安全,而且更優美。
相關文章
- 關於C/C++ void指標,使用void指標拷貝int 陣列C++指標陣列
- 簡述static關鍵字、void與void *(void指標)、函式指標指標函式
- 120 C++中的物件指標C++物件指標
- typedef void (*Fun) (void) 的理解——函式指標——typedef函式指標函式指標
- C++中函式指標與函式物件C++函式指標物件
- 【C++系列】指標物件和物件指標的區別C++指標物件
- int存放到void指標指標
- 【C++注意事項】4 指標 PointersC++指標
- 通過qsort(void * lineptr[], int left, int rifht, int (*comp)(void *, void *))解讀指標函式和void指標...指標函式
- C++中的this指標C++指標
- C++中的函式指標和函式物件總結C++函式指標物件
- C++中為什麼要用指標,而不直接使用物件?C++指標物件
- C++中為什麼使用指標比使用物件本身更好?C++指標物件
- C++中的指標與引用C++指標
- C++ this 指標C++指標
- C++ 指標C++指標
- C++指標理解C++指標
- 【c++】智慧指標C++指標
- C++智慧指標C++指標
- C/C++指向指標的指標C++指標
- JAVA中的指標,引用及物件的cloneJava指標物件
- C++物件導向程式設計(一):基於物件(無成員指標)C++物件程式設計指標
- C語言知識彙總 | 56-C語言NULL空指標以及void指標C語言Null指標
- C++父類指標指向子類物件的實現原理C++指標物件
- c++ 函式指標C++函式指標
- C++引用和指標C++指標
- C++指標轉換C++指標
- C++指標問題C++指標
- 「C++」理解智慧指標C++指標
- c++指標小計C++指標
- C++(函式指標)C++函式指標
- 聊聊 C++ 中的幾種智慧指標 (上)C++指標
- C++中的可見性 指標 筆記C++指標筆記
- 指向const物件的指標 和 const指標物件指標
- 再學C/C++ 之 指標常量 和 常量指標C++指標
- [C++] 成員函式指標和函式指標C++函式指標
- 詳解c++指標的指標和指標的引用C++指標
- C++中const與指標、引用的總結C++指標