Normal
0

7.8 磅
0
2

false
false
false

EN-US
ZH-CN
X-NONE

MicrosoftInternetExplorer4



关于引用和指针的差别的文章非常多非常多,可是总是找不到他们的根本差别,偶然在codeproject上看到这篇文章,认为讲的挺好的,

所以翻译了下,希望对大家有帮助。

原文地址: http://www.codeproject.com/KB/cpp/References_in_c__.aspx

引言

我选择写
C++
中的引用是由于我感觉大多数人误解了引用。而我之所以有这个感受是由于我主持过非常多
C++
的面试,而且我非常少从面试者中得到关于
C++
引用的正确答案。

那么
c++
中引用究竟意味这什么呢?通常一个引用让人想到是一个引用的变量的别名,而我讨厌将
c++
中引用定义为变量的别名。这篇文章中,我将尽量解释清楚,
c++
中根本就没有什么叫做别名的东东。

背景


c/c++
中,訪问一个变量仅仅能通过两种方式被訪问,传递,或者查询。这两种方式是:

1.
通过值
訪问
/
传递变量

2.
通过地址
訪问
/
传递变量

这样的方法就是指针

除此之外没有第三种訪问和传递变量值的方法。引用变量也就是个指针变量,它也拥有内存空间。最关键的是引用是一种会被编译器自己主动解引用的指针。非常难相信么?让我们来看看吧。。。

以下是一段使用引用的简单
c++
代码

#include <iostream.h>
int main()
{
int i = 10; // A simple integer variable
int &j = i; // A Reference to the variable i
j++; // Incrementing j will increment both i and j.
// check by printing values of i and j
cout<< i << j <<endl; // should print 11 11
// Now try to print the address of both variables i and j
cout<< &i << &j <<endl;
// surprisingly both print the same address and make us feel that they are
// alias to the same memory location.
// In example below we will see what is the reality
return 0;
}

引用事实上就是
c++
中的常量指针。表达式
 
int &i = j;
将会被编译器转化成
int *const i = &j;
而引用之所以要初始化是由于
const
类型变量必须初始化,这个指针也必须有所指。以下我们再次聚焦到上面这段代码,并使用编译器的那套语法将引用替换掉。

#include <iostream.h>
int main()
{
int i = 10; // A simple integer variable
int *const j = &i; // A Reference to the variable i
(*j)++; // Incrementing j. Since reference variables are
// automatically dereferenced by compiler
// check by printing values of i and j
cout<< i << *j <<endl; // should print 11 11
// A * is appended before j because it used to be reference variable
// and it should get automatically dereferenced.
return 0;
}

读者一定非常奇怪为什么我上面这段代码会跳过打印地址这步。这里须要一些解释。由于引用变量时会被编译器自己主动解引用的,那么一个诸如
 
cout << &j
<< endl;
的语句,编译器就会将其转化成语句
 
cout << &*j << endl;

如今
&*
会相互抵消,这句话变的毫无意义,而
cout
打印的
j
值就是
i
的地址,由于其定义语句为
int *const
j = &i;

所以语句
cout << &i << &j << endl;
变成了
cout << &i << &*j << endl;
这两种情况都是打印输出
i
的地址。这就是当我们打印普通变量和引用变量的时候会输出同样地址的原因。

以下给出一段复杂一些的代码,来看看引用在级联
(cascading)
中是怎样运作的。

#include <iostream.h>
int main()
{
int i = 10; // A Simple Integer variable
int &j = i; // A Reference to the variable
// Now we can also create a reference to reference variable.
int &k = j; // A reference to a reference variable
// Similarly we can also create another reference to the reference variable k
int &l = k; // A reference to a reference to a reference variable.
// Now if we increment any one of them the effect will be visible on all the
// variables.
// First print original values
// The print should be 10,10,10,10
cout<< i << "," << j << "," << k << "," << l <<endl;
// increment variable j
j++;
// The print should be 11,11,11,11
cout<< i << "," << j << "," << k << "," << l <<endl;
// increment variable k
k++;
// The print should be 12,12,12,12
cout<< i << "," << j << "," << k << "," << l <<endl;
// increment variable l
l++;
// The print should be 13,13,13,13
cout<< i << "," << j << "," << k << "," << l <<endl;
return 0;
}

