C++中構造函數和析構函數調用的時機


今天看書忽然對這個地方有點模糊,尤其是析構函數在調用默認的析構函數和用戶自己覆寫的析構函數的時候有點意識模糊呢。寫段代碼總結下

 

[cpp]  view plain copy
 
  1. #include <iostream>  
  2.   
  3. using namespace std;  
  4.   
  5. class Box  
  6. {  
  7. private:  
  8.     double length;  
  9. public:  
  10.     Box(double lv=1.0):length(lv)//構造函數都沒有返回值  
  11.     {  
  12.         cout << "constructor called" << endl;  
  13.     }  
  14.   
  15.     ~Box()//重寫的析構函數(重寫是對繼承類對基類的重新構造,這里表述不對)  
  16.     {  
  17.         cout << "destructor called" << endl;  
  18.     }  
  19. };//萬惡的分號,我老是忘掉  

 

1、首先直接聲明(定義)看下

//很多朋友指出我這里用聲明不合適,在11樓作了一定解釋,具體不在這里贅述,這里改為“定義”,謝謝大家的指正,但我也保留我自己的意見,所以沒有把“聲明”去掉

 

 

[cpp]  view plain copy
 
  1. int main()  
  2. {  
  3.     Box box(2.3);  
  4. }  


 

這里看到一點java與c++的不同點,c++在聲明的時候就創建了對象,java聲明只是創建一個引用,並不會分配內存。言歸正傳,說明聲明以后就調用了構造函數,然后退出的時候調用析構函數。

 

2、聲明指針

 

[cpp]  view plain copy
 
  1. int main()  
  2. {  
  3.     Box *box;  
  4. }  


 


可以看到,聲明指針並不會調用構造函數,也不會分配內存空間。

 

3、用new創建

 

[cpp]  view plain copy
 
  1. int main()  
  2. {  
  3.     Box *box=new Box(2.3);  
  4. }  



 

僅僅是調用構造函數創建了對象,分配了內存空間。但是沒有調用析構函數,因為box指定的對象的內存是由new來創建分配的,編譯器不能夠自動調用析構函數將其刪除。所以需要調用delete才可以。

 

4、用new創建對象,並delete掉

 

[cpp]  view plain copy
 
  1. int main()  
  2. {  
  3.     Box *box=new Box();  
  4.     delete box;  
  5. }  



 

這次調用了析構函數。可以看出,此時的析構函數不是編譯器自己調用的,是由我們的程序來主動調用的,所以以后需要注意。new了的需要手動釋放內存空間

 

5、什么時候需要重寫析構函數?

 

 

[cpp]  view plain copy
 
  1. class Message()  
  2. {  
  3. private:  
  4.     char *message;  
  5. public:  
  6.     Message(const char* text="default message")  
  7.     {  
  8.         message = new char[strlen(text)+1];  
  9.         strcpy(message, text);  
  10.     }  
  11.   
  12.     void showit()  
  13.     {  
  14.         cout << "message: " << message << endl;  
  15.     }  
  16.   
  17.     ~Message()  
  18. };  
  19.   
  20. Message::~Message()  
  21. {  
  22.     cout << "destructor called" << endl;  
  23.     delete [] message;  
  24. }  


從例子可以看到,當你的構造函數中調用了new來創建對象的內存分配空間,則需要專門調用delete來釋放內存,所以此時需要覆寫析構函數,來專門的釋放此內存空間

 

6、對象的形參傳值問題:(話外題,僅作記錄用)

先看代碼及運行結果

 

[cpp]  view plain copy
 
  1. #include <iostream>  
  2.   
  3. using namespace std;  
  4.   
  5. class Box  
  6. {  
  7. private:  
  8.     double length;  
  9. public:  
  10.     Box(double lv=1.0):length(lv)//構造函數都沒有返回值  
  11.     {  
  12.         cout << "constructor called" << endl;  
  13.     }  
  14.   
  15.     ~Box()  
  16.     {  
  17.         cout << "destructor called" << endl;  
  18.     }  
  19.   
  20.     void showit()  
  21.     {  
  22.         cout << this->length << endl;  
  23.     }  
  24. };  
  25.   
  26. void display(Box box)//關鍵注意這個地方。。。。。。。。。。。。。。。。。。。。。。。。。  
  27. {  
  28.     box.showit();  
  29. }  
  30. int main()  
  31. {  
  32.         Box box;  
  33.         display(box);  
  34. }  



 
        

運行結果

如果將上面的display代碼改為

 

 

[cpp]  view plain copy
 
  1. void display(Box &box)//改為調用的是引用  
  2. {  
  3.     box.showit();  
  4. }  

運行結果

 

 

可以明顯的看到不加引用的時候會出現兩個析構函數的調用。為什么呢?

直接傳參,是形參傳遞,所以會另外創建一個對象來復制main函數里的對象box,所以在display調用完成時刻要調用析構函數來釋放這個函數創建的形參對象的內存空間。但是如果是傳遞的引用,就只有一個參數對象了,所以只調用一個。

 

如果是平時的基本類型,你應該了解,直接把main里的box的值復制給形參box就是了,但是到了對象這里就有點復雜,如果是里面就是單純的像上面的例子一樣double類型等,其自帶有復制函數就可以將各個成員值復制到形參對象里,但是如果里面有引用,比如char *pp = new char[100],那么復制的只是地址,兩個對象公用一個地址,有可能就會造成錯誤。所以以后需要注意這一點,調用對象需要用引用哦。。。。。(要不你自己另寫一個復制函數。)


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM