1. 程式人生 > 程式設計 >詳解C++賦值操作符過載

詳解C++賦值操作符過載

1.賦值操作符過載的原因

賦值操作符是一個使用頻率最高的操作之一,通常情況下它的意義十分明確,就是將兩個同類型的變數的值從一端(右端)傳到另一端(左端)。但在以下兩種情況下,需要對賦值操作符進行過載。
一是賦值號兩邊的表示式型別不一樣,且無法進行型別轉換。
二是需要進行深拷貝。

2. 賦值操作符過載的注意事項

賦值操作符只能通過類的成員函式的形式過載。這就說明了,如果要將使用者自定義型別的值傳遞給基本資料型別的變數,只能通過型別轉換機制,而不能利用過載來實現。

當賦值號兩邊的表示式不一致的時候,可能需要對賦值操作符進行過載,見下面的例子。

#include <iostream>
using namespace std;

class A
{
	int num;
public:
	A(){num=0;}
	A(int i){num=i;}
	void show(){
		cout<<num<<endl;
	}
};

int main(int argc,char* argv[])
{
	A a=5;		 //符值符號兩邊的資料型別不一樣,這裡表示建立新物件
	a.show();
	A a1;
	a1=1;    //賦值號兩邊的資料型別不一樣,這是真正的賦值運算
	a1.show();  
}

程式的輸出結果是:

5
1

在語句A a=5中,雖然用到了“=”,但它的語義是構造一個類A的物件a,它等價於語句A a(5),所以該語句與賦值無關。而語句a1=1是一個真正的賦值語句,變數a1的型別是A,而常量1的型別是int,由於可以通過類A的建構函式A(int)將型別int轉換成型別A(實際上是以int為引數構造了一個類A的臨時物件),然後再完成賦值操作,所以不必再對賦值操作符進行過載。

3.深拷貝情況下對賦值操作符過載

深拷貝是對賦值操作符進行過載的一個因素。那麼什麼是深拷貝呢?簡單的說,深拷貝是在把一個類物件a拷貝到另一個物件b中去時,如果物件a中包含非懸掛指標(野指標),那麼要將a的指標所指區域的內容拷貝到b的相應指標所指的區域中去。進行深拷貝時,一般物件a和b有相同的資料型別。如果在進行賦值時發生深拷貝,就一定要對賦值操作符進行過載,否則賦值運算子就會按賦值的常規語義進行(成員變數之間傳遞資料),而不發生深拷貝。考察如下例子。

#include <iostream>
using namespace std;

class Student
{
	char* name;
	int age;
public:
	Student()
	{
		name=new char[20];
	}

	Student(char* n,int a)
	{
		name=new char[20];
		if(name) strcpy(name,n);
		age=a;
	}

	Student(const Student& s)
	{
		name=new char[20];
		*this=s;
	}
	
	void show()
	{
		cout<<"The student's name is "<<name;
		cout<<" and of age "<<age<<endl;
	}

	~Student()
	{
		delete[] name;
	}
	
	Student& operator=(const Student &s)
	{
		if(name) strcpy(name,s.name);
		age=s.age;
		return *this;
	}
};

int main()
{
	Student s1("張三",18),s4("李四",20);
	Student s2;
	s1.show();
	s2=s4;
	s2.show();
	Student s3=s1;
	s3.show();
	return 0;
}

程式的輸出結果是:

The student's name is 張三 and of age 18
The student's name is 李四 and of age 20
The student's name is 張三 and of age 18

閱讀以上程式,注意如下幾點。

(1)由於在類Student中,存在指標成員name,所以,當兩個Student類成員之間賦值時,必須使用深拷貝。執行s2=s4;語句,就是將s4物件賦值給s2,其中將s4.name字串的內容拷入s2.name就是對深拷貝的具體體現。

(2)類的拷貝建構函式雖然與賦值操作符並不是一回事,但通常可以在拷貝建構函式中利用賦值操作符過載,以避免對兩個物件之間傳遞資料的重複解釋。

(3)上面的程式,直接使用strcpy(name,s.name);實現兩個物件的字串成員的資料傳遞。這是一種簡化的做法,存在很多隱患。比如如果源字串的長度超過20個字元,此程式會出現執行時錯誤。解決的辦法是根據原字串的長度,重新分配目的字串的長度,再次之前還要釋放目的字串的空間。另外,一個物件賦值給自己,也會出現問題,需要進行源物件和目的物件地址的比較,再考慮賦不賦值。

(4)由於深拷貝會涉及到記憶體的動態分配和釋放等一些較為複雜的操作,所以程式設計師在編寫自定義類時要儘量避免深拷貝的出現。例如,在上例中,將成員變數name定義成string name,就可以避免自己編寫實現深拷貝的程式碼。實際的深拷貝工作是由string類來完成,而string類是C++標準庫提供的,我們可放心使用。

(5)最賦值操作符進行過載時,通常將操作符函式的返回值定義為賦值左運算元型別的引用。這是為了實現對賦值表示式的求值,還有一個目的就是為了實現鏈式操作。

以上就是詳解C++賦值操作符過載的詳細內容,更多關於C++賦值操作符過載的資料請關注我們其它相關文章!