關(guān)于C++運(yùn)算符重載的一些困惑詳解
一.背景
在復(fù)習(xí)《C++基礎(chǔ)與提高》時(shí),自己實(shí)現(xiàn)運(yùn)算符重載(i++)時(shí),幾次都報(bào)錯(cuò)。其實(shí)還是自己對(duì)運(yùn)算符重載這一部分內(nèi)容理解得不夠透徹,于是再次看了下書(shū)上的內(nèi)容,理解算是加深了一些,于是提筆記錄一下。
環(huán)境:win10,QT4.8
二.概述
這部分內(nèi)容主要關(guān)于在重載函數(shù)中,函數(shù)前要不要加const,何時(shí)加const,返回類(lèi)型要不要加&(引用)修飾,何時(shí)加&(引用)的問(wèn)題,還有臨時(shí)對(duì)象的問(wèn)題。關(guān)于為什么要重載,重載的規(guī)則,友元重載、成員重載的區(qū)別之類(lèi)的知識(shí)點(diǎn),這里就不贅述了。
三.內(nèi)容
以類(lèi)Complex為例
class Complex
{
public:
Complex(double x = 0, double y = 0)
:m_x(x), m_y(y){}
void dis()
{
cout<<"("<<m_x<<", "<<m_y<<")"<<endl;
}
protected:
double m_x;
double m_y;
};
1.以實(shí)現(xiàn)單目運(yùn)算符prefix++和surfix++為例。
先提這個(gè)例子,一是因?yàn)槲以趶?fù)習(xí)這塊時(shí)遇到了一點(diǎn)問(wèn)題,二是這個(gè)有點(diǎn)特別,涉及到啞元的問(wèn)題。
prefixe++
1).考慮基本數(shù)據(jù)類(lèi)型,以int類(lèi)型為例,如下的操作都是可以的;
int a = 1; ++a; ++++a;
2).先實(shí)現(xiàn)基本的語(yǔ)義,代碼如下:
Complex Complex::operator++(void)
{
m_x++;
m_y++;
return *this;
}
3)考慮添加
重載函數(shù)返回的是對(duì)象自身,并且需要修改對(duì)象,我們即可以想到返回的是引用類(lèi)型。注意,此時(shí)引用指向的對(duì)象在重載函數(shù)調(diào)用時(shí)就已經(jīng)存在了。
4)先運(yùn)行一下,看下是否能編譯通過(guò)
++c1;
++++c1;
此時(shí)重載函數(shù)實(shí)現(xiàn)的效果,與基本類(lèi)型效果一致,符合預(yù)期,此時(shí)就不考慮重載函數(shù)前面是否加const修飾了。
#include <iostream>
using namespace std;
class Complex
{
public:
Complex(double x = 0, double y =0)
:m_x(x), m_y(y){}
void dis()
{
cout<<"("<<m_x<<", "<<m_y<<")"<<endl;
}
Complex & operator++(void);
protected:
double m_x;
double m_y;
};
Complex & Complex::operator++(void)
{
m_x++;
m_y++;
return *this;
}
int main()
{
double a = 1.0;
cout<<++a<<endl;
++++a;
cout<<a<<endl;
Complex c1(1.0, 2.0);
Complex cc = ++c1;
cc.dis();
cc = ++++c1; // cc = (c1.operator++()).operator++();
cc.dis();
return 0;
}
結(jié)果如下

surfix++
為了區(qū)分prefix++和surfix++兩個(gè)成員函數(shù),須使用啞元進(jìn)行區(qū)分(引入 啞元,增加了入?yún)⒌姆绞剑谡{(diào)用時(shí)不需要添加任何的參數(shù)),其實(shí)類(lèi)似一個(gè)占位符。
1).考慮基本數(shù)據(jù)類(lèi)型,以int類(lèi)型為例,可以進(jìn)行的操作和不可以進(jìn)行的操作
int b = 1; b++; // 支持 b++++; // 不支持
2).先實(shí)現(xiàn)基本的語(yǔ)義,代碼如下
Complex operator++(int)
{
Complex temp = *this;
m_x++;
m_y++;
return temp;
}
3)考慮添加
可以觀察到,重載函數(shù)返回的是一個(gè)臨時(shí)對(duì)象。若是串聯(lián)調(diào)用,這個(gè)臨時(shí)對(duì)象它又會(huì)調(diào)用一次此重載函數(shù)
c1.operator++(0).operator++(0);
調(diào)用完,然后就消失了。
此時(shí)切不可在返回類(lèi)型中添加&。原因如下:
【不要返回局部對(duì)象的引用或指針】
函數(shù)完成后,它所占用的存儲(chǔ)空間也隨之被釋放掉。因此,函數(shù)終止意味著局部變量的引用將指向不再有效的內(nèi)存區(qū)域。同樣地,函數(shù)終止,局部對(duì)象被釋放,指針將指向一個(gè)不存在的對(duì)象。
4)先運(yùn)行一下,看下是否能編譯通過(guò)
我們會(huì)發(fā)現(xiàn),第34行無(wú)法通過(guò)編譯,但是第42行可以通過(guò)編譯。

