做網(wǎng)站公司排名電話國(guó)際新聞快報(bào)
前言:
在上文我們知道數(shù)據(jù)類型分為自定義類型和內(nèi)置類型,當(dāng)我想用內(nèi)置類型比較大小是非常容易的但是在C++中成員變量都是在類(自定義類型)里面的,那我想給類比較大小那該怎么辦呢?這時(shí)候運(yùn)算符重載就出現(xiàn)了
一 運(yùn)算符重載概念:
允許用戶為自定義類定義或重新定義運(yùn)算符的行為,使這些類在使用運(yùn)算符時(shí)表現(xiàn)得像內(nèi)置數(shù)據(jù)類型一樣,從而提高代碼的可讀性和簡(jiǎn)潔性。
1.2 運(yùn)算符重載與函數(shù)重載的區(qū)別:
我第一次聽(tīng)到這兩個(gè)重載都傻傻的分不清楚,以為是一個(gè)意思。其實(shí)他們的區(qū)別可大了
函數(shù)重載:
函數(shù)重載是指在同一作用域中有多個(gè)同名函數(shù),但它們的參數(shù)列表(參數(shù)的類型和數(shù)量)不同。編譯器通過(guò)參數(shù)列表來(lái)決定調(diào)用哪個(gè)函數(shù)。函數(shù)重載的目的是為了提高代碼的可讀性和靈活性,使同一操作可以應(yīng)用于不同類型的參數(shù)。
運(yùn)算符重載:
運(yùn)算符重載允許我們?yōu)橛脩舳x的類型(如類)定義或重新定義特定運(yùn)算符(如 +、-、*、/ 等)的行為。運(yùn)算符重載函數(shù)的名稱為 operator
后跟運(yùn)算符符號(hào)。盡管這些函數(shù)的返回類型和參數(shù)列表與普通函數(shù)類似,但它們的目的是使自定義類型能夠使用像內(nèi)置類型一樣的運(yùn)算符。
1.3?運(yùn)算符特點(diǎn):
1 定義運(yùn)算符重載函數(shù):運(yùn)算符重載是通過(guò)定義特殊的成員函數(shù)或全局函數(shù)來(lái)實(shí)現(xiàn)的
2 運(yùn)算符重載函數(shù)的返回類型:通常是運(yùn)算符操作后的結(jié)果類型。
3 運(yùn)算符重載函數(shù)的參數(shù):根據(jù)運(yùn)算符的類型,參數(shù)可以是一個(gè)或多個(gè)。
4??*
?::
?sizeof
??:
?.
?注意以上5個(gè)運(yùn)算符不能重載
3.1 代碼解析:
運(yùn)算符重載成員函數(shù)代碼示例:
//成員函數(shù) 運(yùn)算符重載
class Date
{
public:int _x = 5;int _y = 4;int operator+(const Date& b){return this->_x + b._x + this->_y + b._y;}//錯(cuò)誤寫法//int operator+(const Date& a , const Date& b)/*{return a.x + b.x + a.y + b.y;}*/
};
int main()
{//成員函數(shù) 運(yùn)算符重載Date d1;Date d2;int sum = d1 + d2;std::cout << "d1 d2總和:" << sum << std::endl;return 0;
}
錯(cuò)誤寫法分析:
因?yàn)樗荄ate類里面的成員函數(shù) 又因?yàn)槌蓡T函數(shù)會(huì)自帶一個(gè)隱含的this指針?biāo)猿蓡T函數(shù)版本的 operator+
只能有一個(gè)顯式參數(shù)。如果需要兩個(gè)參數(shù),則應(yīng)使用全局函數(shù)版本的運(yùn)算符重載。
//全局函數(shù) 運(yùn)算符重載
class Point
{
public://默認(rèn)構(gòu)造函數(shù)Point(){this->_x = 5;this->_y = 15;}
//private:int _x;int _y;
};
bool operator==(const Point& b, const Point& a)
{return (b._x == a._x) && (b._y == a._y);
}int main()
{Point f1;Point f2;int B = f1 == f2;std::cout << "1相同 0相否:" << B << std::endl;return 0;
}
全局函數(shù)的運(yùn)算符重載是在類外部實(shí)現(xiàn)的,不屬于任何類,因此沒(méi)有 this
指針。全局函數(shù)可以通過(guò)參數(shù)訪問(wèn)所有操作數(shù)。
假如我把成員函數(shù)變成私有的話那在全局函數(shù)里面就找不到他們了所以想改變就只能把運(yùn)算符變量改為成員函數(shù)或者用友元函數(shù)或getter方法。
二 賦值運(yùn)算符重載概念:
賦值運(yùn)算符重載用于定義對(duì)象之間的賦值操作,即如何將一個(gè)對(duì)象的值賦給另一個(gè)對(duì)象。賦值運(yùn)算符是 =
,它在賦值時(shí)被調(diào)用。通常我們需要重載賦值運(yùn)算符來(lái)處理深拷貝,以防止淺拷貝帶來(lái)的問(wèn)題。
2.1 賦值運(yùn)算符重載和拷貝構(gòu)造的區(qū)別:
通過(guò)賦值運(yùn)算符重載的概念我們知道它主要的功能是將一個(gè)對(duì)象的值賦給另一個(gè)對(duì)象,而這和拷貝構(gòu)造又非常相似,然而賦值運(yùn)算符重載與運(yùn)算符重載只有兩字相差卻又是不同的內(nèi)容,這就讓我很想知道他們之間的區(qū)別到底是什么,接下來(lái)讓我們一起來(lái)解密吧!
概念:
1. 賦值運(yùn)算符重載
定義對(duì)象之間的賦值操作,即如何將一個(gè)對(duì)象的值賦給另一個(gè)對(duì)象。
2. 運(yùn)算符重載:
定義或重新定義自定義類型的運(yùn)算符行為,使其與內(nèi)置類型的運(yùn)算符行為一致。
3. 拷貝構(gòu)造:
創(chuàng)建一個(gè)新的對(duì)象,并將其初始化為現(xiàn)有對(duì)象的副本。
區(qū)別:
拷貝構(gòu)造函數(shù)和賦值運(yùn)算符重載的主要區(qū)別在于它們的使用場(chǎng)景和目的??截悩?gòu)造函數(shù)在對(duì)象創(chuàng)建時(shí)用于初始化新對(duì)象,目的是創(chuàng)建一個(gè)新的副本。賦值運(yùn)算符重載在對(duì)象已存在時(shí)用于賦值操作,目的是修改現(xiàn)有對(duì)象的狀態(tài),使其與另一個(gè)對(duì)象的狀態(tài)相同??截悩?gòu)造函數(shù)通常接收一個(gè)對(duì)同類對(duì)象的常引用,而賦值運(yùn)算符重載通常返回對(duì)象的引用,并接收一個(gè)對(duì)同類對(duì)象的常引用作為參數(shù)。而運(yùn)算符重載和賦值運(yùn)算符重載也真是差了兩個(gè)字而已,并沒(méi)有什么區(qū)別。
2.1.0 代碼解析:
//賦值運(yùn)算符重載
class Date1
{
public://默認(rèn)構(gòu)造函數(shù)Date1(int year = 2005, int month = 5, int date = 25){this->_year = year;this->_month = month;this->_date = date;}//拷貝構(gòu)造函數(shù)Date1(const Date1& other){this->_year = other._year;this->_month = other._month;this->_date= other._date;}//賦值運(yùn)算符重載Date1 operator=(const Date1& d){this->_year = d._year;this->_month = d._month;this->_date = d._date;return *this;}//輸出void print(){std::cout << _year << "-" << _month << "-" << _date << std::endl;}private:int _year;int _month;int _date;
};int main()
{//構(gòu)造函數(shù)Date1 q1(2024 , 7 , 12);Date1 q2(2021 , 6 , 26);//拷貝構(gòu)造Date1 q3(q2);//賦值運(yùn)算符重載Date1 q4;q4 = q1;//輸出q1.print();q2.print();q3.print();q4.print();return 0;
}
從上面代碼可以知道q3是在被創(chuàng)建的時(shí)候就直接被調(diào)用拷貝構(gòu)造初始化而q4是先定義好之后在被調(diào)用賦值運(yùn)算符重載初始化的。
那既然賦值運(yùn)算符重載就是對(duì)象之間的賦值那和C語(yǔ)言中的賦值整體意思還是一樣的但就是賦值的對(duì)象變了,我不知道大家是否還記得在C語(yǔ)言中可以連續(xù)賦值,讓我們來(lái)試試在C++中的賦值運(yùn)算符重載是否也可以實(shí)現(xiàn)呢?
#include <iostream>
class Date
{
public:int _year, _month, _day;Date(int year = 2005, int month = 5, int day = 25){this->_year = year;this->_month = month;this->_day = day;}// 賦值運(yùn)算符重載Date& operator=(const Date& d) {// 自賦值檢查if (this != &d) { _year = d._year;_month = d._month;_day = d._day;}return *this; // 返回當(dāng)前對(duì)象的引用}void Print(){std::cout << _year << "-" << _month << "-" << _day << std::endl;}
};int main() {Date d1(2023, 7, 10);Date d2;Date d3;// 鏈?zhǔn)劫x值d3 = d2 = d1;d1.Print(); d2.Print(); d3.Print(); return 0;
}
輸出:
雖然輸出的結(jié)果確實(shí)是鏈?zhǔn)降怯钟蟹浅6嗟囊苫蟊热鐬槭裁匆獋?this 還有執(zhí)行順序是什么……
讓我們?cè)敿?xì)的來(lái)解答一下:
首先d2傳給隱函數(shù)this指針然后d1傳給?Date& d那這時(shí)d1就是d的引用了,執(zhí)行到下面就是判斷成員變量的地址是否相同(最開(kāi)始它們之間的地址還是不一樣的)跳出循環(huán)之后就返回*this即d2的引用返回值類型??Date& (這個(gè)我之前一直沒(méi)看到所以就很困惑)
2.2 默認(rèn)賦值運(yùn)算符重載:
編譯器生成的默認(rèn)賦值運(yùn)算符重載也和默認(rèn)構(gòu)造函數(shù)中分自定義和內(nèi)置類型那它與默認(rèn)構(gòu)造函數(shù)有什么區(qū)別,讓我們一探究竟吧
內(nèi)置類型:
概念:編譯器生成的默認(rèn)賦值運(yùn)算符會(huì)直接逐字節(jié)拷貝內(nèi)置類型成員變量的值。
代碼演示:
//默認(rèn)賦值運(yùn)算符重載(內(nèi)置類型)
class Date1
{
public://默認(rèn)構(gòu)造函數(shù)Date1(int year = 2005, int month = 5, int date = 25){this->_year = year;this->_month = month;this->_date = date;}void print(){std::cout << _year << "-" << _month << "-" << _date << std::endl;}private:int _year;int _month;int _date;
};int main()
{Date1 q1(2024 , 7 , 12);Date1 q5;q5 = q1;q5.print();return 0;
}
輸出:
就如上圖所示,我并沒(méi)有寫賦值運(yùn)算符重載但是它卻給我打印出和q1對(duì)象中的成員變量一樣的值,所以我們可以得出結(jié)論編譯器生成的默認(rèn)賦值運(yùn)算符會(huì)直接逐字節(jié)拷貝內(nèi)置類型成員變量的值。俗稱淺拷貝。
自定義類型:
代碼演示:
//默認(rèn)賦值運(yùn)算符重載(自定義類型)
class Date2
{
public:// 賦值運(yùn)算符重載Date2& operator=(const Date2& d){if (this != &d) { // 自我賦值檢查_(kāi)a = d._a;}return *this;}private:int _a = 10;
};class Date3
{
public:// 默認(rèn)構(gòu)造函數(shù)Date3(int year = 2005, int month = 5, int date = 25){this->_year = year;this->_month = month;this->date = date;}void print(){std::cout << _year << "-" << _month << "-" << _date << std::endl;}private:int _year;int _month;int _date;Date2 c; // 包含 Date2 類型的成員變量
};int main()
{Date3 q1(2024, 7, 12);Date3 q5;q5 = q1; // 使用編譯器生成的默認(rèn)賦值運(yùn)算符q5.print();return 0;
}
輸出:
如圖所示編譯器生成的默認(rèn)賦值運(yùn)算符會(huì)調(diào)用自定義類型的賦值運(yùn)算符重載。