網(wǎng)站首頁 編程語言 正文
運(yùn)算符重載
C++語法設(shè)計(jì)很巧妙,比如運(yùn)算符重載一個 >
bool operator>(const Date& d)
{
return !(*this <= d);
}
這里可以結(jié)合前面的內(nèi)聯(lián)函數(shù)來進(jìn)一步提高代碼的效率,而內(nèi)聯(lián)函數(shù)不支持 .h 和 .cpp 分開寫,所以成員函數(shù)要成為內(nèi)聯(lián)函數(shù)最好的辦法就是把定義放在類里面,類里面定義的會被默認(rèn)為是 inline 內(nèi)聯(lián)函數(shù)。
我們計(jì)算日期類的加法時:
Date Date::operator+(int d)
{
Date ret(*this);
ret.day += d;
while (ret.day > Getmonth(ret.year, ret.month))
{
ret.day -= Getmonth(ret.year,ret.month);
ret.month++;
if (ret.month == 13)
{
ret.year += 1;
ret.month = 1;
}
}
return ret;
}
運(yùn)算符復(fù)用
我們可能會有這樣的問題,這里面 += 和 + 兩個運(yùn)算符其實(shí)是一樣的,實(shí)現(xiàn)原理上沒什么差別,那你可能會封裝個函數(shù)來解決他們的關(guān)系,但是其實(shí)直接讓他倆互相附庸,分為了 += 復(fù)用+ 和 + 復(fù)用 += 兩種辦法:
1.+= 復(fù)用 +:
2.+ 復(fù)用 +=(更優(yōu)):
兩種乍一看其實(shí)沒什么區(qū)別,但是其實(shí)有優(yōu)越和劣勢可以分的,很 += 是不需要構(gòu)造的,因?yàn)樗莻饕谜{(diào)用(返回值為域外的 this 指針的內(nèi)容,必須要傳引用),但是 + 是必須要構(gòu)造的,拷貝局部對象的 ret 和 最后的 return , 一共需要構(gòu)造兩次。
讓 += 復(fù)用 +,+在先就會讓整個過程構(gòu)造 4 次,而讓 + 來復(fù)用 += 的話,+ 還是構(gòu)造 2 次沒得說,但是 += 就不需要拷貝構(gòu)造了,整個過程就只需要構(gòu)造 2 次,消耗就會小很多。咱就應(yīng)該多摳摳細(xì)節(jié),寫出正確的代碼固然重要,但是追求更優(yōu)秀更高效的代碼是每一個程序員的基本素養(yǎng)。
前置后置運(yùn)算符
既然 +,- 能造,那 ++ 和 – 自然也不在話下,但是這就不好玩了啊, num++ 和 ++num 功能上都是 +1,寫成運(yùn)算符重載格式都是
Date Date::operator++();
我們該怎么區(qū)分呢?要知道函數(shù)名相同而參數(shù)不同就應(yīng)該敏感使用函數(shù)重載,C++這個大聰明是不會考慮不到這些的,因此就有了對應(yīng)的語法:前置不帶參數(shù)而后置帶參數(shù)
Date operator++();//前置++
Date operator++(int d);//后置++
Date& operator++()//前置
{
*this += 1;
return *this;
}
Date operator++(int)//后置
{
Date tmp(*this);
*this += 1;
return tem;
}
其實(shí)括號里面這個參數(shù)并沒有任何意義,單純只是用來區(qū)分前置與后置的寫法,所以這里不寫形參也是可以的,我這里就只給了一個類型。還有這里千萬不要想著去加一個缺省值,顯式傳參還好,要是不傳參編譯器就沒辦法區(qū)分開來,屬于是沒事找事了。
const
給一個場景:
void Func(const Date& d)
{
d1.Print();
}
void test()
{
Date d1(2022,5,19);
d1.Print();
Func(d1);
}
這個場景下就會報(bào)錯:
說實(shí)在的,這個報(bào)錯我自己也看的云里霧里,為什么 Print 那里不報(bào)錯到了 Func 里面 Print 就要報(bào)錯?Print 傳的過去 Func 就傳不過去了?究其為什么會報(bào)錯,其實(shí)涉及到一個權(quán)限問題。
void Print(Date* const this)
{
cout<<year<<"-"<<month<<"-"<<day<<endl;
}
我們知道 Print() 的參數(shù)其實(shí)是 Date& const this ,在上面場景中去調(diào)用 Print 時其實(shí)參數(shù)是 &d1,傳對象的地址。在 Print 定義時 const 修飾的是 this 指針,const 修飾的變量可以初始化,此時指針不能被改變但是他指向的內(nèi)容可以被初始化和修改;而 Func 的 const 修飾 Date*,他指向的內(nèi)容不能被修改,所以這是一個經(jīng)典的權(quán)限放大問題。
const Date* 要傳給 Date* ,所以我們需要一個 const 進(jìn)行修飾保護(hù),但是 this 本質(zhì)是一個隱含形參,我們沒辦法顯式調(diào)用,也就是說 const 沒辦法進(jìn)行修飾。那么C++也提供了一種修飾方法打破這個僵局,就是在函數(shù)尾巴加上 const。
void Print() const
{}
尾巴上的 const 編譯器就會默認(rèn)你是加在了函數(shù)原本定義的前面,這樣就完美了。
C++ 的IO流
我們在代碼中使用的 << , >> 為流輸入和流提取操作符,只要涉及輸入或者輸出數(shù)據(jù),我們立馬想到的就是 cin 和 cout,這倆貨其實(shí)是全局的對象, cin 對應(yīng) istream 類,cout 對應(yīng) ostream 類,它們都聲明在 頭文件中,這也解釋了“為什么在 C++ 程序中引入 就可以使用 cin 和 cout”。
我們之所以可以在 <<, >> 之后接上任何類型,是因?yàn)閺?qiáng)大的語法對每種類型進(jìn)行了重載,能自動識別類型的本質(zhì)就是函數(shù)重載,所以如果一個 int 類型的流插入 cin<<1 其實(shí)是 cin . operator <<(1)。
初始化列表
與其他函數(shù)不同,構(gòu)造函數(shù)除了有名字,參數(shù)列表和函數(shù)體之外,還可以有初始化列表,初始化列表以冒號開頭,后跟一系列以逗號分隔的初始化字段,初始化列表可以看成是對象的成員變量定義的地方:
class Func
{
public:
Func(int a):
_a(a){} // 初始化列表
private:
int _a;
};
注意:每個成員變量在初始化列表中只能出現(xiàn)一次因?yàn)槌跏蓟荒艹跏蓟淮危€要明確哪些成員必須放在初始化列表進(jìn)行初始化:
- 引用成員變量
- const 成員變量
- 自義定類型成員(該類沒有默認(rèn)構(gòu)造函數(shù))
其他變量即可以在初始化列表初始化也可以在函數(shù)體內(nèi)初始化,內(nèi)置類型成員不處理時,會調(diào)用默認(rèn)構(gòu)造函數(shù)即隨機(jī)值,如果我給出缺省值,那么之這個值就是給初始化列表用的,如果在初始化列表也同時給出這個內(nèi)置類型的初始化值,就會采用初始化列表的值。我們應(yīng)該盡量在初始化列表就初始化完,這樣能盡可能的減少很多毛病效率也高。
再來看看這個題目:
這個程序的結(jié)果是啥?
答案是 1 和隨機(jī)值,因?yàn)槌蓡T變量在類中的聲明次序就是他在初始化列表中的初始化順序,與他在初始化列表中的先后次序無關(guān)。_a2 先聲明 _a2 = _a1,此時 _a1 為隨機(jī)值,所以 _a2 為隨機(jī)值,_a1 為 1。
explicit 關(guān)鍵字
構(gòu)造函數(shù)不僅可以構(gòu)造和初始化對象,對于單個參數(shù)的構(gòu)造函數(shù),還具有類型轉(zhuǎn)換的作用。在C語言里面我們就知道有隱式類型轉(zhuǎn)換,其實(shí)在 C++ 里面也是一樣的,比如針對我定義的一個 Date(int year):
Date d1(2022);
Date d2 = 2022;
顯然, 這里 d2 需要的是 Date 類型的參數(shù), 而我們傳入的是一個int, 這個程序卻能成功運(yùn)行, 就是因?yàn)檫@隱式調(diào)用,另外說一句, 在對象剛剛定義時, 即使使用的是賦值操作符 = , 也是會調(diào)用構(gòu)造函數(shù), 而不是重載的 operator= 運(yùn)算符。這兩個語句對應(yīng)前者是構(gòu)造,而后者是構(gòu)造+拷貝構(gòu)造,相當(dāng)于發(fā)生了隱式類型轉(zhuǎn)換, 如果我們寫成:
explicit Date(int year)
這個關(guān)鍵字會阻止這種轉(zhuǎn)換的發(fā)生。
原文鏈接:https://blog.csdn.net/qq_61500888/article/details/124858878
相關(guān)推薦
- 2022-07-22 HttpClient如何自定義重試方法
- 2023-05-07 Python3中省略號(...)用法介紹_python
- 2023-10-17 My-form組件,基于element傳參展示用于后臺管理篩選的表單框
- 2022-06-19 微信小程序前端如何調(diào)用python后端的模型詳解_python
- 2022-09-26 C++實(shí)現(xiàn)頁面的緩沖區(qū)管理器_C 語言
- 2023-01-01 Golang反射修改變量值的操作代碼_Golang
- 2023-01-29 Python安裝Talib庫的詳細(xì)圖文教程_python
- 2022-11-11 C++泛型模板約束深入講解_C 語言
- 最近更新
-
- window11 系統(tǒng)安裝 yarn
- 超詳細(xì)win安裝深度學(xué)習(xí)環(huán)境2025年最新版(
- Linux 中運(yùn)行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎(chǔ)操作-- 運(yùn)算符,流程控制 Flo
- 1. Int 和Integer 的區(qū)別,Jav
- spring @retryable不生效的一種
- Spring Security之認(rèn)證信息的處理
- Spring Security之認(rèn)證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權(quán)
- redisson分布式鎖中waittime的設(shè)
- maven:解決release錯誤:Artif
- restTemplate使用總結(jié)
- Spring Security之安全異常處理
- MybatisPlus優(yōu)雅實(shí)現(xiàn)加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務(wù)發(fā)現(xiàn)-Nac
- Spring Security之基于HttpR
- Redis 底層數(shù)據(jù)結(jié)構(gòu)-簡單動態(tài)字符串(SD
- arthas操作spring被代理目標(biāo)對象命令
- Spring中的單例模式應(yīng)用詳解
- 聊聊消息隊(duì)列,發(fā)送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠(yuǎn)程分支