C++中的運算符重載詳解
1、引例
class Complex
{
private:
double Real,Image;
public:
Complex():Real(0),Image(0) {}
Complex(double r, double i) : Real(r),Image(i) {}
~Complex() {}
};
int main()
{
Complex c1(1.2,2.3);
Complex c2(45,56);
Complex c3;
c3 = c1.Add(c2);
}
類非常簡單,下面我們要討論如何寫一個Add函數(shù),使得兩個對象的屬性相加,返回一個新的對象。
第一種:
Complex::Complex Add(const Complex &c)
{
Complex co;
co.Real = this->Real + c.Real;
co.Image = this->Image + c.Image;
return co;
}
問題1:如何寫出最節(jié)省空間的Add函數(shù)?
第二種:
Complex::Complex Add(const Complex &c) const
{
return Complex(c.Real + this->Real, c.Image + this.Image);
}
由于不需要改變調(diào)用對象的屬性值,我們給this指針添加const 修飾。
分析過程如下:

問題2:為什么第一種方式不節(jié)省空間呢?
首先第一種的代碼比較繁瑣,并且在函數(shù)棧幀中又創(chuàng)建了一個對象(第3行)。并且函數(shù)類型是值傳遞類型(第6行),返回的是一個將亡值對象。那么整個Add函數(shù)空間會產(chǎn)生兩個對象,造成空間的浪費。
第二中代碼創(chuàng)建的是無名對象,減少了一個co對象的創(chuàng)建,并且將無名對象直接作為將亡值對象傳遞給main函數(shù)中的c3。
問題3:我們能否將Add函數(shù)改為引用類型,這樣來減少將亡值對象的創(chuàng)建
Complex::Complex &Add(const Complex &c) const
{
return Complex(c.Real + this->Real, c.Image + this.Image);
}
VS2019發(fā)現(xiàn)報錯,不能返回引用對象:

我們進行分析:

