`
tinggo
  • 浏览: 44904 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论

关于C++引用类型变量

阅读更多
随着设计模式的学习和实践,C++中引用的使用愈发平凡。但是C++中引用类型变量到底是什么东西,这种变量与Java C#中的引用值有什么区别和联系,直到今日才有所了解。这一切都出自于一次偶然的发现。
由于过去长期使用Java这种没有指针的语言,其引用值的概念早就深入人心。
我们知道,当有如下代码时,其实相当于什么都没做。
void function (Object o1, Object o2)
{
    Object temp;
    temp=o1;
    o1=o2;
    o2=temp;
}

这是因为传入函数的是引用值的关系,换句话说,这o1也好o2也罢,这都是指向内存空间的地址值。如果对于这个概念不太理解的话可以继续查阅Java中Passed by value的概念。

在使用过程中,我把这种概念也强加于C++中的引用值中,最后发生了悲剧的事情。
#include <iostream>
using namespace std;

class Object
{
public:
    Object(int value1, int value2):a(value1), b(value2) {}
    int a;
    int b;
};

int main()
{
    Object o1(1,2);
    Object o2(3,4);
    cout<<o1.a<<" "<<o1.b<<" "<<o2.a<<" "<<o2.b<<endl;
    function(o1, o2);
    cout<<o1.a<<" "<<o1.b<<" "<<o2.a<<" "<<o2.b<<endl;
    return 0;
}

void function (Object& o1, Object& o2)
{
    Object temp=o1;
    o1=o2;
    o2=temp;
}



输出结果是
3 4 1 2

那么如果我将函数function做如下修改呢
void function (Object& o1, Object& o2)
{
    Object& temp=o1;
    o1=o2;
    o2=temp;
}

结果是:
3 4 3 4
这个结果在开始时让我大吃一惊,我反复分析最中还是失败了,我当时这样想的
如果这个变量我把它解释成像Java中的引用值,那么在第一次输出结果时应该是不会变的。
在Java中就是不变的输出结果。但是如果不解释成引用值又说不通,因为我很明确这肯定是个指针。我始终无法说服自己。最后我反汇编了代码,看看它到底做了什么。
首先是第一种情况
    function(o1, o2);
00411587  lea         eax,[o2]  
0041158A  push        eax  
0041158B  lea         ecx,[o1]  
0041158E  push        ecx  
0041158F  call        function (411023h)  
00411594  add         esp,8  

这说明它的确是把对象的内存空间压入了栈中,即传给了函数
void function (Object& o1, Object& o2)
{
00411770  push        ebp  
00411771  mov         ebp,esp  
00411773  sub         esp,0D0h  
00411779  push        ebx  
0041177A  push        esi  
0041177B  push        edi  
0041177C  lea         edi,[ebp-0D0h]  
00411782  mov         ecx,34h  
00411787  mov         eax,0CCCCCCCCh  
0041178C  rep stos    dword ptr es:[edi]  
    Object temp=o1;
0041178E  mov         eax,dword ptr [o1]  
00411791  mov         ecx,dword ptr [eax]  
00411793  mov         edx,dword ptr [eax+4]  
00411796  mov         dword ptr [temp],ecx  
00411799  mov         dword ptr [ebp-8],edx  
    o1=o2;
0041179C  mov         eax,dword ptr [o2]  
0041179F  mov         ecx,dword ptr [eax]  
004117A1  mov         edx,dword ptr [eax+4]  
004117A4  mov         eax,dword ptr [o1]  
004117A7  mov         dword ptr [eax],ecx  
004117A9  mov         dword ptr [eax+4],edx  
    o2=temp;
004117AC  mov         eax,dword ptr [o2]  
004117AF  mov         ecx,dword ptr [temp]  
004117B2  mov         dword ptr [eax],ecx  
004117B4  mov         edx,dword ptr [ebp-8]  
004117B7  mov         dword ptr [eax+4],edx  
}

这段汇编中
1. 开了新的内存空间给temp,并且把o1内存中的所有东西传给了temp。
其实在写这段代码之前我怀疑是否能编译通过,因为在我的分析下这两者属于不同的类型,but it did.
我们再来看看结果为3434的那段函数汇编
void function (Object& o1, Object& o2)
{
00411770  push        ebp  
00411771  mov         ebp,esp  
00411773  sub         esp,0CCh  
00411779  push        ebx  
0041177A  push        esi  
0041177B  push        edi  
0041177C  lea         edi,[ebp-0CCh]  
00411782  mov         ecx,33h  
00411787  mov         eax,0CCCCCCCCh  
0041178C  rep stos    dword ptr es:[edi]  
    Object& temp=o1;
0041178E  mov         eax,dword ptr [o1]  
00411791  mov         dword ptr [temp],eax  
    o1=o2;
00411794  mov         eax,dword ptr [o2]  
00411797  mov         ecx,dword ptr [eax]  
00411799  mov         edx,dword ptr [eax+4]  
0041179C  mov         eax,dword ptr [o1]  
0041179F  mov         dword ptr [eax],ecx  
004117A1  mov         dword ptr [eax+4],edx  
    o2=temp;
004117A4  mov         eax,dword ptr [temp]  
004117A7  mov         ecx,dword ptr [eax]  
004117A9  mov         edx,dword ptr [eax+4]  
004117AC  mov         eax,dword ptr [o2]  
004117AF  mov         dword ptr [eax],ecx  
004117B1  mov         dword ptr [eax+4],edx  
}

HoHO,奇迹发现了。
现在将这一切解释一下。

按照上图我们发现,其实对象是由一个指针维护着,对象的名字便是这个指针,这个概念很好理解,Java中也是这样,我们在学校的时候也是这样学的。但是引用值我们的老师告诉我们这是个别名。但是这个解释太具有中国式的含蓄,这也是为什么造成今日我的迷糊。其实引用也是个指针,他指向上面所说的那个指针,正如图所示。
好,他们之间的结构已经说清楚了,那为什么还会出现如此诡异的事呢?有人会问还诡异在哪里?
为什么在代码
Object& temp=o1;
o1=o2;
o2=temp;
执行完后结果会是3434呢?有人会解释说因为他是指针,交换的结果是指针互相对冲,使得最终都是那个指向o2的地址。
如果按照这个理论的话我们尝试解释
Object temp=o1;
o1=o2;
o2=temp;
首先必须申明o1是引用值,即他也是指向那段内存空间指针的指针。你不觉得一个指向指针的指针赋值给一个指向对象的指针,这好像很怪吗?
其实这一切的一切罪魁祸首是诡异的引用的赋值运算符。
他在引用使用它时会做点我们看不见的事,简单而言是这样的。
Object& temp=o1(引用赋值给引用) 结果是:使得两个引用值拥有相同的地址值
Object temp=o1 (引用赋值给对象) 结果是:引用将其指向的对象的内存空间完全赋值给新的对象
o1= Object temp(对象给引用赋值) 结果是:这是新建一个引用的常用语法,不解释
对象赋值给对象略
简而言之,引用的赋值运算符,不是简单的内存空间之间的交换,他会做出语义判断来决定到底是将地址值给对方呢,还是将指向的目标给对方,还是把指向目标的目标给对方。

其实如果C++的引用值做的和Java一样,那也就不会有这样的问题。

最后总结一下
1. C++的引用这个变量是一个地址
2. 引用之间的赋值运算是和Java中不一样的,他是有自己的机制的。



  • 大小: 10.3 KB
0
0
分享到:
评论

相关推荐

    C++引用.txt

    引用也叫做别名,为一个变量起一个名字,二者代表同一地址,也代表同一变量。 int a=1; int &b=a;//b是a的一个变量,初始化为a 声明一个变量时必须对其进行初始化。 声明一个变量的引用后,在函数执行期间,该引用...

    C++中类使用全局变量

    6. **封装**:如果一个变量需要在多个类之间共享,考虑使用静态成员变量或使用指针或引用传递,而不是全局变量。 总之,虽然全局变量在某些情况下可以简化代码,但过度依赖全局变量会导致代码难以理解和维护。在...

    C++指针与引用的区别

    sizeof 是一个运算符,用于获取变量或类型的大小。 联系 1. 引用在语言内部用指针实现;引用是 C++ 中的一种语法糖,实际上它是使用指针实现的。 2. 对一般应用而言,把引用理解为指针,不会犯严重语义错误。引用...

    深入浅出C++引用

    ### 深入浅出C++引用 #### 引言 C++作为一种强大的面向对象编程语言,提供了多种机制来帮助开发者编写高效、可维护的代码。其中,“引用”这一概念是C++中非常重要的特性之一,它使得程序员能够更加灵活地处理数据...

    C++引用传递.

    通过引用传递这些变量可以避免复制整个`float`类型的数据,从而提高程序效率。 2. **主函数**: ```cpp int main() { float a, b, sum, sub, pro; cin &gt;&gt; a &gt;&gt; b; // 读取用户输入的两个浮点数 Math(a, b, sum...

    C++变量与标准库

    本章节介绍了C++中关于变量和基本类型的知识点。通过理解这些基础概念,可以更好地掌握C++编程的基础知识,并为进一步学习高级特性打下坚实的基础。接下来可以进一步探索C++的标准库以及其他高级特性。

    C++_引用的作用和用法

    引用在C++中被视为某一变量(通常称为“目标变量”)的别名。通过引用操作变量,实际上是在操作变量本身,而不是它的副本。因此,引用提供了一种更为高效的方式来访问和修改变量。 ##### 引用的声明 引用的声明语法...

    c++中引用的用法和应用实例

    在C++编程语言中,引用(Reference)是一个非常重要的特性,它为程序员提供了另一种方式来访问和操作已存在的变量。引用不同于指针,它更像是一个变量的别名,一旦引用被初始化指向某个变量,就不能再改变引用的目标...

    c++按引用传递

    引用是一种强类型的别名,必须在初始化时指定其对应的对象。 引用与指针的区别 引用和指针都是C++中用来间接访问对象的机制,但是它们有着本质的区别。指针是一个变量,存储的是对象的内存地址,而引用则是对象的...

    C++中的引用

    在C++编程语言中,引用(Reference)是一个非常关键的概念,它提供了一种安全、高效的方式来间接访问和操作其他变量。引用不同于指针,它更像是一个变量的别名,一旦引用被初始化为某个变量,就不能再改变引用的目标...

    C++引用&和指针在作为形参时的区别

    而引用作为形参时,它实际上是原始变量的一个别名,所以对引用的修改会影响到原始变量,避免了内存问题。 考虑以下代码示例: ```cpp void fun(int* b) { b = (int*)malloc(sizeof(int)*3); for(int i=0; i; i++)...

    class1-c++及汇编下的各种变量类型

    本课程“class1-c++及汇编下的各种变量类型”旨在深入探讨这两种语言中的变量类型及其内存表示,这对于理解和优化代码性能,以及进行逆向工程分析具有重要意义。 首先,我们来详细讨论C++中的变量类型。C++是一种...

    C++引用 。.

    - **声明方式:** 类型标识符&引用名 = 目标变量名; - 例如:`int a; int& ra = a;` - 在这里,`ra` 是 `a` 的引用,即 `a` 的别名。 - **特点:** - 引用声明时必须初始化。 - 引用一旦绑定到一个变量上,就不...

    深入解析C++中的引用类型

    c++比起c来除了多了类类型外还多出一种类型:引用。这个东西变量不象变量,指针不象指针,我以前对它不太懂,看程序时碰到引用都稀里糊涂蒙过去。最近把引用好好地揣摩了一番,小有收获,特公之于社区,让初学者们...

    C++的变量、类型及函数

    #### 引用类型 - C++中的引用类似于别名,用于表示另一个变量。例如,`int &y = x;`声明了一个引用y,它是变量x的别名。 #### 变量初始化 - **C语言**:变量初始化通常使用常量表达式。局部非静态变量可以使用任意...

    c++第二章变量_c++变量课件_

    本课件旨在深入浅出地解释C++变量的概念、类型、声明、初始化以及使用方法。 1. 变量的概念: 变量可以被看作是程序中的一个存储位置,它具有特定的数据类型,用于存储值。每个变量都有一个唯一的名称(标识符),...

    C++ const引用、临时变量 引用参数详解

    C++引用—临时变量、引用参数和const引用 如果实参与引用参数不匹配,C++将生成临时变量。如果引用参数是const,则编译器在下面两种情况下生成临时变量: 实参类型是正确的,但不是左值 实参类型不正确,但可以转换为...

    C++ 引用经典总结

    在C++中,声明引用的语法是`类型标识符 &引用名=目标变量名`。例如,`int a; int &ra=a;`声明了一个名为`ra`的引用,它是`a`的别名。这里的`&`不是取地址运算符,而是用于表明`ra`是一个引用。引用必须在声明时就...

    C++指针与引用

    在C++中,指针和引用是两种非常重要的数据类型,它们都用于间接访问其他变量或对象。然而,它们之间存在显著的区别,了解这些差异对于有效、安全地使用C++语言至关重要。 - **指针**是一种变量,其值是内存地址。...

    C++引用和指针的区别,C++虚函数原理,C++面试经验

    "C++引用和指针的区别、C++虚函数原理、C++面试经验" C++ 引用和指针是两种不同的概念。虽然它们都可以用来表示内存地址,但是它们有着不同的特点和应用场景。 1. 相同点:引用和指针都是地址的概念,指针指向一块...

Global site tag (gtag.js) - Google Analytics