程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> 關於C++ >> 為什麼要在operator=中返回"*this"的引用

為什麼要在operator=中返回"*this"的引用

編輯:關於C++

[問題的提出]:

在很多書籍和文章中,很多次提到在對賦值操作符(=)進行重載的時候,要返回對目的(調用)對象實例(*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; 有什麼不同?

水平有限,歡迎大家批評指正!

本文配套源碼

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved