首页 > 代码库 > 由作业题引发对C++引用的一些思考
由作业题引发对C++引用的一些思考
首先分析一段代码:
#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 &。这下我们可以搞明白问题出现的原因了————函数的返回值作为隐式常量赋值给非 常引用致错。
在此留几个还没搞明白的问题,提示:引用,类型转换,以备以后研究。
由作业题引发对C++引用的一些思考