第十八篇:複製控制( 中 ) --- 過載賦值運算子

穆晨發表於2017-01-26

前言

       先思考一下上一篇隨筆前言中提出的問題。請問:僅僅自定義了複製函式就可以避免帶有指標成員的同類物件相互干擾嗎?很遺憾,還不夠。請思考以下情形( A中依然帶有指標成員 ):A a1; A a2; a1 = a2; 在最後一句執行時,複製函式並不會啟用( 這種情況啟用的是預設的賦值運算子 ),因此上篇隨筆提到的問題( 物件相互干擾 )依然會發生。為此,我們還得再過載賦值運算子,才能徹底避免這種衝突干擾現象。

又一個典型錯誤示例

 1 #include <iostream>
 2 #include <cstdlib>
 3 #include <fstream>
 4 #include <string>
 5 
 6 using namespace std;
 7 
 8 class A {
 9 public:
10     // 建構函式為指標成員開闢空間並賦初值0
11     A() {
12         num_p = new int;
13         *num_p = 0;
14     }
15     // 給指標所指物件賦值
16     void setNum(int num) {
17         *num_p = num;
18     }    
19     // 獲取指標所指物件
20     int getNum() const {
21         int num = *num_p;
22         return num;
23     }
24 private:
25     int *num_p;
26 };
27 
28 int main()
29 {
30     A a1, a2;
31 
32     // 設定a1指標成員所指物件的值
33     a1.setNum(1);
34     // 呼叫系統預設的賦值運算子
35     a2 = a1;
36     // 觀察得出a1,a2的指標成員所指物件均為整數1。
37     cout << "a1`s num: " << a1.getNum() << endl;
38     cout << "a2`s num: " << a2.getNum() << endl;
39 
40     // 修改a1指標成員所指物件的值
41     a1.setNum(2);
42     // 觀察得出不單a1的指標成員所指物件改了,a2的也跟著變了。 
43     cout << "a1`s num: " << a1.getNum() << endl; 
44     cout << "a2`s num: " << a2.getNum() << endl;
45 
46     return 0;
47 }

       執行結果:

       

       我們可以觀察到“ 干擾 ”現象又發生了,這是由於上第35行程式碼執行時,啟用了系統預設賦值運算子,它會將a1指標成員本身拷貝到a2。

解決思路

       既然預設的賦值運算子無法滿足我們的要求,那麼我們可以自定義一個以指定編譯器在複製物件時的操作。

對【上篇隨筆解決方案】的改進

       下面的程式碼對【上篇隨筆的解決方案】增加了自定義的賦值符,賦值運算子啟用時,拷貝指標所指物件,而不是指標本身,這樣才真正解決了這個問題:

 1 #include <iostream>
 2 #include <cstdlib>
 3 #include <fstream>
 4 #include <string>
 5 
 6 using namespace std;
 7 
 8 class A {
 9 public:
10     // 建構函式為指標成員開闢空間並賦初值0
11     A() {
12         num_p = new int;
13         *num_p = 0;
14     }
15     // 自定義複製函式 
16     A(const A & a) {
17         num_p = new int;
18         *num_p = a.getNum();
19     }
20     // 自定義賦值運算子號
21     A & operator=(const A & a) {
22         num_p = new int;
23         *num_p = a.getNum();
24     }
25     // 給指標所指物件賦值
26     void setNum(int num) {
27         *num_p = num;
28     }    
29     // 獲取指標所指物件
30     int getNum() const {
31         int num = *num_p;
32         return num;
33     }
34 private:
35     int *num_p;
36 };
37 
38 int main()
39 {
40     A a1, a3;
41 
42     // 設定a1指標成員所指物件的值
43     a1.setNum(1);
44     // 呼叫自定義的複製函式
45     A a2=a1;
46     // 啟用自定義的賦值運算子
47     a3 = a1;
48     // 觀察得出a1,a2, a3的指標成員所指物件均為整數1。
49     cout << "a1`s num: " << a1.getNum() << endl;
50     cout << "a2`s num: " << a2.getNum() << endl;
51     cout << "a3`s num: " << a3.getNum() << endl;
52 
53     // 修改a1指標成員所指物件的值
54     a1.setNum(2);
55     // 觀察得出a1的指標成員所指物件改了,a2, a3的沒變。 
56     cout << "a1`s num: " << a1.getNum() << endl; 
57     cout << "a2`s num: " << a2.getNum() << endl;
58     cout << "a3`s num: " << a3.getNum() << endl;
59 
60 
61     return 0;
62 }

       執行結果:

       

小結

       自定義了複製函式的類,往往也需要過載賦值運算子

相關文章