第十七篇:复制控制( 上 ) --- 自定义复制函数

前言

  若要将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引用且无返回 )

posted @ 2017-01-26 22:50  穆晨  阅读(259)  评论(0编辑  收藏  举报