C++中的引用

来源:互联网 发布:龙珠人物战斗力数据 编辑:程序博客网 时间:2024/06/05 04:07

引用就是对象的另一个名字--这是《c++primer》中介绍引用里的一句话;而且很多c++参考书中都有“引用是另一个对象的别名”这一说;这句话很容易让人引起误会。看下面的例子:
int main()
{
 int a;
 int &b = a;

 a = 1;
 cout<<"a="<<a<<endl;
 cout<<"b="<<b<<endl;

 b = 2;
 cout<<"a="<<a<<endl;
 cout<<"b="<<b<<endl;
 
 cout<<"&a="<<&a<<endl;
 cout<<"&b="<<&b<<endl;

 return 0;
}
输出结果:
a=1
b=1
a=2
b=2
&a=0012FF7C
&b=0012FF7C

从上面看出,对a操作相当于对b操作,对b操作相当于对a操作,就好比b是a的影子,两者都会互相影响,但是影子和实物本质上还是有区别的,看如下会编代码:

1015:     int a;
1016:     int &b = a;
00401598   lea         eax,[ebp-4]
0040159B   mov         dword ptr [ebp-8],eax
这几行汇编代码中,先得到b(ebp-4)的地址赋给eax,然后eax赋给ebp-8(也就是a)。反正就是把b的地址赋给a,最后a里面存的是b的地址,而b里面呢,是数值(因为没初始化所以是一个int型的随机数)。到这里,你还认为a和b是一样的吗?
再看看下面的:

1026:     cout<<"&a="<<&a<<endl;
00401656   push        offset @ILT+200(std::endl) (004010cd)
0040165B   lea         edx,[ebp-4]             ;获取a的地址
0040165E   push        edx
0040165F   push        offset string "&a=" (0046f020)
00401664   push        offset std::cout (0047ce90)
00401669   call        @ILT+650(std::operator<<) (0040128f)
0040166E   add         esp,8
00401671   mov         ecx,eax
00401673   call        @ILT+60(std::basic_ostream<char,std::char_traits<char> >::operator<<) (00401041)
00401678   mov         ecx,eax
0040167A   call        @ILT+480(std::basic_ostream<char,std::char_traits<char> >::operator<<) (004011e5)
1027:     cout<<"&b="<<&b<<endl;
0040167F   push        offset @ILT+200(std::endl) (004010cd)
00401684   mov         eax,dword ptr [ebp-8]  ;&b操作,想想这里为什么不是lea eax    [ebp -8]呢,因为这里b是对a的引用
00401687   push        eax
00401688   push        offset string "&b=" (0046f01c)
0040168D   push        offset std::cout (0047ce90)
00401692   call        @ILT+650(std::operator<<) (0040128f)
00401697   add         esp,8
0040169A   mov         ecx,eax
0040169C   call        @ILT+60(std::basic_ostream<char,std::char_traits<char> >::operator<<) (00401041)
004016A1   mov         ecx,eax
004016A3   call        @ILT+480(std::basic_ostream<char,std::char_traits<char> >::operator<<) (004011e5)
从这段代码的结果看出&a和&b操作都是反回a的地址,但是过程不同,对于&a,它是lea   edx,[ebp-4];而&b,它是eax,dword ptr [ebp-8] 也就是b的值给eax。说明b存的是a的地址

1018:     a = 1;
0040159E   mov         dword ptr [ebp-4],1  ;对a的赋值
1019:     cout<<"a="<<a<<endl;
004015A5   push        offset @ILT+200(std::endl) (004010cd)
004015AA   mov         ecx,dword ptr [ebp-4]  ;对a的读取
004015AD   push        ecx
004015AE   push        offset string "a=" (0046f028)
004015B3   push        offset std::cout (0047ce90)
004015B8   call        @ILT+650(std::operator<<) (0040128f)
004015BD   add         esp,8
004015C0   mov         ecx,eax
004015C2   call        @ILT+255(std::basic_ostream<char,std::char_traits<char> >::operator<<) (00401104)
004015C7   mov         ecx,eax
004015C9   call        @ILT+480(std::basic_ostream<char,std::char_traits<char> >::operator<<) (004011e5)
1020:     cout<<"b="<<b<<endl;
004015CE   push        offset @ILT+200(std::endl) (004010cd)
004015D3   mov         edx,dword ptr [ebp-8]    ;  对b的读取代码
004015D6   mov         eax,dword ptr [edx]
004015D8   push        eax
004015D9   push        offset string "b=" (0046f024)
004015DE   push        offset std::cout (0047ce90)
004015E3   call        @ILT+650(std::operator<<) (0040128f)
004015E8   add         esp,8
004015EB   mov         ecx,eax
004015ED   call        @ILT+255(std::basic_ostream<char,std::char_traits<char> >::operator<<) (00401104)
004015F2   mov         ecx,eax
004015F4   call        @ILT+480(std::basic_ostream<char,std::char_traits<char> >::operator<<) (004011e5)
1021:
1022:     b = 2;
004015F9   mov         ecx,dword ptr [ebp-8]    ;对b赋值
004015FC   mov         dword ptr [ecx],2

从中看出对a的赋值代码,和对a的读取代码都是直接操作。而对b的读取和赋值操作中,先读取b中保存的值(a的地址)给edx,然后通过dword ptr [edx]完成读取,对于赋值也一样;

所以,对于a的赋值和读取操作,直接就可以;而对于b(它是引用),先要读取它里面的保存的值(也就是a的地址),然后根据这个地址进行读取和赋值操作。当然我们写代码时,完全可以把b当成a的一个别名来操作;

------本人菜鸟一个,有什么地方理解错了,望大牛指出

原创粉丝点击