C++primer提到,引用就是对象的别名,换言之,计算机在对对象引用的时候并没有实际分配空间,这个可以从引用对象的角度去测试:
假设有:
class A
{
......
};
A a;
A b=a;//调用拷贝构造函数,也叫类型转换
A &c=a;//给a取一个别名,不调用任何函数
那么既然引用只是名称,那么sizeof(type&)是什么呢,我的猜想是,sizeof()并不在乎里面的名称是什么,他只关心类型,对于引用,那么就是结果就是,
引用什么类型,那么返回什么类型的大小,这个用reinterpret_cast关键字进行测试:
A a;//假设a的大小是24,这个根据A类大小设定
int &b=reinterpret_cast<int&> (a);
cout<<"对象a的大小是:"<<sizeof (a)<<endl;
cout<<"引用b的大小是:"<<sizeof (b)<<endl;
cout<<"他们的地址分别是"<<endl<<(int*)(&a)<<endl<<(int*)&b;
可以看出,他们的地址都是一样的,也就是说,是同一个对象,但是sizeof只会看int&是int型的引用,就直接返回int的大小4个字节了。
2.引用的是变量名的情况
假设有:
double b=3.33;
int &a=(int)b和int &a=(int&)b;有什么区别
对于前者,是类型转换,对于类型转换,计算机实际是通过一定方式,生成一个临时的,且符合转换类型的变量,(int)b就好比 (A)a,我们知道,a就是A类的对象,
(A)a有意义吗,实际是有的,他会调用拷贝构造函数生成一个临时的对象,如果拷贝构造函数有显示的输出语句,那么就一目了然了。再进行引申,如果
A是一个类名,可以用 A b=A(a);来调用拷贝构造函数,这个与A b=a;有什么区别呢,区别就在于,对于A b=A(a);那么先通过A (a)进行类型转化,这时候用a
构造一个临时对象,再执行A b=临时对象,但是这个语句不会再次调用拷贝构造函数,这个原因说起来就要提起c++ primer第13章关于合成的复制构造函数的定义了,
合成构造函数的行为是,执行逐个成员初始化。也就是说,在程序员没有自己定义构造函数的时候,是执行合成的构造函数的,但是,还有一种情况,即使自定义
了拷贝构造函数,也会执行合成的构造函数,那就是,当等号的右边是一个临时对象的时候将不会执行已定义的拷贝构造函数,而是执行默认的合成复制构造函数。
所以对于 A b=(A)a来说, A(a)生成的是临时对象,所以最后那步A b=临时对象调用的是缺省的复制构造函数,吧并不会调用用户设置的拷贝构造函数。所以最终
自定的拷贝构造函数只在(A)a时被调用,而如果用户自定义的拷贝构造函数是 A (A&),那么对于有些编译器是会对上述行为报错的,原因很简单,因为当他要执行
A b=临时对象时,发现等号右边是一个右值,引用是不能对右值引用的(A&=临时对象),那么变异会报错,这时只需把自定义的拷贝构造函数改为A (const A&)就行了,
因为C++是允许右值引用的,例如const int &a=3;那么由(A)a生成的临时变量就能作为形参被传递了。但是对于 A b=a;就不同了,这个是直接把a作为形参调用
拷贝构造函数,所以即使用户定义的拷贝构造函数是A (A&)也就是不允许接受右值作为形参也不影响,因为a是实际占用空间的。那回过头,对于前面的
double b=3.33
int &a=(int)b;#1实际是申请一个临时空间,把b按照int的规格写入这个空间
int &a=(int&)b;#2则不同了,他直接把b的存储内容当成int类型,也就是里面一堆的1010101的二进制,没有任何实际的转化
这两个的区别就是,最后当你cout<<a的时候,#2是会输出异常的,因为他没经过规格化的类型转换,只是把机器码的意思改变了,由double变成int了,
这个问题在c就有了,例如
double d=5.55;
int *p=(int*) &d;
printf ("%lf",*p);//输出异常,因为*p里面的机器码被解释为int
printf ("%lf",*(double*)p);//输出正常,强扭后,*p被解释为double
可见。同样对机器码,不用的解释会影响最后的输出。
但是对于int &a=(int)b又会有新问题,(int)b生成的是临时变量,这个是不能付给引用的,不出意外会报错,只需把int&a改为const int&a即可。
3.常量引用
对于const int& a=3.33;
因为常量是不能取地址的,(&3.33非法),所以根本不可能给他取别名,实际的做法分为两步
1)(int)3.33生成一个临时空间
2)把这个空间与引用关联
类似const int&a=(int)3.33;所以当你多次对一个常量进行引用,返回的只是不同的临时空间地址而已
例如:
const int& p1=3.33;
const int&p2=3.33;
const int&p3=3.33;
p1,p2,p3的地址都是不同的。