網(wǎng)站首頁 編程語言 正文
重載運算符時返回值為類的對象或者返回對象的引用
最終的目的是為了進行連續(xù)的運算
a = b + c + d; //不只是兩個對象相加,是為了兩個以上的對象的相加
以上面的代碼為例,假設a,b,c,d都是同一個類(classA)的不同對象,假如我重載這個類的加號時,返回值類型不是此類或者他的引用,如下
void operator+(classA &a, classA &b)
{
?? ?//加法運算
}
那么在我最上面的代碼中,b + c 的值就為空(或者其他類型),那么這個得出來的值就沒有辦法繼續(xù)和d來進行加法的運算,也沒有辦法賦值給a了,這也就無法實現(xiàn)我所期望的連續(xù)運算的目的。
所以,c++重載運算符時返回值為類的對象是為了實現(xiàn)連續(xù)的運算(大多數(shù)這種運算其實是賦值運算或者<< >>)
如果你以后要重載運算符,有什么連續(xù)運算的需要,就可以使用這種方法,不過最好也要遵守c++中一些語法的規(guī)定,不要重載出來的東西讓人摸不著頭腦
那么,現(xiàn)在講為什么有一些函數(shù)要返回對象的引用,這其實是為了提高程序的運行效率,眾所周知,當一個函數(shù)返回一個值時,他并不是將你在此函數(shù)里面原有的你想要的那個值返回,而是將你想要的那個值,復制一下,然后把這個復制出來的值給返回,如下
classA operator+(classA &a, classA &b)
{
?? ?classA temp;
?? ?//加法運算
?? ?return temp;
}
代碼最終返回的并不是你在函數(shù)里定義的那個temp,而是將temp復制了一份,將復制的那份返回了,函數(shù)里定義的那個temp在函數(shù)運行結(jié)束后就釋放了。
同理,就算你沒有在函數(shù)里面新建東西,而是直接返回通過a和b運算出來的一些東西(或者你直接返回*this),他也要復制一下。
所以,只要你不采用返回類的對象,而是返回類的對象的引用,就不會復制,也即不會調(diào)用類的復制構(gòu)造函數(shù),也即提升了程序的效率
classA & operator+(classA &a, classA &b)
{
?? ?//加法運算
?? ?//a.time = a.time + b.time; //假設time是此類的一個屬性
?? ?//return a;
?? ?//加法只有這樣可以實現(xiàn)連續(xù)的運算,有些雞肋,但是=,<<,>>,就很好用了
}
所以,當你重載的運算符需要連續(xù)的運算時,你可以返回他的類的對象。如果你想要減少不必要的開銷(復制構(gòu)造函數(shù)),提高程序效率,并且你返回的對象是需要作為左值的話,那么你可以返回他的引用
不過絕大部分 返回對象 或者 他的引用 實現(xiàn)連續(xù)運算,都是用在重載 賦值運算符= 或者 插入運算符<< 或者 提取運算符>> 中的。
那里面比較好用,其他的如加法那些,連續(xù)運算就很雞肋,也比較難實現(xiàn),但是返回引用可以提升效率卻是真真的好啊
關于運算符重載中返回值的坑及解決
相信不少朋友在學習運算符重載的時候,都會被參數(shù)與返回值應該是左值引用,還是右值引用,還是const常量所困擾。當然我無法一一枚舉,這次先講一下返回值的坑 (沒錯就是我親手寫的bug)
E0334 “Myclass” 沒有適當?shù)膹椭茦?gòu)造函數(shù)
其實這個問題的根源是,沒有定義常量參數(shù)類型的拷貝構(gòu)造函數(shù)所致
先來看看代碼
//頭文件head.h
class Myclass
{
private:
int a;
public:
Myclass(int b=0):a(b) {} //構(gòu)造函數(shù)
Myclass(Myclass& c); //復制構(gòu)造函數(shù)
~Myclass(){} //析構(gòu)函數(shù)
Myclass operator+(Myclass& d); //重載+運算符
friend ostream& operator<<(ostream& os ,const Myclass& d);
//重載<<運算符
};
//以下是定義
Myclass::Myclass(Myclass& c)
{
a = c.a;
}
Myclass Myclass::operator+(Myclass& d)
{
return Myclass(d.a+a); //!!此處報錯
}
ostream& operator<<(ostream& os,const Myclass& d)
{
os << d.a << std::endl;
return os;
}
//main.cpp
#include"head.h"
int main()
{
Myclass a1(5);
Myclass a2(12);
Myclass sum = a1 + a2; //!!此處報錯
std::cout << sum;
}
代碼在VS中,又出現(xiàn)了令人討厭的小紅線,沒有適當?shù)膹椭茦?gòu)造函數(shù),這就有疑問了, 不是明明有個構(gòu)造函數(shù)Myclass(int b=0):a(b) {}嗎,參數(shù)是int很合適啊?
于是,我們定義一個臨時變量temp,再將它返回,此時會隱式調(diào)用拷貝構(gòu)造函數(shù)而后返回一個副本后原來的temp就die了,因此返回值不可以是引用。
下面是代碼
Myclass Myclass::operator+(Myclass& d)
{
Myclass temp(d.a + a);
return temp;
}
此時第一處報錯消失了,但是第二處報錯依然存在,而且仍為 “沒有適當?shù)膹椭茦?gòu)造函數(shù)”,這就說明了,我的入手方向應該是拷貝構(gòu)造函數(shù)
經(jīng)過博主的調(diào)試,得知是因為函數(shù)的返回值是一個純右值,為了驗證這個想法,使用了右值引用,來接收這個純右值(當然,右值引用更多的是用在移動構(gòu)造函數(shù)上,將 將亡值“偷”出來)
#include"head.h"
int main()
{
Myclass a1(5);
Myclass a2(12);
Myclass&& sum = a1 + a2;
}
果然,它不報錯了
但是考慮到實用性,總不能讓用戶今后做個加法都要用右值引用接收吧,因此,我們要從源頭解決,即重載拷貝構(gòu)造函數(shù)。
值得思考的是,右值不就是被賦值的那個嗎,為什么用Myclass&& sum = a1 + a2;無法賦值呢?眾所周知,Myclass&& sum = a1 + a2;調(diào)用的是拷貝構(gòu)造函數(shù),類不同于基本數(shù)據(jù)類型,它要通過程序員來
設置一系列的功能,我們沒有設置接受,Myclass類型的右值的功能,只定義了接受int類型的右值的功能,這自然是不行的了。
因此,重載拷貝構(gòu)造函數(shù)
Myclass::Myclass(const Myclass& c)
{
a = c.a;
}
此時就能運行了
E0349 沒有與這些操作數(shù)匹配的 “<<” 運算符
關于流運算符為什么要寫成$ostream& operator<<(ostream& os,const Myclass& d); 而非ostream& operator<<(ostream& os,Myclass& d);這個問題,網(wǎng)上絕大部分的回答都是輸出沒必要修改值。
那么我們先定義后者
#head.h
#pragma once
#include<iostream>
using std::ostream;
class Myclass
{
private:
int a;
public:
Myclass(int b=0):a(b) {}
Myclass(Myclass& c);
Myclass(const Myclass& c);
~Myclass(){}
Myclass operator+(Myclass& d);
friend ostream& operator<<(ostream& os ,Myclass& d);
};
Myclass::Myclass(const Myclass& c)
{
a = c.a;
}
Myclass::Myclass(Myclass& c)
{
a = c.a;
}
Myclass Myclass::operator+(Myclass& d)
{
Myclass temp(d.a + a);
return temp;
}
ostream& operator<<(ostream& os,Myclass& d)
{
os << d.a << std::endl;
return os;
}
#main.cpp
#include"head.h"
int main()
{
Myclass a1(5);
Myclass a2(12);
Myclass&& sum = a1 + a2;
std::cout << a1 + a2; //此處有討厭小紅線
}
不難發(fā)現(xiàn),討厭的小紅線又出來了。
我們可以想象一下這個過程,a1.operator+(a2),返回了個臨時變量,暫且假設它叫newguy,那么newguy為一個右值,又調(diào)用了函數(shù)os.<<(&d),傳參為&d=newguy,現(xiàn)在問題來了,左值引用怎么能夠接受一個純右值呢? 而我們定義的重載的流運算符接受的參數(shù)類型為左值,我們并沒有給出從左值到右值強制類型轉(zhuǎn)換的函數(shù),但是在上一部分,我們給出了從右值到左值的拷貝構(gòu)造函數(shù),因此,將流運算符聲明為前者更好。
C3861 “function”: 找不到標識符
這個問題應該是非常常見的,不習慣將函數(shù)(或是類)先聲明后定義而又喜歡讓函數(shù)(或是類)相互調(diào)用,但是在類模板它比以上兩種更為隱蔽。
#include<iostream>
class A
{
friend void show(); //“聲明”函數(shù)
friend void show1(); //“聲明”函數(shù)
};
void show() //定義
{
show1();
}
void show1(){} //定義
int main()
{
A a;
show(); //調(diào)用
show1(); //調(diào)用
}
以上流程看似聲明->定義->調(diào)用非常完美,實則還是會報錯的,不過跟以上兩種不一樣的是,它是在linking的時候出錯,這是為什么呢?
原來友元函數(shù)并不屬于這個類的一部分,在類內(nèi)定義僅僅是為了告訴編譯器“這個函數(shù)是這個類的友元函數(shù)”,并沒有對這個函數(shù)本身進行聲明,因此,正確的做法應該是這樣的:
#include<iostream>
void show();
void show1();
class A
{
friend void show();
friend void show1();
};
void show()
{
show1();
}
void show1(){}
int main()
{
A a;
show();
show1();
}
Summary
本文主要講了三點。
首先,要注意將拷貝構(gòu)造函數(shù)重載。
其次,要將流運算符<<的參數(shù)類型確定為(ostream&,const myclass&),當然,istream則萬萬不可const,ostream是沒有拷貝構(gòu)造函數(shù)的,因此引用也是必須的。
最后,類內(nèi)友元函數(shù)的聲明,并不等同于函數(shù)本身的聲明。
原文鏈接:https://blog.csdn.net/Jegret/article/details/107745237
相關推薦
- 2022-01-15 cURL error 60: SSL certificate problem: unable to
- 2022-09-27 Android內(nèi)置的OkHttp用法介紹_Android
- 2022-06-14 golang并發(fā)安全及讀寫互斥鎖的示例分析_Golang
- 2022-09-09 C#正則表達式與HashTable詳解_C#教程
- 2022-02-09 深入了解C++異常處理_C 語言
- 2023-03-16 python中split()函數(shù)的用法詳解_python
- 2022-05-04 C#異步編程由淺入深(三)之詳解Awaiter_C#教程
- 2021-12-10 redis服務器cpu100%的原因和解決方案
- 最近更新
-
- window11 系統(tǒng)安裝 yarn
- 超詳細win安裝深度學習環(huán)境2025年最新版(
- Linux 中運行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎操作-- 運算符,流程控制 Flo
- 1. Int 和Integer 的區(qū)別,Jav
- spring @retryable不生效的一種
- Spring Security之認證信息的處理
- Spring Security之認證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權
- redisson分布式鎖中waittime的設
- maven:解決release錯誤:Artif
- restTemplate使用總結(jié)
- Spring Security之安全異常處理
- MybatisPlus優(yōu)雅實現(xiàn)加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務發(fā)現(xiàn)-Nac
- Spring Security之基于HttpR
- Redis 底層數(shù)據(jù)結(jié)構(gòu)-簡單動態(tài)字符串(SD
- arthas操作spring被代理目標對象命令
- Spring中的單例模式應用詳解
- 聊聊消息隊列,發(fā)送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠程分支