以下这段代码是将上面代码中的引用替换之后代码,也就是说明我们不依赖编译器的自己主动替换功能,手动进行替换也能达到同样的目标。

#include <iostream.h>
int main()
{
int i = 10; // A Simple Integer variable
int *const j = &i; // A Reference to the variable
// The variable j will hold the address of i
// Now we can also create a reference to reference variable.
int *const k = &*j; // A reference to a reference variable
// The variable k will also hold the address of i because j
// is a reference variable and
// it gets auto dereferenced. After & and * cancels each other
// k will hold the value of
// j which it nothing but address of i
// Similarly we can also create another reference to the reference variable k
int *const l = &*k; // A reference to a reference to a reference variable.
// The variable l will also hold address of i because k holds address of i after
// & and * cancels each other.
// so we have seen that all the reference variable will actually holds the same
// variable address.
// Now if we increment any one of them the effect will be visible on all the
// variables.
// First print original values. The reference variables will have * prefixed because
// these variables gets automatically dereferenced.
// The print should be 10,10,10,10
cout<< i << "," << *j << "," << *k << "," << *l <<endl;
// increment variable j
(*j)++;
// The print should be 11,11,11,11
cout<< i << "," << *j << "," << *k << "," << *l <<endl;
// increment variable k
(*k)++;
// The print should be 12,12,12,12
cout<< i << "," << *j << "," << *k << "," << *l <<endl;
// increment variable l
(*l)++;
// The print should be 13,13,13,13
cout << i << "," << *j << "," << *k << "," << *l <<endl;
return 0;
}

我们通过以下代码能够证明
c++
的引用不是神马别名,它也会占用内存空间的。

#include <iostream.h>
class Test
{
int &i; // int *const i;
int &j; // int *const j;
int &k; // int *const k;
};
int main()
{
// This will print 12 i.e. size of 3 pointers
cout<< "size of class Test = " << sizeof(class Test) <<endl;
return 0;
}

结论

我希望这篇文章能把
c++
引用的全部东东都解释清楚,然而我要指出的是
c++
标准并没有解释编译器怎样实现引用的行为。所以实现取决于编译器,而大多数情况下就是将事实上现为一个
const
指针。

引用支持
c++
虚函数机制的代码

#include <iostream.h>
class A
{
public:
virtual void print() { cout<<"A.."<<endl; }
};
class B : public A
{
public:
virtual void print() { cout<<"B.."<<endl; }
};

class C : public B
{
public:
virtual void print() { cout<<"C.."<<endl; }
};
int main()
{
C c1;
A &a1 = c1;
a1.print(); // prints C
A a2 = c1;
a2.print(); // prints A
return 0;
}

上述代码使用引用支持虚函数机制。假设引用不过一个别名,那怎样实现虚函数机制,而虚函数机制所须要的动态信息只能通过指针才干实现,所以更加说明引用事实上就是一个
const
指针。

