網(wǎng)站首頁 編程語言 正文
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); }
類非常簡單,下面我們要討論如何寫一個(gè)Add函數(shù),使得兩個(gè)對象的屬性相加,返回一個(gè)新的對象。
第一種:
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)建了一個(gè)對象(第3行)。并且函數(shù)類型是值傳遞類型(第6行),返回的是一個(gè)將亡值對象。那么整個(gè)Add函數(shù)空間會產(chǎn)生兩個(gè)對象,造成空間的浪費(fèi)。
第二中代碼創(chuàng)建的是無名對象,減少了一個(gè)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)報(bào)錯(cuò),不能返回引用對象:
我們進(jìn)行分析:
問題4:我們能否將這個(gè)Add函數(shù)名改為 + 運(yùn)算符?
//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)榧犹枴? ... }
這樣使用,編譯器又會報(bào)錯(cuò),操作符不可作為一個(gè)有效的函數(shù)名來被使用。
問題5:如何使 +預(yù)算符 作為函數(shù)名使用?
這就引出了今天的關(guān)鍵,函數(shù)運(yùn)算符重載。
在C++中,為了使操作符作為一個(gè)有效的函數(shù)名,我們在操作符前面添加一個(gè)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; //上面一行實(shí)際上是 //c3 = c1.operator+ (c2); //c3 = operator+(&c1,c2); //編譯器還會經(jīng)過一次編譯 }
前面幾篇博客已經(jīng)分析了第15行的由來,是將c1的地址傳遞給this指針,將c2作為形參c的別名傳遞給函數(shù)。
2、類中自動建立的函數(shù)
在C++中,如果我們定義一個(gè)類,它會給我們自動創(chuàng)建六個(gè)缺省函數(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標(biāo)準(zhǔn)下,又增添了兩個(gè)缺省函數(shù),這里不做深究:
移動構(gòu)造函數(shù)移動賦值函數(shù)
3、重載賦值運(yùn)算符解析
回到最初的例子:
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行添加一個(gè)等號運(yùn)算符重載函數(shù): void operator=(const Object& obj)
此處不可添加const修飾this指針,因?yàn)樾枰褂胻his指針作為左值被修改。
問題6:void operator=(const Object& obj) 只能用于 obja = objb,為什么不可以這樣使用 obja = objb = objc;
我們逐一分析:
obja = objb = objc; //當(dāng)調(diào)用等號運(yùn)算符函數(shù)的時(shí)候。 obja = objb.operator = (objc); obja = operator = (&objb,objc); //如果此處是調(diào)用的是 void operator=(const Object& obj) ; //等號從右向左指向,我們不能把一個(gè)void 類型賦給一個(gè)obja對象類型。
我們將賦值運(yùn)算符進(jìn)行再次重載,丟棄 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指針和形參引用進(jìn)行判斷。
Object &operator=(const Object &obj) { if(this != &obj) { this->value = obj.value } }
問題8:為什么函數(shù)是在棧區(qū)構(gòu)建的,以引用返回打印的不是一個(gè)隨機(jī)值?
運(yùn)行程序,VS2012中,打印的是一個(gè)隨機(jī)值。
VS2019打印的是一個(gè)正常值。
c));
> 問題7:如果遇到obja = obja這種情況,如何賦值呢? > > 回答:對this指針和形參引用進(jìn)行判斷。 ```cpp Object &operator=(const Object &obj) { if(this != &obj) { this->value = obj.value } }
問題8:為什么函數(shù)是在棧區(qū)構(gòu)建的,以引用返回打印的不是一個(gè)隨機(jī)值?
運(yùn)行程序,VS2012中,打印的是一個(gè)隨機(jī)值。
VS2019打印的是一個(gè)正常值。
在WIN10系統(tǒng)中,VS2019與操作系統(tǒng)完全結(jié)合,安全性更高。當(dāng)程序多次運(yùn)行的時(shí)候,它的邏輯地址都不一樣,這樣做的好處是:當(dāng)病毒入侵時(shí),由于程序的邏輯地址是變化的,病毒不好尋找入侵的入口。
總結(jié)
原文鏈接:https://blog.csdn.net/weixin_46401837/article/details/122555466
相關(guān)推薦
- 2022-12-13 python字典如何獲取最大和最小value對應(yīng)的key_python
- 2022-08-25 詳解C語言中結(jié)構(gòu)體的使用_C 語言
- 2023-01-17 Qt中控件的函數(shù)使用教程分享_C 語言
- 2022-10-25 在PyCharm中使用FMEObjects的操作步驟_python
- 2022-09-07 redis?protocol通信協(xié)議及使用詳解_Redis
- 2022-07-26 注冊bean有多少種方式
- 2022-06-06 Ubuntu系統(tǒng)-FFmpeg安裝及環(huán)境配置
- 2022-07-30 RocketMQ消息過濾是如何實(shí)現(xiàn)的?
- 最近更新
-
- 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錯(cuò)誤: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)程分支