詳解C++賦值操作符重載
1.賦值操作符重載的原因
賦值操作符是一個使用頻率最高的操作之一,通常情況下它的意義十分明確,就是將兩個同類型的變量的值從一端(右端)傳到另一端(左端)。但在以下兩種情況下,需要對賦值操作符進(jìn)行重載。
一是賦值號兩邊的表達(dá)式類型不一樣,且無法進(jìn)行類型轉(zhuǎn)換。
二是需要進(jìn)行深拷貝。
2. 賦值操作符重載的注意事項
賦值操作符只能通過類的成員函數(shù)的形式重載。這就說明了,如果要將用戶自定義類型的值傳遞給基本數(shù)據(jù)類型的變量,只能通過類型轉(zhuǎn)換機(jī)制,而不能利用重載來實現(xiàn)。
當(dāng)賦值號兩邊的表達(dá)式不一致的時候,可能需要對賦值操作符進(jìn)行重載,見下面的例子。
#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; //符值符號兩邊的數(shù)據(jù)類型不一樣,這里表示創(chuàng)建新對象 a.show(); A a1; a1=1; //賦值號兩邊的數(shù)據(jù)類型不一樣,這是真正的賦值運算 a1.show(); }
程序的輸出結(jié)果是:
5
1
在語句A a=5中,雖然用到了“=”,但它的語義是構(gòu)造一個類A的對象a,它等價于語句A a(5),所以該語句與賦值無關(guān)。而語句a1=1是一個真正的賦值語句,變量a1的類型是A,而常量1的類型是int,由于可以通過類A的構(gòu)造函數(shù)A(int)將類型int轉(zhuǎn)換成類型A(實際上是以int為參數(shù)構(gòu)造了一個類A的臨時對象),然后再完成賦值操作,所以不必再對賦值操作符進(jìn)行重載。
3.深拷貝情況下對賦值操作符重載
深拷貝是對賦值操作符進(jìn)行重載的一個因素。那么什么是深拷貝呢?簡單的說,深拷貝是在把一個類對象a拷貝到另一個對象b中去時,如果對象a中包含非懸掛指針(野指針),那么要將a的指針?biāo)竻^(qū)域的內(nèi)容拷貝到b的相應(yīng)指針?biāo)傅膮^(qū)域中去。進(jìn)行深拷貝時,一般對象a和b有相同的數(shù)據(jù)類型。如果在進(jìn)行賦值時發(fā)生深拷貝,就一定要對賦值操作符進(jìn)行重載,否則賦值運算符就會按賦值的常規(guī)語義進(jìn)行(成員變量之間傳遞數(shù)據(jù)),而不發(fā)生深拷貝。考察如下例子。
#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; }
程序的輸出結(jié)果是:
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,所以,當(dāng)兩個Student類成員之間賦值時,必須使用深拷貝。執(zhí)行s2=s4;語句,就是將s4對象賦值給s2,其中將s4.name字符串的內(nèi)容拷入s2.name就是對深拷貝的具體體現(xiàn)。
(2)類的拷貝構(gòu)造函數(shù)雖然與賦值操作符并不是一回事,但通??梢栽诳截悩?gòu)造函數(shù)中利用賦值操作符重載,以避免對兩個對象之間傳遞數(shù)據(jù)的重復(fù)解釋。
(3)上面的程序,直接使用strcpy(name,s.name);實現(xiàn)兩個對象的字符串成員的數(shù)據(jù)傳遞。這是一種簡化的做法,存在很多隱患。比如如果源字符串的長度超過20個字符,此程序會出現(xiàn)運行時錯誤。解決的辦法是根據(jù)原字符串的長度,重新分配目的字符串的長度,再次之前還要釋放目的字符串的空間。另外,一個對象賦值給自己,也會出現(xiàn)問題,需要進(jìn)行源對象和目的對象地址的比較,再考慮賦不賦值。
(4)由于深拷貝會涉及到內(nèi)存的動態(tài)分配和釋放等一些較為復(fù)雜的操作,所以程序員在編寫自定義類時要盡量避免深拷貝的出現(xiàn)。例如,在上例中,將成員變量name定義成string name,就可以避免自己編寫實現(xiàn)深拷貝的代碼。實際的深拷貝工作是由string類來完成,而string類是C++標(biāo)準(zhǔn)庫提供的,我們可放心使用。
(5)最賦值操作符進(jìn)行重載時,通常將操作符函數(shù)的返回值定義為賦值左操作數(shù)類型的引用。這是為了實現(xiàn)對賦值表達(dá)式的求值,還有一個目的就是為了實現(xiàn)鏈?zhǔn)讲僮鳌?/p>
以上就是詳解C++賦值操作符重載的詳細(xì)內(nèi)容,更多關(guān)于C++賦值操作符重載的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
C++實現(xiàn)leetcode(3.最長無重復(fù)字符的子串)
這篇文章主要介紹了C++實現(xiàn)leetcode(3.最長無重復(fù)字符的子串),本篇文章通過簡要的案例,講解了該項技術(shù)的了解與使用,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下2021-07-07