5)重載的運(yùn)算符是否會(huì)導(dǎo)致表達(dá)式可以被賦值,應(yīng)該以基礎(chǔ)類(lèi)型為準(zhǔn),如int a, b, c; (a=b)=c;是可以的,而(a+b)=c;是不允許的。返回類(lèi)型通過(guò)加const加以限定來(lái)實(shí)現(xiàn)。
為了使自定義類(lèi)型與基本數(shù)據(jù)類(lèi)型一致,我們?cè)诜祷仡?lèi)型前面加上const。重載函數(shù)中代碼修改為如下
const Complex operator++(int);
修改之后,我們可以看到,第34行和42行均無(wú)法通過(guò)編譯,符合預(yù)期。

2.雙目運(yùn)算符+
1)考慮基本類(lèi)型,以下操作都是支持的
int a1 = 1, a2 = 2, a3 = 3; int m; m = a1+a2; m = a1+(a2+a3); m = (a1+a2)+a3;
2)先重載=,成員函數(shù)如下
Complex & Complex::operator=(const Complex &another)
{
this->m_x = another.m_x;
this->m_y = another.m_y;
return *this;
}
3)再重載運(yùn)算符+,如下:
因?yàn)椴⑽葱薷膫魅氲膮?shù),所以參數(shù)前加了const
Complex Complex::operator+(const Complex &another)
{
return Complex(this->m_x + another.m_x, this->m_y + another.m_y);
}
4)返回類(lèi)型是否需要加const呢?
我們?cè)賹?duì)比下表達(dá)式的賦值情況,第49行,對(duì)于基本類(lèi)型,臨時(shí)對(duì)象被賦值的情況編譯無(wú)法通過(guò),但是第58行,自定義類(lèi)型卻編譯通過(guò)了。此時(shí),為了使其編譯不過(guò),可通過(guò)在返回值類(lèi)型前加const加以限定。

將代碼
Complex Complex::operator+(const Complex &another);
修改為如下:
const Complex Complex::operator+(const Complex &another);
5)此時(shí),發(fā)現(xiàn)第49和58行均無(wú)法通過(guò)編譯,同時(shí)第55行和第57行也編譯不過(guò)了。
這個(gè)是為啥呢?
再仔細(xì)看剛修改的代碼和第57行代碼。重載函數(shù)返回類(lèi)型加了const后,返回的就是const對(duì)象了。第57行代碼,c1 + c2 + c3; c1 + c2返回的是const對(duì)象,而重載函數(shù)是一個(gè)非const函數(shù)。此時(shí),即會(huì)報(bào)錯(cuò)。
在const修飾類(lèi)一節(jié)中,有學(xué)習(xí)過(guò):如果const構(gòu)成函數(shù)重載,const對(duì)象只能調(diào)用const函數(shù),非const對(duì)象優(yōu)先調(diào)用非const函數(shù)。
調(diào)整,在重載函數(shù)后面添加const,如下:
const Complex Complex::operator+(const Complex &another) const;
四.結(jié)尾
學(xué)無(wú)止境,繼續(xù)前行,
參考材料
《C++基礎(chǔ)與提高》 王桂林
《C++ Primer》第5版SB、JL、BE
到此這篇關(guān)于C++運(yùn)算符重載的一些困惑的文章就介紹到這了,更多相關(guān)C++運(yùn)算符重載內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
OpenMP task construct 實(shí)現(xiàn)原理及源碼示例解析
這篇文章主要為大家介紹了OpenMP task construct 實(shí)現(xiàn)原理及源碼示例解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-03-03
QT設(shè)置widget背景圖片不影響widget內(nèi)其他控件背景的方法
這篇文章主要給大家介紹了關(guān)于QT設(shè)置widget背景圖片不影響widget內(nèi)其他控件背景的方法,軟件的界面為了更直觀或美觀,常常需要通過(guò)圖片來(lái)表達(dá),需要的朋友可以參考下2023-06-06
C語(yǔ)言一看就懂的指針與結(jié)構(gòu)體介紹
指針提供了對(duì)地址操作的一種方法,因此,使用指針可使得C語(yǔ)言能夠更高效地實(shí)現(xiàn)對(duì)計(jì)算機(jī)底層硬件的操作。另外,通過(guò)指針可以更便捷地操作數(shù)組。C數(shù)組允許定義可存儲(chǔ)相同類(lèi)型數(shù)據(jù)項(xiàng)的變量,結(jié)構(gòu)是C編程中另一種用戶自定義的可用的數(shù)據(jù)類(lèi)型,它允許您存儲(chǔ)不同類(lèi)型的數(shù)據(jù)項(xiàng)2022-04-04
C語(yǔ)言實(shí)現(xiàn)父進(jìn)程主動(dòng)終止子進(jìn)程的方法總結(jié)
一般的情況,子進(jìn)程自己運(yùn)行完后,執(zhí)行exit 或者return 后,父進(jìn)程wait. waitpid收回子進(jìn)程,但子進(jìn)程是一個(gè)循環(huán)等待狀態(tài)不主動(dòng)退出,父進(jìn)程可以采用文中介紹的幾種方法,需要的朋友可以參考下2023-10-10
Java?C++?算法題解leetcode669修剪二叉搜索樹(shù)示例
這篇文章主要為大家介紹了Java?C++?算法題解leetcode669修剪二叉搜索樹(shù)示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-09-09

