為什麽復制構造函數的參數需要加const和引用
為什麽復制構造函數的參數需要加const和引用
一.引言
1.0在解答這個問題之前,我們先跑個小程序,看下調用關系。
1 #include <iostream>
2 using namespace std;
3 class CExample
4 {
5 public:
6 CExample(int x) :m_nTest(x) //帶參數構造函數
7 {
8 cout<< "constructor with argument."<<endl;
9 }
10 CExample(const CExample & ex) // 拷貝構造函數
11 {
12 m_nTest = ex.m_nTest;
13 cout << "copy constructor."<<endl;
14 }
15 CExample& operator = (const CExample &ex)//賦值函數(賦值運算符重載)
16 {
17 cout << "assignment operator." << endl;
18 m_nTest = ex.m_nTest;
19 return *this;
20 }
21 void myTestFunc(CExample ex)
22 {
23 }
24 private:
25 int m_nTest;
26 };
27
28 int main()
29 {
30 CExample aaa(2);
31 CExample bbb(3);
32 bbb = aaa;
33 CExample ccc = aaa;
34 bbb.myTestFunc(aaa);
35 system("pause");
36 return 0;
37 }
1.1【輸出結果】
1.2【分析結果】
第一個輸出: constructor with argument. //CExample aaa(2);
這裏創建了變量aaa,在創建的同時還帶有參數2,那就調用帶參數的構造函數
第二個輸出:constructor with argument. //CExample bbb(3);
分析同第一個
第三個輸出:assignment operator. //bbb = aaa;
bbb之前已經創建了,所以這個不會調用構造函數,而只是將aaa賦值給bbb,所以調用賦值函數
第四個輸出:copy constructor. //CExample ccc = aaa;
這個和上一個的區別就在於:bbb之前已經創建過了,而這裏的ccc是在這條語句才創建的,所以這裏是在創建ccc的同時將aaa賦值給ccc,所以這句調用的肯定是構造函數,又因為需要將aaa賦值給ccc,所以調用的是拷貝構造函數。
第五個輸出:copy constructor. // bbb.myTestFunc(aaa);
這裏是調用了一個自己寫的myTestFunc函數,其中這個函數中的參數沒有采用引用,那就是值傳遞的方式。就是編譯器先創建一個類型為CExample名稱為ex的對象,然後將aaa的值傳遞給ex(值傳遞方式的特性),將相當於要執行一條CExample ex = aaa的語句。經第四個輸出的分析可知,這需要調用拷貝構造函數。所以輸出copy constrctor。
二.解答問題
2.1為什麽要用引用?
【錯誤答案】個人第一反應:為了減少一次內存拷貝。
【正確答案】由上節的第五個輸出分析可知,在執行bbb.myTestFunc(aaa);時,其實會調用拷貝構造函數。如果我們的拷貝構造函數的參數不是引用,那麽在bbb.myTestFunc(aaa);時,調用CExample ex = aaa;,又因為ex之前沒有被創建,所以又需要調用拷貝構造函數,故而又執行CExample ex = aaa;,就這樣永遠的遞歸調用下去了。
所以, 拷貝構造函數是必須要帶引用類型的參數的, 而且這也是編譯器強制性要求的。
2.2為什麽要用const?
【正確答案】如果在函數中不會改變引用類型參數的值,加不加const的效果是一樣的。而且不加const,編譯器也不會報錯。但是為了整個程序的安全,還是加上const,防止對引用類型參數值的意外修改。
——如有不對的地方,非常歡迎給予指導!
——【感謝】資料來源於http://blog.csdn.net/tunsanty/article/details/4264738
——【感謝】資料來源於http://blog.csdn.net/sinat_36053757/article/details/70597567
為什麽復制構造函數的參數需要加const和引用