关于函数的参数为类的引用时编译错误的分析
2014-04-08 22:12
288 查看
关于函数的参数为类的引用的分析
下面这段程序是重载“+”,使之实现两个复数的相加,并且利用了转换构造函数,可以将实数转换成复数类,程序如下:
#include<iostream>
using namespace std;
class Complex
{
public:
Complex(){real = 0;imag = 0;}
Complex(double r){real = r;imag = 0;}
Complex(double r,double i){real = r;imag = i;}
friend Complex operator + (Complex &c1,Complex &c2); //改为(Complexc1,Complex
c2)程序正确
void display();
private:
double real;
double imag;
};
Complexoperator + (Complex &c1,Complex &c2) //改为(Complexc1,Complex
c2)程序正确
{
return Complex(c1.real + c2.real, c1.imag + c2.imag);
}
voidComplex::display()
{
cout << "(" << real << "," << imag<< "i)" << endl;
}
intmain()
{
Complex c1(3,4),c3;
c3 = c1 + 2.5;
c3.display();
return 0;
}
这是一个错误的程序,编译不能通过,错在“+”重载函数用了“类的引用调用”,如果不用“类的引用调用”,改用“实参传递形参”,程序正确。为什么这里不能用“类的引用调用”呢??
在利用转换构造函数来实现复数和整型值相加的时候,我也遇到了上面最开始的问题。上面的内容是我在网上查找资料时copy下来的。后来,我又自己翻阅了谭浩强编的C++,找到了比较清楚的解释。
书中在介绍引用时强调,可以用常量或表达式对引用进行初始化,但此时必须用const作声明。
为什么一定要用const作声明?这是我的最先有的一个疑问,想必你也是的。下面分析。
引用,一般地来讲是不能被初始化的。为什么
?因为引用是和被引用的变量共享存储单元的,编译系统是不会给它分配存储空间的。那么,引用只能被声明,不能被定义了。
如果你一定要给引用初始化,可以,但必须用const了。为什么?
编译器处理引用初始化并不是一步完成的。例如,上面代码把2.5传给引用,编译器首先时在内部生成了一个临时变量,然后通过临时变量再赋给引用。代码表示下:
double temp = 2.5;
Complex &c2 =temp;
这里就涉及到了我们问题的关键所在了。改变引用的c2值,同样会改变temp的值,但是,2.5的值却不能被修改。我们把引用作为形参,如果改变引用的值,是希望同时能够改变传递的实参的值的。这就与我们上面例子分析的结果产生了矛盾。与其允许修改引用的值而不能满足用户的需要,还不如不允许修改,这就是C++对这类引用必须要加const的原因。了解了我前面提到的2个为什么,相信你就能明白了。
4000
那么最初遇到的问题,根据上面的分析便很容易解决了。要么,我们不用引用,就用传值的方式,要么,我们在使用引用时,用const加以限定。如果你用了引用,又没加const,很不幸
,编译又会出现一些错误,而不能通过了。
下面这段程序是重载“+”,使之实现两个复数的相加,并且利用了转换构造函数,可以将实数转换成复数类,程序如下:
#include<iostream>
using namespace std;
class Complex
{
public:
Complex(){real = 0;imag = 0;}
Complex(double r){real = r;imag = 0;}
Complex(double r,double i){real = r;imag = i;}
friend Complex operator + (Complex &c1,Complex &c2); //改为(Complexc1,Complex
c2)程序正确
void display();
private:
double real;
double imag;
};
Complexoperator + (Complex &c1,Complex &c2) //改为(Complexc1,Complex
c2)程序正确
{
return Complex(c1.real + c2.real, c1.imag + c2.imag);
}
voidComplex::display()
{
cout << "(" << real << "," << imag<< "i)" << endl;
}
intmain()
{
Complex c1(3,4),c3;
c3 = c1 + 2.5;
c3.display();
return 0;
}
这是一个错误的程序,编译不能通过,错在“+”重载函数用了“类的引用调用”,如果不用“类的引用调用”,改用“实参传递形参”,程序正确。为什么这里不能用“类的引用调用”呢??
在利用转换构造函数来实现复数和整型值相加的时候,我也遇到了上面最开始的问题。上面的内容是我在网上查找资料时copy下来的。后来,我又自己翻阅了谭浩强编的C++,找到了比较清楚的解释。
书中在介绍引用时强调,可以用常量或表达式对引用进行初始化,但此时必须用const作声明。
为什么一定要用const作声明?这是我的最先有的一个疑问,想必你也是的。下面分析。
引用,一般地来讲是不能被初始化的。为什么
?因为引用是和被引用的变量共享存储单元的,编译系统是不会给它分配存储空间的。那么,引用只能被声明,不能被定义了。
如果你一定要给引用初始化,可以,但必须用const了。为什么?
编译器处理引用初始化并不是一步完成的。例如,上面代码把2.5传给引用,编译器首先时在内部生成了一个临时变量,然后通过临时变量再赋给引用。代码表示下:
double temp = 2.5;
Complex &c2 =temp;
这里就涉及到了我们问题的关键所在了。改变引用的c2值,同样会改变temp的值,但是,2.5的值却不能被修改。我们把引用作为形参,如果改变引用的值,是希望同时能够改变传递的实参的值的。这就与我们上面例子分析的结果产生了矛盾。与其允许修改引用的值而不能满足用户的需要,还不如不允许修改,这就是C++对这类引用必须要加const的原因。了解了我前面提到的2个为什么,相信你就能明白了。
4000
那么最初遇到的问题,根据上面的分析便很容易解决了。要么,我们不用引用,就用传值的方式,要么,我们在使用引用时,用const加以限定。如果你用了引用,又没加const,很不幸
,编译又会出现一些错误,而不能通过了。
相关文章推荐
- 一个关于函数内部指针参数返回的错误调试及分析
- 从一段经典错误代码说起——关于局部变量指针和函数传参的问题分析
- 关于函数返回引用的分析?
- 关于Java的引用和函数参数传递
- 再开一篇关于C++程序设计基核心之一:引用,指针,符号优先级,函数参数传递
- 关于strdup函数参数为NULL的分析和建议
- C++学习笔记(四)——关于数组作为函数参数的值传递和引用传递
- 关于函数模版编译出现链接错误
- vs2010编译时出现错误提示:error C2470: “xx”: 看起来像函数定义,但没有参数列表;跳过明显的函数体
- 关于两个小东东的分析(函数执行值与函数的预编译跟解释执行阶段)
- 关于js 函数传递引用参数理解
- 关于函数参数引用
- 2010.8.16 关于函数参数是指针、还是引用的区别
- 关于python函数传参数问题 , 不管什么类型都是传引用
- C语言学习4: 函数返回值与传入参数,关于函数值传递和类型隐性转换,变量不同的作用域,static变量,多文件编译例如两个C文件,显示函数调用语句跳转,递归,斐波那契数列,多文件编译相同变量的问题。
- 关于JavaScript预编译和执行顺序以及函数引用类型的思考
- CCS3.3关于函数参数的引用
- 关于“索引和长度必须引用该字符串内的位置。参数名: length”错误的解析
- 关于带返回值委托函数和委托函数使用引用参数的问题
- 关于Java函数传参以及参数在函数内部改变的问题——JAVA值传递与引用最浅显的说明!