由作業題引發對C++引用的一些思考

deepwzh發表於2017-03-23

首先分析一段程式碼:

#include <bits/c++config.h>
#include <ostream>
#include <iostream>
#include <cstdio>
using namespace std;
class Node{
    int x;
    public:
    Node(int x=0):x(x){
    }

};
Node get(){
    return Node(5);
}
int main(){
    Node & i =  get();  
    return 0;
}
View Code

一點編譯,輸出一行編譯錯誤

test1.cpp:25:21: error: invalid initialization of non-const reference of type ‘Node&’ from an rvalue of type ‘Node’

     Node & i =  get();

意思是不能將Node型別的右值複製給Node&型別的變數。

我嘗試改一下原始碼,主函式改為

1 int main(){
2   //int & n = 5;
3 Node t = get(); 4 Node & i = t ; 5
5   return 0; 6 }

發現程式可以編譯了。仔細對比這兩段程式碼,我們可以得到這樣一個事實:函式中返回的值相當於一個常量,它是臨時產生的。只有當把這個函式的返回值賦值給變數的時候,我,們可以把變數的值賦值給Node&型別的變數。為了驗證這個猜測,我們去掉上邊的註釋:

test1.cpp:24:15: error: invalid initialization of non-const reference of type ‘int&’ from an rvalue of

 type ‘int’

     int & t = 5;


這個編譯錯誤和上邊的編譯錯誤基本是一致的,從而驗證了我們的猜測。

在這個問題的基礎上,我們研究這樣一個問題

 1 #include <bits/stdc++.h>
 2 #include <istream>
 3 using namespace std;
 4 class Character{
 5     char c;
 6     public:
 7     Character(){}
 8     Character(char c):c(c){}
 9     Character  operator + (const int ch){
10         return Character(((c+ch-'a')%26+26)%26+'a');
11     }
12     Character  operator - (const int ch){
13         return  Character(((c-ch-'a')%26+26)%26+'a');
14     }
15     friend istream & operator >> (istream &is, Character &ch);
16     friend ostream & operator << (ostream &os, Character &ch);
17 };
18 ostream &operator << (ostream &os, Character &ch){
19     os << ch.c ;
20     return os;
21 }
22 istream &operator >> (istream &is, Character& ch){
23     is >> ch.c;
24     return is;
25 }
26 int main()
27 {
28     int cases, data;
29     Character ch;
30     int d;
31     cin>>cases;
32     for (int i = 0; i < cases; i++)
33     {
34         cin>>ch;
35         cin>>data;
36         cout<<(ch + data)<<" "<<(ch - data)<<endl;
37     }
38 }

編譯上邊的程式碼,我們得到一連串編譯錯誤資訊,看的頭都大。不過不要過於擔心。我們經常會因為一個小錯誤產生連鎖反應才產生了如此多的錯誤。我們要做的是查詢最本源的那個bug。

首先我想到的可能<<的過載寫的有問題,我查閱了iostream,ostream標頭檔案的原始碼,確定了與之相關的函式

1  inline basic_ostream<_CharT, _Traits>&  operator<<(basic_ostream<_CharT, _Traits>& __out, const _CharT* __s);
2  inline basic_ostream<_CharT, _Traits>&  operator<<(basic_ostream<_CharT, _Traits>& __out, _CharT __c);

我根據原始碼判斷,<<過載的大致應該是這個函式,從剛才的一大串編譯錯誤中似乎也能驗證這一點,裡面包含原始碼中的第2行語句。

於是我根據原始碼第一行有const 這一事實,把<<的過載函式第二個引數前邊都加上const,往第一條語句靠攏,程式成功編譯了。或者我去掉引用,往第二條語句靠攏,程式同樣編譯成功了,更改程式碼如下。

ostream &operator<<(ostream &os,Character a);
ostream &operator<<(ostream &os,const Character &a);

我們至此可以把程式改正確了。但還有一個問題沒有解決,為什麼僅僅去掉const就發生了編譯錯誤了?

這時結合我們一開始探討的例子,這段程式碼和文章一開始的程式碼情況基本一致。即把一個返回非引用值的函式傳給Character &。這下我們可以搞明白問題出現的原因了————函式的返回值作為隱式常量賦值給非 常引用致錯。

在此留幾個還沒搞明白的問題,提示:引用,型別轉換,以備以後研究。

相關文章