关于C++重载赋值运算符"="的讨论

原文地址:http://www.vckbase.com/index.php/wv/219

[问题的提出]:

在很多书籍和文章中,很多次提到在对赋值操作符(=)进行重载的时候,要返回对目的(调用)对象实例(*this)的引用。其中不免有这样的论断:一定要返回对调用对象的引用;返回对调用实例对象的引用是为了实现链式连续赋值。

这里说明两个问题:第一,是否重载赋值操作符必须返回对调用对象的引用,第二,是否这样就可以实现链式赋值,而不这样就不行。

首先,必须承认,返回对"*this"的引用是标准的二目操作符重载的格式,效率很高。这样做有很多优点:如实现链式赋值、避免临时对象的产生(调用拷贝构造函数)、销毁(调用析构函数),但不是非这样做不可,下面通过对比来论述返回对"*this"的引用的优点及其他做法的缺点,同时也能清楚第二个问题,我们从例子着手。

01. // a.h
02. class 
03. {
04. public:
05. A();
06. A(int nTest);
07. A(const A& a);
08. virtual ~A();
09. A operator=(const A& a);
10. // A& operator=(const A& a);
11.  
12. private:
13. int m_nTest;
14.  
15. public:
16. void printit();
17. };
18.
19.  
20. // a.cpp
21. A::A(int nTest)
22. {
23. m_nTest = nTest;
24. cout << "constructor A Value is executed now!" << endl;
25. }
26.  
27. A::A(const A& a)
28. {
29. this->m_nTest = a.m_nTest;
30. cout << "Copy constructor A is executed now!" << endl; 
31. }
32.  
33. A::A()
34. {
35. cout << "constructor A Default is executed now!" << endl;
36. }
37.  
38. A::~A()
39. {
40. cout << "Destructor A is executed now!" << endl;
41. }
42. A A::operator=(const A& a)
43. // A& A::operator=(const A& a)
44. {
45. if (this==&a) 
46. return *this;
47. this->m_nTest = a.m_nTest;
48. cout << "Assignment A is 
49. executed now!" << endl;
50. return *this;
51. }

在main()函数中调用

1. A a(100),b(99),c(98);
2. a = b = c;
3. a.printit();
4. b.printit();
5. c.printit();

结果为:

constructor A Value is executed now!
constructor A Value is executed now!
constructor A Value is executed now!
Assignment A is executed now!
Copy constructor A is executed now!
Assignment A is executed now!
Copy constructor A is executed now!
Destructor A is executed now!
Destructor A is executed now!
98
98
98
Destructor A is executed now!
Destructor A is executed now!
Destructor A is executed now!

如果将 A operator=(const A& a) 改为 A& operator=(const A& a) 
则结果为:

constructor A Value is executed now!
constructor A Value is executed now!
constructor A Value is executed now!
Assignment A is executed now!
Assignment A is executed now!
98
98
98
Destructor A is executed now!
Destructor A is executed now!
Destructor A is executed now!

两者的不同为前者比后者多执行了两次构造(拷贝构造函数)和析构函数,可见在执行过程充产生了两个临时对象。

[1]在赋值函数为:A operator=(const A& a)的情况下

对于a=b=c; 实际为a.operator=(b.operator=(c))

在执行A operator=(const A& a) 后返回 *this 给一个临时对象,所以生成和销毁这个临时对象的时候分别要调用构造和析构函数,而构造时是用一个已经存在的实例出初始化同类型的实例,所以调用的拷贝初始化函数。析构时,先析构前面一个(a.operator=)产生的临时对象,后析构"b.operator="产生的临时对象.

[2] 在赋值函数为:A& operator=(const A& a)的情况下

不同的是没有临时对象的产生,因为operator=返回的是对当前对象的引用,而引用只是别名,而不是构造新对象的。这点可以通过如下函数调用来理解:

1. void fun(A& temp)
2. {
3. temp ...
4. }
5. A a;

执行fun(a)函数调用时,没有产生临时对象。

可见,重载"="操作符,不一定要返回对赋值目的对象的引用,但返回引用是很好的做法,建议您这样使用。

最后提出几个问题,大家可以思考一下:

[1] 若将a=b=c; 改为(a=b)=c后分别调用A operator=(const A& a) 和A&operator=(const A& a)结果会有什么不同?

[2] 能否将A&operator=(const A& a)改为const A&operator=(const A& a)?

[3] 能否将A&operator=(const A& a)中的return *this;改为return a?

[4] A a, b;

a = b;

与 A a;

A b = a; 有什么不同?

水平有限,欢迎大家批评指正!

经实验,回答思考题:

【1】调用A operator = (const A& a ),结果为

【2】可以。

【3】不能 原因:不能将类型为‘A&’的非 const 引用初始化为类型为‘const A*’的临时变量

【4】

说明:上面为A a,b; a=b的结果;下面为A a; A b = a;的结果。上面分别调用了两次默认构造函数和一次赋值操作;

下面调用一次默认构造函数和一次带参数的构造函数。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值