第十七篇:複製控制( 上 ) --- 自定義複製函式

穆晨發表於2017-01-26

前言

  若要將a物件複製給b物件,編譯器應當做何工作?C++初學者也許會直接說” a物件的成員複製給b物件的成員 “。在很多情況下,這種說法正確,事實上C++會給類定義一個預設的複製函式,它所做的工作也正是如此。但,下面問題來了:如果類的成員當中有指標,這種做法還行嗎?本文將對這個問題作出例項分析。

一個典型錯誤示例

  下面這個程式碼示例用來檢驗前言中所提到的問題:

 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;
31 
32     // 設定a1指標成員所指物件的值
33     a1.setNum(1);
34     // 呼叫系統自動合成的複製函式
35     A 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 }

       執行結果:

       

       我們可以觀察到,當類中具有指標成員時,如果使用預設的複製函式,那麼此後當某個物件修改了其指標成員所指物件,那麼該類派生的其他物件的指標成員所指物件也會跟著改變。這顯然不符合程式設計規範,下面我們將提出解決方案。

解決思路

       既然系統自帶的複製函式無法滿足我們的要求,那麼我們可以自定義一個以指定編譯器在複製物件時的操作。

一個正確示例

       下面這個程式碼給出了一個具體解決方案,複製函式啟用時,拷貝指標所指物件,而不是指標本身:

 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     void setNum(int num) {
22         *num_p = num;
23     }    
24     // 獲取指標所指物件
25     int getNum() const {
26         int num = *num_p;
27         return num;
28     }
29 private:
30     int *num_p;
31 };
32 
33 int main()
34 {
35     A a1;
36 
37     // 設定a1指標成員所指物件的值
38     a1.setNum(1);
39     // 呼叫自定義的複製函式
40     A a2=a1;
41     // 觀察得出a1,a2的指標成員所指物件均為整數1。
42     cout << "a1`s num: " << a1.getNum() << endl;
43     cout << "a2`s num: " << a2.getNum() << endl;
44 
45     // 修改a1指標成員所指物件的值
46     a1.setNum(2);
47     // 觀察得出a1的指標成員所指物件改了,a2的沒變。 
48     cout << "a1`s num: " << a1.getNum() << endl; 
49     cout << "a2`s num: " << a2.getNum() << endl;
50 
51     return 0;
52 }

       執行結果:

       

       這一次,兩個物件沒有出現“ 相互干擾 ”了。

說明

       1. 複製函式不單在A a = b的形式下啟用,在作為函式引數傳遞時,生成容器時也會啟用,這點要注意到。

       2. 注意複製函式的原型( 形參為const引用且無返回 )

相關文章