c++中有些重載運算符為什麼要返回引用?
1. c++中有些重載運算符為什麼要返回引用,單單為了避免析構再構造嗎?
2. 在此情況下,返回值為NULL或類似情況怎麼辦?3. 返回的引用賦給一個變數後,那個變數是不是引用?怎麼理解?4. 據說返回局部對象的引用非常危險,請問返回引用到底有什麼作用?,難道輸入輸出流返回的不是局部對象的引用?
謝邀,我嘗試一個個地解答。
1. c++中有些重載運算符為什麼要返回引用,單單為了避免析構再構造嗎?
不是。「有些」重載運算符要返回的引用,是為了返回它本身。如class TestClass {
private:
int number;
public:
TestClass operator+=(const TestClass rhs) {
number += rhs.number;
return *this;
}
};
上例是一個C++的不完整的簡單類,其中+=運算符,它本身的意義是「自增,並返回自增後的值」,所以就要返回自己,而不是返回一個自己的拷貝。
2. 在此情況下,返回值為NULL或類似情況怎麼辦?
引用不可為空,樓主所說的情況不存在。3. 返回的引用賦給一個變數後,那個變數是不是引用?怎麼理解?#include &
using namespace std;
class StupidClass {
int flag;
public:
StupidClass(int flag): flag(flag) {
cout &<&< "Constructor " &<&< flag &<&< endl;
}
~StupidClass() {
cout &<&< "Destructor " &<&< flag &<&< endl;
}
StupidClass(const StupidClass rhs) {
cout &<&< "Copy Constructor *this=" &<&< flag &<&< " rhs=" &<&< rhs.flag &<&< endl;
}
StupidClass operator=(const StupidClass rhs) {
cout &<&< "Operator = *this=" &<&< flag &<&< " rhs=" &<&< rhs.flag &<&< endl;
return *this;
}
StupidClass operator+=(const StupidClass rhs) {
cout &<&< "Operator += *this=" &<&< flag &<&< " rhs=" &<&< rhs.flag &<&< endl;
flag += rhs.flag;
return *this;
}
};
int main() {
StupidClass var1(1), var2(2);
StupidClass var3 = var1 += var2;
return 0;
}
輸出是
Constructor 1
Constructor 2
Operator += *this=1 rhs=2
Copy Constructor *this=3 rhs=3
Destructor 3
Destructor 2
Destructor 3
所以結果就是先執行var1 += var2,然後使用得來的var1對var3拷貝構造。其中var1中的flag變成3了(看後面兩個Destructor 3,和Copy Constructor *this=3 rhs=3)。
如果把var3的類型改成StupidClass,那麼輸出就變成Constructor 1
Constructor 2
Operator += *this=1 rhs=2
Destructor 2
Destructor 1
那麼var3就是var1的引用了。
4. 據說返回局部對象的引用非常危險,請問返回引用到底有什麼作用?,難道輸入輸出流返回的不是局部對象的引用?
輸入輸出流重載的是 &<&< 和 &>&> 運算符,一般是這樣寫的ostream operator&<&<(ostream os, const TestClass rhs) {
os &<&< rhs.number;
return os;
}
這裡面沒有返回局部對象的引用啊,所謂返回局部對象的引用是像這樣的
int func() {
int dummy = 1;
return dummy;
}
在這裡dummy就是一個「局部對象」。
先回答第一個問題:C++的有些重載運算符為什麼要返回引用?
事實上我們的重載運算符返回void 、返回對象本身、返回對象引用都是可以的,並不是說一定要返回一個引用,只不過在不同的情況下需要不同的返回值
那麼我們什麼情況下要返回對象的引用呢?
原因有兩個:①允許進行連續賦值②防止返回對象(返回對象也可以進行連續賦值)的時候調用拷貝構造函數和析構函數導致不必要的開銷,降低賦值運算符等的效率。
對於第二點原因:如果用「值傳遞」的方式,雖然功能仍然正確,但由於return語句要把 *this拷貝到保存返回值的外部存儲單元之中,增加了不必要的開銷,會降低賦值函數的效率。
場景一:需要返回對象引用或者返回對象(效率沒有返回引用高),需要實現連續賦值,使重載的運算符更符合C++本身的運算符的語意,=連續賦值, += -= *= /= &<&<輸出流 先討論兩個例子: 1:關於賦值 =,我們知道賦值=有連續等於的特性int x,y,z;
x = y = z = 15; 同樣有趣的是,賦值採用的是右結合律,所以上述連鎖賦值被解析為: x = (y = (z = 15)); //賦值連鎖形式 這裡15先被賦值給z,然後其結果(更新後的z)再被賦值給y,然後其結果(更新後的y)再被賦值給x。 為了實現「連鎖賦值」,賦值操作符號必須返回一個reference指向操作符號的左側實參(而事實上重載運算符的左側實參就是調用對象本身,比如= += -=等) 這是你為classes實現賦值操作符時應該遵循的協議:這個協議不僅僅適用於以上的標準賦值形式,也適用於所有賦值運算 class Widght{
public:
.....
Widget operator=(cosnt Widget rhs)
{
...
return* this;
}
Widget operator+=(cosnt Widget rhs)
{
...
return* this;
}
Widget operator-=(cosnt Widget rhs)
{
...
return* this;
}
Widget operator*=(cosnt Widget rhs)
{
...
return* this;
}
Widget operator/=(cosnt Widget rhs)
{
...
return* this;
}
...
};
注意,這只是個協議,並無強制性,如果不遵循它,代碼一樣可以通過編譯,然而這份協議被所有內置類型和標準程序庫提供的類型入string,vector,complex,trl:shared_ptr或者即將提供的類型共同遵守。因此除非你有一個標新立異的好理由,不然還是隨眾吧。
下面看一個賦值運算符號的例子
String::String(const char* s) String String::operator=(const String other) int main() str3 = str1 = str2;//str3.operator=(str1.operator=str2)#ifndef STRING_H
#define STRING_H
using namespace std;
class String
{
private:
char *str;
int len;
public:
String(const char* s);
String operator=(const String another);
void show()
{
cout&<&<"value = "&<&#include&
#include&
#include"String.h"
using namespace std;
{
len = strlen(s);
str = new char[len + 1];
strcpy(str,s);
}
{
if(this == other)
return *this;
delete[] str;
len = other.len;
str = new char[len + 1];
strcpy(str,other.str);
return *this;
}
{
String str1("abc");
String str2("123");
String str3("456");
str1.show();
str2.show();
str3.show();
str3.show();
str1.show();
return 0;
}
如果採用String operator+(const String str) 這樣就不會有多餘的調用(因為這裡直接return一個已經存在對象的引用)
如果採用return對象 那麼第二次賦值運算調用的情況就是將一個新的String對象傳遞到operator+()的參數中去 相當於 const Stringstr = returnStringObj;如果採用return對象引用 那麼第二次賦值運算的情況就是將一個已經存在的String對象(其實就是str1)的引用傳遞到operator+()的參數中去 const Stringstr = returnReference; (String returnReference = str1;)+=等運算符也是同樣的考慮,比如int main()
{
String str1("abc");
String str2("123");
String str3("456");
str1.show();
str2.show();
str3.show();
str3 = str1 = str2;//str3.operator=(str1.operator=str2)
str3.show();
str1.show();
int num = 10;
num+=(num+=100);
cout&<&
如果要這樣使用+=或其他上面舉出的運算符,+=運算的返回值一定要是一個對象或者引用才行,不然就會出現錯誤(參數類型不符號)。
當然如果確定不會這麼使用,直接返回void也是可以的上面的例子也說明了一點,析構函數的調用是在變數作用域結束的時候(以及程序運行結束的時候)
在不需要對返回值進行操作的時候,直接返回void就行了,首先要明白一點,運算符左側的對象就是操作對象比如ObjectA = ObjectB ObjectA.operator=(ObjectB) ObjectA+=ObjectB ObjectA.operator+(ObjectB)下面看返回voidpublic:
String(const char* s);
void operator=(const String another);
void String::operator=(const String other)
{
if(this == other)
return;
delete[] str;
len = other.len;
str = new char[len + 1];
strcpy(str,other.str);
}
int main()
{
String str1("abc");
String str2("123");
str1.show();
str2.show();
str1 = str2;//str1.operator=str2
str1.show();
return 0;
}
以上就是答案
題主還是沒理清思路啊。要從兩個角度分析這個問題:為什麼返回應用?以及返回之後發生了什麼?
1、2 兩問實際上是第一個問題:為什麼在重載操作符的時候會返回引用?
實際上這裡的原因很簡單:為了表達正確的語義。C++ 的操作符重載的全部意義就是為了讓所謂」值類型「的操作看起來更像是 int / float 之類基本類型的操作,所以當談論操作符重載的時候,返回的引用基本上都是綁定在 *this(當實現為成員函數)或者第一個參數(當實現為全局函數,如 operator&<&< (ostream, T) 這種);目的很明確:為了串聯表達式。而很明顯可以看到:這兩個情況都不存在 NULL 的可能性。如果傳入對象為 NULL,錯誤早在返回引用被訪問之前就已經出了。一個函數能不能返回引用,應該在這個函數內部進行分析:- 對於一個傳入的對象,生命期由調用者管理的時候,返回它的引用通常是沒問題的(operator&<&< 等通常屬於這種情況)
- this 指針實際上等價於被傳入給成員函數的」第一個參數「,生命周期也是由調用者管理的,所以等價於第一個情況
- 被調用函數管理的局部對象,由於在函數返回的時候生命周期結束,無法保持,通常不應該返回引用;如果外部需要,可以返回值(進行拷貝)或者分配在堆上並返回指針(需要調用者之後清理)。
int i = 0;
int i1 = i;
int r1 = i;
int r2 = i1;
int r3 = r1;
int i2 = r1;
請問 r2 和 r3 有區別么?沒有。當你把一個」引用「放在等號右側的時候,它和」被它引用的對象「是等價的,所以」3. 返回的引用賦給一個變數後,那個變數是不是引用?「 的答案僅取決於左邊這個變數的定義(體會 i2 和 r3 的區別)。
第四個問題,也就是 CSDN 那個問題里的錯誤在於,這個被返回的對象的生命期在當前表達式結束的時候已經結束了。你需要分析的是這個被綁定的對象的生命期;根據我第一段斜體字,以及 @鍾宇騰 的分析,可以很明顯的看出這裡和 CSDN 那段代碼中,對象的生命期是有本質區別的。正確的做法,上面已經分析了。我只回答問題1,因為問題234,樓上的幾位大牛已經說的很完整了。
問題1:C++中有些重載運算符為什麼要返回引用?
答:因為C++標準中支持很多這種寫法:int a;
(a+=3)*=4;
這不單發生在+=運算符上,還有=運算符。
當然,大家最熟悉的應該是&<&<運算符:cout &<&< "hello world!" &<&< endl;
返回引用一個重要目的是實現鏈式調用
a.add().add().test().print()1.如果不返回引用,那麼a=b=c是無效的2.返回自身引用不存在NULL的情況3.引用應當用於初始化引用,而不是付給變數4.cout &<&< "A" 返回的是cout的引用。推薦閱讀:
※為什麼C語言考試不夠好?
※%d的格式不能用來輸出sizeof的返回值嗎?
※為什麼學習編程第一課要學習輸出"hello, world"?這是誰規定的?