在C++中, 構造函數,拷貝構造函數,析構函數和賦值函數(賦值運算符重載)是最基本不過的需要掌握的知識。 但是如果我問你“拷貝構造函數的參數爲什麼必須使用引用類型?”這個問題, 你會怎麼回答? 或許你會回答爲了減少一次內存拷貝? 很慚愧的是,我的第一感覺也是這麼回答。不好還好,我有理性這個好品質。思索一下以後,發現這個答案是不對的。讓我來撕開(有點暴力,但是我喜歡,嘿嘿--齜牙)那件隱藏在真理外的小褲衩,讓它袒露在“登徒子”們的眼前吧。
先從一個小例子開始:(自己測試一下自己看看這個程序的輸出是什麼?)
view plaincopy to clipboardprint?
- #include <iostream.h>
- class CExample
- {
- int m_nTest;
- public:
- CExample(int x):m_nTest(x) //帶參數構造函數
- {
- cout << "constructor with argument/n";
- }
- CExample(const CExample & ex) //拷貝構造函數
- {
- m_nTest = ex.m_nTest;
- cout << "copy constructor/n";
- }
- CExample& operator = (const CExample &ex)//賦值函數(賦值運算符重載)
- {
- cout << "assignment operator/n";
- m_nTest = ex.m_nTest;
- return *this;
- }
- void myTestFunc(CExample ex)
- {
- }
- };
- int main()
- {
- CExample aaa(2);
- CExample bbb(3);
- bbb = aaa;
- CExample ccc = aaa;
- bbb.myTestFunc(aaa);
- return 0;
- }
看這個例子的輸出結果:
constructor with argument // CExample aaa(2);
constructor with argument // CExample bbb(3);
assignment operator // bbb = aaa;
copy constructor // CExample ccc = aaa;
copy constructor // bbb.myTestFunc(aaa);
如果你能一眼看出就是這個結果的話, 恭喜你,可以站起來扭扭屁股,不用再往下看了。
如果你的結果和輸出結果有誤差, 那拜託你謙虛的看完。
第一個輸出: constructor with argument // CExample aaa(2);
如果你不理解的話, 找個人把你拖出去痛打一頓,然後嘴裏還喊着“我是二師兄,我是二師兄.......”
第二個輸出:constructor with argument // CExample bbb(3);
分析同第一個
第三個輸出: assignment operator // bbb = aaa;
第四個輸出: copy constructor // CExample ccc = aaa;
這兩個得放到一塊說。 肯定會有人問爲什麼兩個不一致。原因是, bbb對象已經實例化了,不需要構造,此時只是將aaa賦值給bbb,只會調用賦值函數,就這麼簡單,還不懂的話,撞牆去! 但是ccc還沒有實例化,因此調用的是拷貝構造函數,構造出ccc,而不是賦值函數,還不懂的話,我撞牆去!!
第五個輸出: copy constructor // bbb.myTestFunc(aaa);
實際上是aaa作爲參數傳遞給bbb.myTestFunc(CExample ex), 即CExample ex = aaa;和第四個一致的, 所以還是拷貝構造函數,而不是賦值函數, 如果仍然不懂, 我的頭剛纔已經流血了,不要再讓我撞了,你就自己使勁的再裝一次吧。
通過這個例子, 我們來分析一下爲什麼拷貝構造函數的參數只能使用引用類型。
看第四個輸出: copy constructor // CExample ccc = aaa;
構造ccc,實質上是ccc.CExample(aaa); 我們假如拷貝構造函數參數不是引用類型的話, 那麼將使得 ccc.CExample(aaa)變成aaa傳值給ccc.CExample(CExample ex),即CExample ex = aaa,因爲 ex 沒有被初始化, 所以 CExample ex = aaa 繼續調用拷貝構造函數,接下來的是構造ex,也就是 ex.CExample(aaa),必然又會有aaa傳給CExample(CExample ex), 即 CExample ex = aaa;那麼又會觸發拷貝構造函數,就這下永遠的遞歸下去。
所以繞了那麼大的彎子,就是想說明拷貝構造函數的參數使用引用類型不是爲了減少一次內存拷貝, 而是避免拷貝構造函數無限制的遞歸下去。
所以, 拷貝構造函數是必須要帶引用類型的參數的, 而且這也是編譯器強制性要求的