深入分析C++引用的更多相关文章

  1. [转]数组引用:C++ 数组做参数 深入分析

    "数组引用"以避免"数组降阶"(本文曾贴于VCKBASE\C++论坛) 受[hpho]的一段模板函数的启发,特写此文,如有雷同,实在遗憾. 数组降阶是个讨厌的事 ...

  2. 数组引用:C++ 数组做参数 深入分析

    转载:https://blog.csdn.net/jiangxinyu/article/details/7767065 在 C++中,数组永远不会按值传递,它是传递第一个元素,准确地说是第 0个 的指 ...

  3. C++ 中的 const、引用和指针的深入分析

    1,关于 const 的疑问: 1,const 什么时候为只读变量,什么时候是常量: 1,const 从 C 到 C++ 进化的过程中得到了升级,const 在 C++ 中不仅仅像在 C 中声明一个只 ...

  4. Spring 循环引用(三)源码深入分析版

    @ 目录 前言 正文 分析 doGetBean 为什么Prototype不可以 createBean doCreateBean getEarlyBeanReference getSingleton b ...

  5. 深入分析Spring 与 Spring MVC容器

    1 Spring MVC WEB配置 Spring Framework本身没有Web功能,Spring MVC使用WebApplicationContext类扩展ApplicationContext, ...

  6. block中如何避免循环引用

    使用 weak–strong dance 技术 block 可以直接引用 self,但是要非常小心地在 block 中引用 self.因为在 block 引用 self,可能会导致循环引用.如下例所示 ...

  7. 深入分析PHP优化及注意事项

    深入分析PHP优化及注意事项 1.尽量静态化: 如果一个方法能被静态,那就声明它为静态的,速度可提高1/4,甚至我测试的时候,这个提高了近三倍. 当然了,这个测试方法需要在十万级以上次执行,效果才明显 ...

  8. Java多线程之ConcurrentSkipListMap深入分析(转)

    Java多线程之ConcurrentSkipListMap深入分析   一.前言 concurrentHashMap与ConcurrentSkipListMap性能测试 在4线程1.6万数据的条件下, ...

  9. Android关于Theme.AppCompat相关问题的深入分析(转)

    http://www.jianshu.com/p/6ad7864e005e 先来看这样一个错误: No resource found that matches the given name '@sty ...

随机推荐

  1. WebService CXF调试常见报错及解决方案

    1.CXF java.lang.RuntimeException: Cannot create a secure XMLInputFactory 解决方案:从apache-cxf/lib下寻找Wood ...

  2. extjs之messagebox按钮显示中文

    在extjs中我们用到了很多的提示框,但是在对话框按钮上面显示的都是英文的ok.yes.no.cancel,这里给出一个方法,能够使得提示框的按钮文本显示问中文. extjs在加载完成之后会调用页面的 ...

  3. Thinkphp发布文章获取第一张图片为缩略图实现方法

    正则匹配图片地址获取第一张图片地址 此为函数 在模块或是全局Common文件夹中的function.php中 /** * [getPic description] * 获取文本中首张图片地址 * @p ...

  4. 发一个自己写的php框架

    这个框架是我在学习php初期练手写的,现在分享出来希望对初学者有一定帮助. 目录结构:app:网站系统目录    ---common:网站配置目录    ---tpl:网站模板目录    ---log ...

  5. 转:Python 与 Excel 不得不说的事

    数据处理是 Python 的一大应用场景,而 Excel 则是最流行的数据处理软件.因此用 Python 进行数据相关的工作时,难免要和 Excel 打交道. 如果仅仅是要以表单形式保存数据,可以借助 ...

  6. Python的多线程实现

    概述 Python虚拟机使用GIL(Global Interpreter Lock,全局解释器锁)来实现互斥线程对共享资源的访问,暂时无法利用多处理器的优势. Python中,thread和threa ...

  7. powerpoint2015如何调整PPT立体图形

    在powerpoint2016中,可以添加图片来丰富演说,但通常人们只会懂得插入平面图片.动态图片,立体图片就无法插入了吗?不是的,在powerpoint2016为我们准备了大量的预设,可以调整图片, ...

  8. HDU 1005(周期问题)

    HDU 1005 Time Limit:1000MS     Memory Limit:32768KB     64bit IO Format:%I64d & %I64u   Descript ...

  9. 1001WA

    时间关系只实现了其中一部分的功能  现在的程序可以实现一个大数的平方 #include <stdio.h> #include <string.h> void mypower(i ...

  10. python中快速删除实例对象中的所有属性

    def DeleteObjectAllProperties(objectInstance): if not objectInstance: return listPro =[key for key i ...