您好,登錄后才能下訂單哦!
本篇內容介紹了“C語言運算符的重載實例分析”的有關知識,在實際案例的操作過程中,不少人都會遇到這樣的困境,接下來就讓小編帶領大家學習一下如何處理這些情況吧!希望大家仔細閱讀,能夠學有所成!
我們先討論下面代碼,并復習前面的內容
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可以使用無名函數直接代替將亡值對象,相比可以省一次對象的構建
我們再分析如果我們使用引用返回Add函數
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); }
若我們以引用返回,將亡值對象會創建在Add函數的棧幀中,然后返回將亡值地址,函數return結束該空間會被釋放、
若沒有引用,構建無名對象也就是將亡值對象會構建在主函數的空間中,這里使用將亡值對象值給到c3是沒有問題的
我們查看對象的構造與析構
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修飾,這是因為我們返回將亡值在臨時空間具有常性,所以普通引用是不能進行返回的,需要使用常引用返回
const Complex& Add(const Complex& x)const { return Complex(this->Real + x.Real, this->Image + x.Image); }
我們發現對臨時對象的構建后馬上就進行析構,那么是怎么將數據拿出給到c3的?這個在最后我們進行分析
//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); }
這里是不可以的,加號是一個操作符,不能使用操作放作為有效的函數名稱;但是在C++中為了使這些操作符號能夠當作函數名,那么我們需要在前面加上一個關鍵字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); }
也就是告訴編譯器,加號是一個有效的函數名,這就叫做運算符的重載;隨后我們之間使用 c3 = c1 + c2 就是可以的
int main() { Complex c1(12, 23); Complex c2(4.5, 5.6); Complex c3; c3 = c1 + c2; //編譯器編譯會是下面的情況 //c3 = c1.operator+(c2); //c3 = operator+(&c1,c2); 加上this指針 }
一個對象,編譯器會給它有6個缺省函數
我們再來看下面這個問題
//我們寫一個賦值運算符重載 void operator=(const Object& obj) { this->value = obj.value; } //返回類型為void,這樣不可以就不可以連等 //obja = objb = objc; //obja = objb.operator=(objc); //obja = operator=(&objb,objc); 返回的無類型,不能給obja賦值
且賦值函數不可以定義為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));
通過返回對象,就可以實現連等;并且我們可以通過引用返回,因為此對象的生存期并不受函數的影響,不會產生一個臨時對象作為一個過度
防止自賦值
若是我們將obja給obja賦值,也就是自賦值
obja = obja operator=(&obja,obja);
我們就需要進行一步判斷
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; }
我們在這里希望通過引用返回,這里return的臨時對象會構建在fun函數的棧幀中,并且在函數結束棧幀釋放,隨后調用賦值運算符重載,但是數值依舊是正確的
我們跟蹤這個被析構對象的地址,首先我們定位在fun函數的return obja;
,隨后進入析構函數將我們的obja進行析構
接著運行到回到主函數進行賦值,接著進入賦值運算符重載,可以看到,這里的obj地址與已被析構的obja地址相同
可以看到這個值依舊存在,依舊可以打印給出,這是因為vs2019的特殊性質造成的;我們每次運行程序會發現每次的對象地址都在變化,邏輯地址會隨機改變,被析構對象的棧幀不會被接下來的賦值運算符重載擾亂地址空間,所以即使我們引用返回的對象已經死亡依舊可以將數值正確返回
但是在vc中,我們得到的值會是隨機值,這是因為vc中每次運行程序地址都不會改變,當我們從fun函數退出進入賦值語句中,就會將原本存儲數據的地址擾亂,繼而變成了隨機值
盡管我們引用返回能夠將數據正確打印,但是該對象已經死亡,這是不安全的,所以我們一定不要以引用返回對象
VS2019具有一個特點:當我們調用函數,若函數中沒有定義局部變量或局部對象時,該函數基本不對棧幀進行清掃
“C語言運算符的重載實例分析”的內容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業相關的知識可以關注億速云網站,小編將為大家輸出更多高質量的實用文章!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。