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
