C++中的構造函數,拷貝構造函數和賦值運算
關于C++中的構造函數,拷貝構造函數和賦值運算,以前看過一篇《高質量C++/C編程指南》的文章中介紹的很清楚,網上能搜索到,如果想詳細了解這方面的知識可以參看一下這篇文章。
常見的給對象賦值方式有構造函數,拷貝構造函數,賦值運算符這三種方法,如下代碼演示了這幾種常見的方法。
A a1;
A a2(a1);
A a3 = a1;
a3 = a2;
如果不手動寫代碼,C++編譯器默認提供了構造函數,拷貝構造函數,賦值運算符的這三種方法的默認實現。
默認構造函數沒有參數,它什么也不做,程序員如果要實現手動構造的話則需要編寫相應的重載版本。前面代碼的第一行就是通過默認構造函數來創建一個對象,一般也不會和其它幾種構造方式混淆,和C#,Java等其它語言也是一樣的,還比較容易掌握。
而拷貝構造函數和賦值運算符則是C++獨有的,也是很多人所不熟悉的地方。構造函數和拷貝構造函數用于從一個對象復制出另一個對象。系統提供的默認拷貝構造函數和賦值運算的工作方式是內存拷貝,也就是淺拷貝。如果對象中用到了需要手動釋放的對象,則會出現問題,這時就要手動重載這兩個函數,實現深拷貝。
拷貝構造函數和賦值運算的重載聲明如下:
A (const A& other)
A& operator = (const A& other)
要實現這兩個函數,我們必須知道這幾個基本信息
- 什么時候會調用
- 輸入參數代表什么
- 函數體應該如何實現
- 返回值代表什么
1. 什么時候會調用
首先我們來看這兩個函數什么時候會調用,對于上面代碼的2-4行。
- 第二行:A a2(a1); 這個很明顯調用的是拷貝構造函數
- 第四行:a3 = a2 這個很明顯調用的是賦值運算
- 第三行:A a3 = a1; 這個就沒其它幾個那么好懂了,看起來即像是調用拷貝構造函數創建一個對象,又像是調用賦值運算復制一個對象,還是兩個都調了? 實際上,這個調用的是拷貝構造函數,和第二行的方式是等價的。
對于第三行的 A a3 = a1; 這種方式,我們如何去理解它呢?實際上有一個很好記的統一的大原則:從無到有是調用構造函數,從有到有調用的是賦值運算。基于這個原則,前面四行代碼哪個是調用哪個函數就很好區分了。
2. 輸入參數代表什么
拷貝構造函數和賦值運算函數都一個入參,這個入參很明顯是待復制的數據源對象,簡單講就是括號里面的,= 號右邊的。
從拷貝構造函數和賦值運算函數的聲名形式來看,它是一個const型的,說明復制的過程中不應該修改源對象。當然,如果定義為const型的也能編過去,就是用起來沒那么好用罷了(可以參看后面的effective C++ 條款15鏈接)。
3. 函數體應該如何實現
拷貝構造函數和賦值運算的功能一樣,都是根據已有的對象復制出新對象。它們擁有同樣的入參,實現的功能也應該是一樣的。
按照c++的設計原則,重載了一個就應該重載另一個,并且有相同的實現,否則這種不一致性很容易導致程序出問題。
至于復制過程如何實現,關于如何實現對象深拷貝的網上有許多文章詳細的講解了這一過程,這個也是c程序員的基本技能。由于篇幅所限這里就不多介紹了。我的一般方法就是:先實現位拷貝,然后在對動態申請對象編碼實現深拷貝。
4. 返回值代表什么
拷貝構造函數沒有返回值,這個很好理解。但賦值運算有一個返回值就不那么容易理解了,數據復制操作時在函數運算體內就已經完成了,還要一個返回值干嘛,返回到外面有什么用?
最初我也認為這個函數返回值設計為void型更容易理解,后來才知道返回值主要是為了實現類似w = x = y = z = 0的連等,不過連等這個編程習慣本身就不大好。
最后再看看應該如何返回,其實直接返回個return *this; 就可以了,至于為什么不用其它的方式,還是看看權威的解釋吧(鏈接失效的話直接google搜索標題):effective C++ 條款15: 讓operator=返回*this的引用。
RFID管理系統集成商 RFID中間件 條碼系統中間層 物聯網軟件集成