目錄
我們先討論下面**,並複習前面的內容
class complex
complex(double r, double i) :real(r), image(i) {}
~complex() {}
//complex add(const complex* this,const complex &c)
complex add(const complex& x)const
void print() };
int main()
直接return可以使用無名函式直接代替將亡值物件,相比可以省一次物件的構建
我們再分析如果我們使用引用返回add函式
const complex& add(const complex& x)const
若我們以引用返回,將亡值物件會建立在add函式的棧幀中,然後返回將亡值位址,函式return結束該空間會被釋放、
若沒有引用,構建無名物件也就是將亡值物件會構建在主函式的空間中,這裡使用將亡值物件值給到c3是沒有問題的
我們檢視物件的構造與析構
class complex
complex(double r, double i) :real(r), im
complex(const complex& x):real(x.real),image(x.image)
~complex()
//complex add(const complex* const this,const complex &c)
complex add(const complex& x)const
void print() };
int main()
首先我們使用引用返回需要加上const修飾,這是因為我們返回將亡值在臨時空間具有常性,所以普通引用是不能進行返回的,需要使用常引用返回
const complex& add(const complex& x)const
我們發現對臨時物件的構建後馬上就進行析構,那麼是怎麼將資料拿出給到c3的?這個在最後我們進行分析
//complex operator+(const complex* const this,const complex &c)
complex operator+(const complex &c) const
這裡是不可以的,加號是乙個操作符,不能使用操作放作為有效的函式名稱;但是在c++中為了使這些操作符號能夠當作函式名,那麼我們需要在前面加上乙個關鍵字operator
//complex operator+(const complex* const this,const complex &c)
complex operator+(const complex &c) const
也就是告訴編譯器,加號是乙個有效的函式名,這就叫做運算子的過載;隨後我們之間使用 c3 = c1 + c2 就是可以的int main()
乙個物件,編譯器會給它有6個預設函式
我們再來看下面這個問題
//我們寫乙個賦值運算子過載
void operator=(const object& obj)
//返回型別為void,這樣不可以就不可以連等
//obja = objb = objc;
//obja = objb.operator=(objc);
//obja = operator=(&objb,objc); 返回的無型別,不能給obja賦值
且賦值函式不可以定義為const修飾
object& operator=(const object& obj)
obja = objb = objc;
//改寫
obja = objb.operator=(objc);
obja = operator=(&objb,objc);
obja.operator=(operator=(&objb,objc));
operator=(&obja,operator=(&objb,objc));
通過返回物件,就可以實現連等;並且我們可以通過引用返回,因為此物件的生存期並不受函式的影響,不會產生乙個臨時物件作為乙個過度
防止自賦值
若是我們將obja給obja賦值,也就是自賦值
obja = obja
operator=(&obja,obja);
我們就需要進行一步判斷
object& operator=(const object& obj)
return *this;
}我們通過這段**來看,與上面問題相同
object& operator=(const object& obj)
return *this;
}};object& fun(const object& obj)
int main()
我們在這裡希望通過引用返回,這裡return的臨時物件會構建在fun函式的棧幀中,並且在函式結束棧幀釋放,隨後呼叫賦值運算子過載,但是數值依舊是正確的
我們跟蹤這個被析構物件的位址,首先我們定位在fun函式的return obja;,隨後進入析構函式將我們的obja進行析構
接著執行到回到主函式進行賦值,接著進入賦值運算子過載,可以看到,這裡的obj位址與已被析構的obja位址相同
可以看到這個值依舊存在,依舊可以列印給出,這是因為vs2019的特殊性質造成的;我們每次執行程式會發現每次的物件位址都在變化,邏輯位址會隨機改變,被析構物件的棧幀不會被接下來的賦值運算子過載擾亂位址空間,所以即使我們引用返回的物件已經死亡依舊可以將數值正確返回
但是在vc中,我們得到的值會是隨機值,這是因為vc中每次執行程式位址都不會改變,當我們從fun函式退出進入賦值語句中,就會將原本儲存資料的位址擾亂,繼而變成了隨機值
儘管我們引用返回能夠將資料正確列印,但是該物件已經死亡,這是不安全的,所以我們一定不要以引用返回物件
vs2019具有乙個特點:當我們呼叫函式,若函式中沒有定義區域性變數或區域性物件時,該函式基本不對棧幀進行清掃
C 運算子過載詳解
1.運算子過載定義 c 中預定義的運算子的操作物件只能是基本資料型別。但實際上,對於許多使用者自定義型別 例如類 也需要類似的運算操作。這時就必須在c 中重新定義這些運算子,賦予已有運算子新的功能,使它能夠用於特定型別執行特定的操作。運算子過載的實質是函式過載,它提供了c 的可擴充套件性,也是c 最...
C 運算子過載詳解
list item過載運算子需要使用運算子函式,其宣告格式為operatorop argument list 要求op必須是c 的有效運算子,且不能是.等 1 過載後的運算子至少有乙個引數為自定義型別 2 使用運算子時不能違反運算子原來的句法規則,不能修改運算子的優先順序,不能建立新的運算子 3 不...
運算子過載詳解
1.運算子過載定義 c 中預定義的運算子的操作物件只能是基本資料型別。但實際上,對於許多使用者自定義型別 例如類 也需要類似的運算操作。這時就必須在c 中重新定義這些運算子,賦予已有運算子新的功能,使它能夠用於特定型別執行特定的操作。運算子過載的實質是函式過載,它提供了c 的可擴充套件性,也是c 最...