以前在群里面发现有人说,引用可以被赋值,然后其推断出引用其实是可以重新指向其它对象的,而不是只能在初始化时确定所指对象,以后不能改变。如果是这样的话,引用和指针还有什么区别了。存在引用的好处就是,引用一经过定义就确定所指对象,以后不用测试其是否指向无效对象,也不用担心所指对象会改变。
下面来看看这段造成误解的代码吧。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| #include <iostream> using namespace std;
int main() { int nA = 10; int nRef = nA;
cout << "nA:" << nA << ' ' << "nRef:" << nRef << endl;
int nB = 11; nRef = nB; cout << "nB:" << nB << endl; cout << "nA:" << nA << ' ' << "nRef:" << nRef << endl;
nRef = 12; cout << "nB:" << nB << endl; cout << "nA:" << nA << ' ' << "nRef:" << nRef << endl;
return 0; }
|
运行结果:
从结果可以看到,用nB对nRef进行赋值后,nA的值也变成11了,由此可见nRef仍然指向nA。而再对nRef赋值12,只有nA变成12,而nB仍然是11。这些都可以很清楚的说明,引用所指的对象是没有变化的,一经初始化就不会改变。
下面再来看看,注释掉输出语句后的反汇编代码。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
| int main() { 00EC48F0 push ebp 00EC48F1 mov ebp,esp 00EC48F3 sub esp,0E4h 00EC48F9 push ebx 00EC48FA push esi 00EC48FB push edi 00EC48FC lea edi,[ebp-0E4h] 00EC4902 mov ecx,39h 00EC4907 mov eax,0CCCCCCCCh 00EC490C rep stos dword ptr es:[edi] int nA = 10; 00EC490E mov dword ptr [nA],0Ah int nRef = nA; 00EC4915 lea eax,[nA] 00EC4918 mov dword ptr [nRef],eax
int nB = 11; 00EC491B mov dword ptr [nB],0Bh nRef = nB; 00EC4922 mov eax,dword ptr [nRef] 00EC4925 mov ecx,dword ptr [nB] 00EC4928 mov dword ptr [eax],ecx
nRef = 12; 00EC492A mov eax,dword ptr [nRef] 00EC492D mov dword ptr [eax],0Ch
return 0; 00EC4933 xor eax,eax }
|
从以下几句能看到nRef实际上存储的是nA的地址。lea是取有效地址的意思。
1 2 3
| int nRef = nA; 00EC4915 lea eax,[nA] 00EC4918 mov dword ptr [nRef],eax
|
从给引用赋值的汇编代码可以看出,实际上的动作是把nRef代表的地址放入一个寄存器,再取nB的值放入一个寄存器,然后将nB的值赋给nRef指向的内存。
1 2 3 4
| nRef = nB; 00EC4922 mov eax,dword ptr [nRef] 00EC4925 mov ecx,dword ptr [nB] 00EC4928 mov dword ptr [eax],ecx
|