第十八篇:复制控制( 中 ) --- 重载赋值运算符

前言

       先思考一下上一篇随笔前言中提出的问题。请问:仅仅自定义了复制函数就可以避免带有指针成员的同类对象相互干扰吗?很遗憾,还不够。请思考以下情形( 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 }

       运行结果:

       

小结

       自定义了复制函数的类,往往也需要重载赋值运算符

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