把參數傳遞給函數有三種方法,一種是傳值,一種是傳地址,一種是傳引用。傳值與其餘兩種方式不一樣的地方在於 當使用函數
傳值方式的時候,會在函數裏面生成傳遞參數的一個副本,這個副本的內容是按位從原始參數那裏複製過來的,二者的內容是相同的。spa
當原始參數是一個類的對象時,它也會產生一個對象的副本,此時須要注意:通常對象在建立時都會調用構造函數來進行初始化,可是指針
在產生對象的副本時若是再執行對象的構造函數,那麼這個對象的屬性又再恢復到原始狀態,這就不是咱們但願的了。因此在產生對象對象
副本的時候,構造函數不會被執行,被執行的是一個默認的默認的拷貝構造函數。內存
問題緣由: 編譯器
當函數執行完畢要返回的時候對象副本會執行析構函數,編譯
若是你的析構函數是空的話,也不會發生什麼問題,但通常的析構函數都是要完成一些清理工做,如釋放指針所指向的內存空間,這時候變量
可能就會出問題。 譬如:咱們在構造函數中爲一個指針變量分配了內存,在析構函數中釋放給這個指針所指向的內存空間,在把對象傳遞循環
給函數至函數結束返回 的這個過程當中 首先有一個對象的副本產生了。這個副本也有一個指針,它和原始對象的指針是指向同塊內存空間的,構造函數
函數返回時,副本對象的析構函數執行了,釋放了副本對象中指針指向的內存空間,可是這個內存空間對於原始對象而言仍是有效地,
這是第一個問題,後面當原始對象也被銷燬的時候,原始對象的析構函數執行,還會對那塊已經釋放掉的內存空間再次釋放,產生嚴重
錯誤,這是第二個問題。
解決方法:
既然傳值有這樣的問題,那是否可使用傳地址或者傳引用的方式解決這種問題呢?
事實上傳地址和傳引用確實能夠解決這種問題,可是這並不適用全部的狀況,有時咱們不但願在函數裏面的一些操做會影響到函數外部的變量。
爲了解決這種問題,此時就須要用到拷貝構造函數,拷貝構造函數就是在產生副本對象的時候執行的,在拷貝構造函數裏面咱們申請一個新的內存空間,
這樣在副本對象執行析構函數時其釋放的就是新的內存空間,從而解決這個問題。
適用範圍:
1. 一個對象以值傳遞的方式傳入函數體
2. 一個對象以值傳遞的方式從函數返回
3. 一個對象須要經過另一個對象進行初始化
拷貝構造函數不能夠改變它所引用的對象,若是能夠改變,那麼將致使無限循環,若是類中沒有顯示的聲明一個拷貝構造函數,
那麼編譯器會爲你隱式定義一個位拷貝的默認拷貝構造函數
若是不許備使用按值傳遞對象,那麼實際上是不須要拷貝構造函數,可是咱們若是不寫拷貝構造函數,編譯器又可能爲咱們建立一個默認的。
那麼如何保證一個對象將永遠不會被經過按值傳遞方式傳遞呢?
聲明一個私有的拷貝構造函數,甚至沒必要去定義它,除非成員函數或友元函數須要執行按值傳遞方式的傳遞。不然,若是用戶試圖用按值傳遞方式傳遞
或返回對象,編譯器將會報錯。這是由於拷貝構造函數是私有的。由於已經顯示地聲明咱們接管了這項工做,因此編譯器再也不建立默認的拷貝構造函數