首先分析一段程式碼:
#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; }
一點編譯,輸出一行編譯錯誤
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 &。這下我們可以搞明白問題出現的原因了————函式的返回值作為隱式常量賦值給非 常引用致錯。
在此留幾個還沒搞明白的問題,提示:引用,型別轉換,以備以後研究。