為什么需要拷貝構造函數


  把參數傳遞給函數有三種方法,一種是傳值,一種是傳地址,一種是傳引用。傳值與其他兩種方式不同的地方在於 當使用

傳值方式的時候,會在函數里面生成傳遞參數的一個副本,這個副本的內容是按位從原始參數那里復制過來的,兩者的內容是相同的。

當原始參數是一個類的對象時,它也會產生一個對象的副本,此時需要注意:一般對象在創建時都會調用構造函數來進行初始化,但是

在產生對象的副本時如果再執行對象的構造函數,那么這個對象的屬性又再恢復到原始狀態,這就不是我們希望的了。所以在產生對象

副本的時候,構造函數不會被執行,被執行的是一個默認的默認的拷貝構造函數。

 

  問題原因:

  當函數執行完畢要返回的時候對象副本會執行析構函數,

如果你的析構函數是空的話,也不會發生什么問題,但一般的析構函數都是要完成一些清理工作,如釋放指針所指向的內存空間,這時候

可能就會出問題。 譬如:我們在構造函數中為一個指針變量分配了內存,在析構函數中釋放給這個指針所指向的內存空間,在把對象傳遞

給函數至函數結束返回 的這個過程中 首先有一個對象的副本產生了。這個副本也有一個指針,它和原始對象的指針是指向同塊內存空間的,

函數返回時,副本對象的析構函數執行了,釋放了副本對象中指針指向的內存空間,但是這個內存空間對於原始對象而言還是有效地,

這是第一個問題,后面當原始對象也被銷毀的時候,原始對象的析構函數執行,還會對那塊已經釋放掉的內存空間再次釋放,產生嚴重

錯誤,這是第二個問題。

  解決方法:

  既然傳值有這樣的問題,那是否可以使用傳地址或者傳引用的方式解決這種問題呢?

  事實上傳地址和傳引用確實可以解決這種問題,但是這並不適用所有的情況,有時我們不希望在函數里面的一些操作會影響到函數外部的變量。

為了解決這種問題,此時就需要用到拷貝構造函數,拷貝構造函數就是在產生副本對象的時候執行的,在拷貝構造函數里面我們申請一個新的內存空間,

這樣在副本對象執行析構函數時其釋放的就是新的內存空間,從而解決這個問題。

  適用范圍:

1. 一個對象以值傳遞的方式傳入函數體

2. 一個對象以值傳遞的方式從函數返回

3. 一個對象需要通過另外一個對象進行初始化  

  拷貝構造函數不可以改變它所引用的對象,如果可以改變,那么將導致無限循環,如果類中沒有顯示的聲明一個拷貝構造函數,

那么編譯器會為你隱式定義一個位拷貝的默認拷貝構造函數

 

  如果不准備使用按值傳遞對象,那么其實是不需要拷貝構造函數,但是我們如果不寫拷貝構造函數,編譯器又可能為我們創建一個默認的。

那么如何保證一個對象將永遠不會被通過按值傳遞方式傳遞呢?

  聲明一個私有的拷貝構造函數,甚至不必去定義它,除非成員函數或友元函數需要執行按值傳遞方式的傳遞。否則,如果用戶試圖用按值傳遞方式傳遞

或返回對象,編譯器將會報錯。這是因為拷貝構造函數是私有的。因為已經顯示地聲明我們接管了這項工作,所以編譯器不再創建默認的拷貝構造函數


免責聲明!

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



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