1. 程式人生 > >memset() 初始化類物件

memset() 初始化類物件

今天看到迅雷2014校招一道筆試題如下:

  1. #include <iostream>
  2. usingnamespace std;  
  3. class parent  
  4. {  
  5. public:  
  6.     virtualvoid output();  
  7. };  
  8. void parent::output()  
  9. {  
  10.     printf("parent!");  
  11. }  
  12. class son : public parent  
  13. {  
  14. public:  
  15.     virtualvoid output();  
  16. };  
  17. void son::output()  
  18. {  
  19.     printf("son!"
    );  
  20. }  
  21. int main()  
  22. {  
  23.     son s;  
  24.     memset(&s , 0 , sizeof(s));  
  25.     parent& p = s;  
  26.     p.output();  
  27.     return 0;  
  28. }  

輸出程式執行結果:程式不輸出結果,執行出錯!!分析一下原因:

在使用memset初始化物件Obj之前,通過Obj呼叫Show和Print函式時程式執行正常,但是一旦利用Memset函式初始化該物件,再對該obj呼叫Show和Print函式,則程式立馬崩潰。究其原因是因為初始化obj的時候,將obj包含的指向虛擬函式表VTBL的指標也清除了

。包含虛擬函式的類物件都有一個指向虛擬函式表的指標,此指標被用於解決執行時和動態型別強制轉換時虛擬函式的呼叫問題。該指標是被隱藏的,對程式設計師來說,這個指標也是不可存取的。當進行memset操作時,這個指標(即指向虛擬函式表的地址)的值也要被初始化,這樣一來,只要一呼叫虛擬函式,程式便會崩潰。
這種現象在很多由C轉向C++的程式設計師來說,很容易犯這個錯誤,而且這個錯誤很難查。

為了避免這種情況,記住對於有虛擬函式的類物件,決不能使用memset來進行初始化操作。而是要用預設的建構函式或其它的init例程來初始化成員變數。

當類中有虛擬函式的時候,編譯器會為類插入一個我們看不見的資料並建立一個表。這個表就是

虛擬函式表(vtbl),那個我們看不見的資料就是指向虛擬函式表的指標——虛表指標(vptr)。虛擬函式表就是為了儲存類中的虛擬函式的地址。我們可以把虛擬函式表理解成一個數組,陣列中的每個元素存放的就是類中虛擬函式的地址。當呼叫虛擬函式的時候,程式不是像普通函式那樣直接跳到函式的程式碼處,而是先取出vptr即得到虛擬函式表的地址,根據這個來到虛擬函式表裡,從這個表裡取出該函式的地址,最後呼叫該函式。所以只要不同類的vptr不同,他對應的vtbl就不同,不同的vtbl裝著對應類的虛擬函式地址,這樣虛擬函式就可以完成它的任務了。

合併兩家說法