C語言運(yùn)算符的重載詳解
寫一個(gè)Add函數(shù)
我們先討論下面代碼,并復(fù)習(xí)前面的內(nèi)容
class Complex { private: double Real, Image; public: Complex() :Real(0), Image(0) {} Complex(double r, double i) :Real(r), Image(i) {} ~Complex() {} //Complex Add(const Complex* const this,const Complex &c) Complex Add(const Complex& x)const { Complex y; y.Real = Real + x.Real; y.Image = Image + x.Image; return y; //return Complex(this->Real + x.Real, this->Image + x.Image); } void Print() { cout << Real << "+" << Image << "i" << endl; } }; int main() { Complex c1(12, 23); Complex c2(4.5, 5.6); Complex c3; c3 = c1.Add(c2); c3.Print(); return 0; }
直接return可以使用無名函數(shù)直接代替將亡值對(duì)象,相比可以省一次對(duì)象的構(gòu)建
我們?cè)俜治鋈绻覀兪褂?strong>引用返回Add函數(shù)
const Complex& Add(const Complex& x)const { Complex y; y.Real = Real + x.Real; y.Image = Image + x.Image; return y; //return Complex(this->Real + x.Real, this->Image + x.Image); }
若我們以引用返回,將亡值對(duì)象會(huì)創(chuàng)建在Add函數(shù)的棧幀中,然后返回將亡值地址,函數(shù)return結(jié)束該空間會(huì)被釋放、
若沒有引用,構(gòu)建無名對(duì)象也就是將亡值對(duì)象會(huì)構(gòu)建在主函數(shù)的空間中,這里使用將亡值對(duì)象值給到c3是沒有問題的
我們查看對(duì)象的構(gòu)造與析構(gòu)
class Complex { private: double Real, Image; public: Complex() :Real(0), Image(0) {} Complex(double r, double i) :Real(r), Image(i) { cout << "Create:" << this << endl; } Complex(const Complex& x):Real(x.Real),Image(x.Image) { cout << "Copy Create:" << this << endl; } ~Complex() { cout << "~Complex:" << this << endl; } //Complex Add(const Complex* const this,const Complex &c) Complex Add(const Complex& x)const { return Complex(this->Real + x.Real, this->Image + x.Image); } void Print() { cout << Real << "+" << Image << "i" << endl; } }; int main() { Complex c1(12, 23); Complex c2(4.5, 5.6); Complex c3; c3 = c1.Add(c2); c3.Print(); return 0; }
首先我們使用引用返回需要加上const修飾,這是因?yàn)槲覀兎祷貙⑼鲋翟?strong>臨時(shí)空間具有常性,所以普通引用是不能進(jìn)行返回的,需要使用常引用返回
const Complex& Add(const Complex& x)const { return Complex(this->Real + x.Real, this->Image + x.Image); }
我們發(fā)現(xiàn)對(duì)臨時(shí)對(duì)象的構(gòu)建后馬上就進(jìn)行析構(gòu),那么是怎么將數(shù)據(jù)拿出給到c3的?這個(gè)在最后我們進(jìn)行分析
為什么不用加號(hào)作為函數(shù)名
//Complex operator+(const Complex* const this,const Complex &c) Complex operator+(const Complex &c) const { return Complex(this->Real + x.Real, this->Image + x.Image); }
這里是不可以的,加號(hào)是一個(gè)操作符,不能使用操作放作為有效的函數(shù)名稱;但是在C++中為了使這些操作符號(hào)能夠當(dāng)作函數(shù)名,那么我們需要在前面加上一個(gè)關(guān)鍵字operator
//Complex operator+(const Complex* const this,const Complex &c) Complex operator+(const Complex &c) const { return Complex(this->Real + x.Real, this->Image + x.Image); }
也就是告訴編譯器,加號(hào)是一個(gè)有效的函數(shù)名,這就叫做運(yùn)算符的重載;隨后我們之間使用 c3 = c1 + c2 就是可以的
int main() { Complex c1(12, 23); Complex c2(4.5, 5.6); Complex c3; c3 = c1 + c2; //編譯器編譯會(huì)是下面的情況 //c3 = c1.operator+(c2); //c3 = operator+(&c1,c2); 加上this指針 }
運(yùn)算符的重載
一個(gè)對(duì)象,編譯器會(huì)給它有6個(gè)缺省函數(shù)
我們?cè)賮砜聪旅孢@個(gè)問題
//我們寫一個(gè)賦值運(yùn)算符重載 void operator=(const Object& obj) { this->value = obj.value; } //返回類型為void,這樣不可以就不可以連等 //obja = objb = objc; //obja = objb.operator=(objc); //obja = operator=(&objb,objc); 返回的無類型,不能給obja賦值
且賦值函數(shù)不可以定義為const修飾
Object& operator=(const Object& obj) { this->value = obj.value; return *this; }
obja = objb = objc; //改寫 obja = objb.operator=(objc); obja = operator=(&objb,objc); obja.operator=(operator=(&objb,objc)); operator=(&obja,operator=(&objb,objc));
通過返回對(duì)象,就可以實(shí)現(xiàn)連等;并且我們可以通過引用返回,因?yàn)?strong>此對(duì)象的生存期并不受函數(shù)的影響,不會(huì)產(chǎn)生一個(gè)臨時(shí)對(duì)象作為一個(gè)過度
防止自賦值
若是我們將obja給obja賦值,也就是自賦值
obja = obja operator=(&obja,obja);
我們就需要進(jìn)行一步判斷
Object& operator=(const Object& obj) { if(this != &obj)//防止自賦值 { this->value = obj.value; } return *this; }
上面問題解決
我們通過這段代碼來看,與上面問題相同
Object& operator=(const Object& obj) { if (this != &obj) { this->value = obj.value; } return *this; } }; Object& fun(const Object& obj) { int val = obj.Value() + 10; Object obja(val); return obja; } int main() { Object objx(0); Object objy(0); objy = fun(objx); cout << objy.Value() << endl; return 0; }
我們?cè)谶@里希望通過引用返回,這里return的臨時(shí)對(duì)象會(huì)構(gòu)建在fun函數(shù)的棧幀中,并且在函數(shù)結(jié)束棧幀釋放,隨后調(diào)用賦值運(yùn)算符重載,但是數(shù)值依舊是正確的
我們跟蹤這個(gè)被析構(gòu)對(duì)象的地址,首先我們定位在fun函數(shù)的return obja;
,隨后進(jìn)入析構(gòu)函數(shù)將我們的obja進(jìn)行析構(gòu)
接著運(yùn)行到回到主函數(shù)進(jìn)行賦值,接著進(jìn)入賦值運(yùn)算符重載,可以看到,這里的obj地址與已被析構(gòu)的obja地址相同
可以看到這個(gè)值依舊存在,依舊可以打印給出,這是因?yàn)関s2019的特殊性質(zhì)造成的;我們每次運(yùn)行程序會(huì)發(fā)現(xiàn)每次的對(duì)象地址都在變化,邏輯地址會(huì)隨機(jī)改變,被析構(gòu)對(duì)象的棧幀不會(huì)被接下來的賦值運(yùn)算符重載擾亂地址空間,所以即使我們引用返回的對(duì)象已經(jīng)死亡依舊可以將數(shù)值正確返回
但是在vc中,我們得到的值會(huì)是隨機(jī)值,這是因?yàn)関c中每次運(yùn)行程序地址都不會(huì)改變,當(dāng)我們從fun函數(shù)退出進(jìn)入賦值語句中,就會(huì)將原本存儲(chǔ)數(shù)據(jù)的地址擾亂,繼而變成了隨機(jī)值
盡管我們引用返回能夠?qū)?shù)據(jù)正確打印,但是該對(duì)象已經(jīng)死亡,這是不安全的,所以我們一定不要以引用返回對(duì)象
VS2019具有一個(gè)特點(diǎn):當(dāng)我們調(diào)用函數(shù),若函數(shù)中沒有定義局部變量或局部對(duì)象時(shí),該函數(shù)基本不對(duì)棧幀進(jìn)行清掃
總結(jié)
到此這篇關(guān)于C語言運(yùn)算符的重載詳解的文章就介紹到這了,更多相關(guān)C語言運(yùn)算符重載內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
C++實(shí)現(xiàn)簡單的掃雷游戲(控制臺(tái)版)
這篇文章主要為大家詳細(xì)介紹了C++實(shí)現(xiàn)簡單的掃雷游戲,控制臺(tái)版的掃雷游戲希望大家喜歡,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2016-05-05C++實(shí)現(xiàn)線性表順序存儲(chǔ)的示例代碼
這篇文章主要為大家詳細(xì)介紹了C++實(shí)現(xiàn)線性表順序存儲(chǔ)的相關(guān)知識(shí),文中的示例代碼講解詳細(xì),具有一定的學(xué)習(xí)價(jià)值,感興趣的可以了解一下2023-03-03c語言中abs()和fabs()的區(qū)別點(diǎn)整理
在本篇文章里小編給大家分享的是關(guān)于c語言abs()和fabs()的區(qū)別,有需要的朋友們可以參考學(xué)習(xí)下。2020-02-02重啟后nvidia-smi命令不可執(zhí)行出現(xiàn)“Make?sure?that?the?latest?NVIDIA?
這篇文章主要介紹了重啟后nvidia-smi命令不可執(zhí)行,出現(xiàn)“Make?sure?that?the?latest?NVIDIA?driver?is?installed?and?running.”問題,本文給大家分享最新完美解決方法,需要的朋友可以參考下2022-12-12