問題4:我們能否將這個Add函數(shù)名改為 + 運算符?
//Complex::Complex Add(const Complex &c) const
Complex::Complex +(const Complex &c) const
{
Complex co;
co.Real = this->Real + c.Real;
co.Image = this->Image + c.Image;
return co;
}
int main()
{
...
//c3 = c1.Add(c2);
c3 = c1.+(c2); //將原先Add的地方改變?yōu)榧犹枴?
...
}
這樣使用,編譯器又會報錯,操作符不可作為一個有效的函數(shù)名來被使用。
問題5:如何使 +預算符 作為函數(shù)名使用?
這就引出了今天的關(guān)鍵,函數(shù)運算符重載。
在C++中,為了使操作符作為一個有效的函數(shù)名,我們在操作符前面添加一個operator。
Complex operator+(const Complex &c) const
{
return Complex(c.Real + this->Real,c.Image + this->Image);
}
int main()
{
Complex c1(1.2,2.3);
Complex c2(10,10);
Complex c3;
c3 = c1 + c2;
//上面一行實際上是
//c3 = c1.operator+ (c2);
//c3 = operator+(&c1,c2); //編譯器還會經(jīng)過一次編譯
}
前面幾篇博客已經(jīng)分析了第15行的由來,是將c1的地址傳遞給this指針,將c2作為形參c的別名傳遞給函數(shù)。
2、類中自動建立的函數(shù)
在C++中,如果我們定義一個類,它會給我們自動創(chuàng)建六個缺省函數(shù):
構(gòu)造函數(shù)析構(gòu)函數(shù)拷貝構(gòu)造函數(shù)賦值函數(shù)普通對象的&(取地址符)的重載常對象的&(取地址符)重載
代碼示例如下:
class Object
{
public:
Object() {} //構(gòu)造函數(shù)
~Object() {} //析構(gòu)函數(shù)
Object(const Object &obj) {} //拷貝構(gòu)造函數(shù)
Object &operator=() {const Object &obj} //賦值函數(shù)
{
return *this;
}
Object *operator&() //普通對象的&(取地址符)的重載
{
return this;
}
const Object *operator&() const //常對象的&(取地址符)重載
{
return this;
}
};
然后,在C11標準下,又增添了兩個缺省函數(shù),這里不做深究:
移動構(gòu)造函數(shù)移動賦值函數(shù)
3、重載賦值運算符解析
回到最初的例子:
class Object
{
int value;
public:
Object () {
cout << "create:" << this << endl;
} //普通構(gòu)造函數(shù)
Object (int x = 0):value(x) {cout << "create:" << this << endl;} //缺省構(gòu)造函數(shù)
~Object() //析構(gòu)函數(shù)
{
cout << "~Objcet() " << this << endl;
}
Object(Object &obj):value(obj.value)
{
cout << "Copy create:" << this << endl;
}
int & Value()
{
return value;
}
const int &Value() const
{
return value;
}
Object &operator=(const Object& obj) //此處加引用
{
this->value = obj.value;
return *this; //this指針指向objb的地址。賦值函數(shù)結(jié)束后,objb不會被消亡,所以可以以引用返回
}
void operator=(const Object& obj) //賦值語句不可給this指針加const
{
this->value = obj.value;
}
};
int main()
{
Object objx(0);
Object objy(0);
objy = fun(objx);
cout << objy.Value() << endl;
return 0;
}
我們在34行添加一個等號運算符重載函數(shù): void operator=(const Object& obj)
此處不可添加const修飾this指針,因為需要使用this指針作為左值被修改。
問題6:void operator=(const Object& obj) 只能用于 obja = objb,為什么不可以這樣使用 obja = objb = objc;
我們逐一分析:
obja = objb = objc; //當調(diào)用等號運算符函數(shù)的時候。 obja = objb.operator = (objc); obja = operator = (&objb,objc); //如果此處是調(diào)用的是 void operator=(const Object& obj) ; //等號從右向左指向,我們不能把一個void 類型賦給一個obja對象類型。
我們將賦值運算符進行再次重載,丟棄 void 版本:
Object &operator=(const Object& obj) //此處加引用
{
this->value = obj.value;
return *this; //this指針指向objb的地址。賦值函數(shù)結(jié)束后,objb不會被消亡,所以可以以引用返回
}
這樣就可以使用了。
我們接著上次的深入分析:
obja.operator=(operator=(&objb,objc)); operator=(&obja,operator=(&objb,objc));
問題7:如果遇到obja = obja這種情況,如何賦值呢?
回答:對this指針和形參引用進行判斷。
Object &operator=(const Object &obj)
{
if(this != &obj)
{
this->value = obj.value
}
}
問題8:為什么函數(shù)是在棧區(qū)構(gòu)建的,以引用返回打印的不是一個隨機值?
運行程序,VS2012中,打印的是一個隨機值。
VS2019打印的是一個正常值。
c));
> 問題7:如果遇到obja = obja這種情況,如何賦值呢?
>
> 回答:對this指針和形參引用進行判斷。
```cpp
Object &operator=(const Object &obj)
{
if(this != &obj)
{
this->value = obj.value
}
}
問題8:為什么函數(shù)是在棧區(qū)構(gòu)建的,以引用返回打印的不是一個隨機值?
運行程序,VS2012中,打印的是一個隨機值。
VS2019打印的是一個正常值。
在WIN10系統(tǒng)中,VS2019與操作系統(tǒng)完全結(jié)合,安全性更高。當程序多次運行的時候,它的邏輯地址都不一樣,這樣做的好處是:當病毒入侵時,由于程序的邏輯地址是變化的,病毒不好尋找入侵的入口。
總結(jié)
到此這篇關(guān)于C++中的運算符重載詳解的文章就介紹到這了,更多相關(guān)C++運算符重載內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
C語言數(shù)據(jù)結(jié)構(gòu)的時間復雜度和空間復雜度
算法在編寫成可執(zhí)行程序后,運行時需要耗費時間資源和空間(內(nèi)存)資源 。因此衡量一個算法的好壞,一般是從時間和空間兩個維度來衡量的,即時間復雜度和空間復雜度,感興趣的同學可以參考閱讀2023-04-04

