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