Chinaunix首页 | 论坛 | 博客
  • 博客访问: 536841
  • 博文数量: 576
  • 博客积分: 40000
  • 博客等级: 大将
  • 技术积分: 5020
  • 用 户 组: 普通用户
  • 注册时间: 2008-10-13 14:47
文章分类

全部博文(576)

文章存档

2011年(1)

2008年(575)

我的朋友

分类:

2008-10-14 15:01:08

为什么要在operator=中返回"*this"的引用
作者:



[问题的提出]:
在很多书籍和文章中,很多次提到在对赋值操作符(=)进行重载的时候,要返回对目的(调用)对象实例(*this)的引用。其中不免有这样的论断:一定要返回对调用对象的引用;返回对调用实例对象的引用是为了实现链式连续赋值。
这里说明两个问题:第一,是否重载赋值操作符必须返回对调用对象的引用,第二,是否这样就可以实现链式赋值,而不这样就不行。
首先,必须承认,返回对"*this"的引用是标准的二目操作符重载的格式,效率很高。这样做有很多优点:如实现链式赋值、避免临时对象的产生(调用拷贝构造函数)、销毁(调用析构函数),但不是非这样做不可,下面通过对比来论述返回对"*this"的引用的优点及其他做法的缺点,同时也能清楚第二个问题,我们从例子着手。

// a.h
class A  
{
public:
A();
	A(int nTest);
	A(const A& a);
	virtual ~A();
	A operator=(const A& a);
	// A& operator=(const A& a);

private:
	int m_nTest;
	
public:
	void printit();
};
}

// a.cpp
A::A(int nTest)
{
	m_nTest = nTest;
	cout << "constructor A Value is executed now!" << endl;
}

A::A(const A& a)
{
	this->m_nTest = a.m_nTest;
	cout << "Copy constructor A is executed now!" << endl;	
}

A::A()
{
	cout << "constructor A Default is executed now!" << endl;
}

A::~A()
{
	cout << "Destructor A is executed now!" << endl;
}
A A::operator=(const A& a)
// A& A::operator=(const A& a)
{
	if (this==&a)  
	return *this;
	this->m_nTest = a.m_nTest;
	cout << "Assignment A is  
executed now!" << endl;
	return *this;
}
在main()函数中调用
A a(100),b(99),c(98);
a = b = c;
a.printit();
b.printit();
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!
99
99
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=返回的是对当前对象的引用,而引用只是别名,而不是构造新对象的。这点可以通过如下函数调用来理解:
void fun(A& temp)
{
temp ...
}
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; 有什么不同?

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


--------------------next---------------------

我同意 xinyue 的结论,A A::operator=(const A& a)
执行过程中是产生临时变量,但this指针已经把a=b=c中a,b的值改变了。 ( xcheng 发表于 2002-11-13 10:22:00)
 
这里的printit()是从何处来的 ( 初学者 发表于 2002-10-11 17:31:00)
 
(1):使用 const A& operator=(const A& a) 不会产生临时对象,只是一个引用别名的使法。 

(2):是的都为98,我用VC测试了

(3):对于返回引用值和传值调用:
  1:(a=b)=c           key:99,99,98;
  2: (a=b)=c           key:98,99,98; ( xinyue 发表于 2002-9-24 15:27:00)
 
我想问一个问题:
  若为const A&operator=(const A& a),生成一临时对象初始化返回的const A&型,此变量与一般同类型的变量的区别是?是否也仅仅是个临时的变量了。
( 入门者 发表于 2002-8-31 23:53:00)
 
对于第一种情况,输出的结果应该都是98呀。
首先,赋值“=”的操作是从右向左的。
另外当operator= 返回 A 时,程序仅仅是多了两次构造和析构,但从赋值的结果来看a、b、c都应该98。 ( moonwolf 发表于 2002-8-24 21:59:00)
 
为什么我在vc6下执行第一种情况的输出都是98? ( ? 发表于 2002-8-21 15:46:00)
 
获益匪浅,终于透彻的清楚了~
谢谢!

( alexjin 发表于 2002-8-21 14:43:00)
 
不错不错 ( 浩 发表于 2002-8-13 20:39:00)
 
谢谢! ( www 发表于 2002-8-12 17:12:00)
 
这篇文章让我加深了理解,谢谢! ( hehe 发表于 2002-8-12 10:25:00)
 
.......................................................

--------------------next---------------------

阅读(401) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~