1. 程式人生 > >c/c++: c++函式返回型別什麼情況帶const

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