c/c++: c++函式返回型別什麼情況帶const
https://www.cnblogs.com/Azhu/p/4352613.html
c++ 函式的返回型別,包括const 什麼時候起作用呢?
- 函式返回值不想其立即修改的。
例子如下,這是一個簡單的避免產生隱形返回變數的方法,abc 的函式返回是引用,main函式中第10行,++ 操作是基於 const int & 型別,所以會出錯,但以後對改引用的操作不會受到const 約束。
這樣的好處是避免了函式返回值與操作符的邏輯錯誤結合,例如下面的例子中函式返回的++,對於main 函式是不直觀的,進一步的應用是在操作符過載方面,見下一情況說明。
1 const int & abc(int a,int b,int &re) 2 { 3 re = a+b; 4 return re; 5 } 6 7 int main() 8 { 9 int a = 1,b =2,c; 10 abc(a,b,c)++; /////////////////////錯誤 11 c++; /////////////////////正確 12 cout<<c<<endl; 13 return 0; 14 }
- 過載運算子符合邏輯
一般變數賦值a=b=c,這是沒有問題的,但是(a=b)=c 編譯會出錯,這是內建操作符的判斷,如果對 = 操作符過載了,為了避免這樣的邏輯錯誤,需要在返回型別上加上const 約束,下面例子中A類過載了運算子 +,如果第6行中返回型別沒有const 約束,那麼15行編譯會通過,場景如果是:if(a+b==c) 誤寫為 if(a+b=c)。
+ 運算子過載加const 約束 對 a+b+c 這樣的運算沒有影響,因為a+b 運算的結果是const ,但對其只是只讀操作,會建立一個新的 A 類返回。
1 class A 2 { 3 public: 4 int a; 5 A(int b):a(b){} 6 friend const A operator +(const A& lft,const A& rgt) 7 { 8 return A(lft.a + rgt.a); 9 } 10 }; 11 12 int main() 13 { 14 A a(1),b(3),c(7); 15 a+b = c; /////////錯誤 16 return 0; 17 }
- 通過函式建立指向常量的指標
如果通過函式來建立常字串,除了在main 函式中約束之外,也可以在函式返回型別中約束,第一行中左邊的const 約束了返回的是常字串的指標索引,因為它的存在12行必須宣告為 const char *p,如果第一行左邊const 不存在,那麼12行可以加可以不加const,這樣約束常字串的效果只能在main 中反映,不能很好的表達呼叫函式的功能。
同時第一行中的第二個const 加了也無效,其約束的是一個由 char * p 轉變為 char * const 的隱藏指標,該隱藏指標的指向值賦予給main 函式中的p,所以後者可以修改指向。(這時我的理解不確定正確與否)
1 const char * const helpFun() 2 { 3 char * p =new char[3]; 4 p[0]='a'; 5 p[1]='b'; 6 p[2]='\0'; 7 return p; 8 } 9 10 int main() 11 { 12 const char * p = helpFun(); 13 p++; 14 cout<<p<<endl; 15 delete p; 16 return 0; 17 }
- 滿足對const成員函式的呼叫
這個結合例子說明比較容易,這裡主要有一個原因是:const型別的物件,不能呼叫自身的非const成員函式,但是可以呼叫自己的const成員函式。例如下面的例子,b 宣告為const A,12行是可以編譯成功的,13行缺會錯誤,根本原因或許是內部 this 指標轉換(不確定)。
1 class A { 2 public: 3 A():num(2) { } 4 void setnum() { } 5 void getnum() const{ } 6 private: 7 int num; 8 }; 9 int main() 10 { 11 const A b; 12 b.getnum(); 13 b.setnum();///////////////////////錯誤 14 return 0; 15 }
基於上面的一個原因,下面例子便容易說明,A 類是B 類運算中產生的隱藏變數,為了呼叫A 類中的const 函式,B類生產A 類的函式返回型別需要加const。
1 class A 2 { 3 public: 4 A():num(2){} 5 void setnum(){ num = 10; } 6 void getnum() const{ 7 printf("%d\\n",num); 8 } 9 private: 10 int num; 11 }; 12 13 class B 14 { 15 public: 16 const A* get() 17 { 18 A *p = new A(); 19 return p; 20 } 21 }; 22 23 int main() 24 { 25 B b; 26 b.get()->getnum(); 27 b.get()->setnum(); 28 return 0; 29 }
- const 成員函式的返回型別是引用時候,需要加const 約束
int fun() const; int & fun() const;
成員函式中上面是合法的,下面缺不合法,具體例子如下,對於第5行 函式返回型別中的const 不能省略,不管第10行是否有const,這應該是內部value 物件型別的轉換,GetValue 函式中的value 被轉換成了 const int(第10行沒有const 也會轉換),但return 的如果是 int & 型別便出現了 const int -> int & 這種型別轉換,這是禁止的,所以返回引用時必須加const,總結來說,如果GetValue 是const函式且返回型別是引用,那麼返回型別中的const 和16行的const 不能省略。
1 class Test 2 { 3 public : 4 Test(int a):value(a){} 5 const int & GetValue()const 6 { 7 return value; 8 } 9 private: 10 const int value; 11 }; 12 13 int main() 14 { 15 Test t(3); 16 const int &a = t.GetValue(); 17 cout<<a<<endl; 18 return 0; 19 }
引申如果const 成員函式返回的值 指標呢?這與返回int 型別是一樣是賦值給接受物件,而引用因為沒有了複製所以必須有const,例如下面程式碼可以編譯執行,同時發現繞開了類的private約束。第6行返回型別加const,其實便是第三種情況。如果第13行 是 const int * p,那麼情況便不一樣了,第6行和第19行都需要加const。
1 class Test 2 { 3 public : 4 Test(int a):value(a){ p = &value; } 5 void setValue(){value =10;} 6 int * GetValue()const 7 { 8 return p; 9 } 10 int getv(){return value;} 11 private: 12 int value; 13 int * p; 14 }; 15 16 int main() 17 { 18 Test t(3); 19 int *a = t.GetValue(); 20 cout<<*a<<endl; 21 *a = 5; 22 cout<<t.getv()<<endl; 23 delete a; 24 return 0; 25 }
參考資料:
http://www.docin.com/p-97354417.html
http://blog.chinaunix.net/uid-24922718-id-3480107.html
http://blog.sina.com.cn/s/blog_4366aa320100cknr.html
http://blog.csdn.net/zhjxin1800/article/details/7584375
http://www.cnblogs.com/lichkingct/archive/2009/04/21/1440848.html