深入分析C++引用
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++引用的更多相关文章
- [转]数组引用:C++ 数组做参数 深入分析
"数组引用"以避免"数组降阶"(本文曾贴于VCKBASE\C++论坛) 受[hpho]的一段模板函数的启发,特写此文,如有雷同,实在遗憾. 数组降阶是个讨厌的事 ...
- 数组引用:C++ 数组做参数 深入分析
转载:https://blog.csdn.net/jiangxinyu/article/details/7767065 在 C++中,数组永远不会按值传递,它是传递第一个元素,准确地说是第 0个 的指 ...
- C++ 中的 const、引用和指针的深入分析
1,关于 const 的疑问: 1,const 什么时候为只读变量,什么时候是常量: 1,const 从 C 到 C++ 进化的过程中得到了升级,const 在 C++ 中不仅仅像在 C 中声明一个只 ...
- Spring 循环引用(三)源码深入分析版
@ 目录 前言 正文 分析 doGetBean 为什么Prototype不可以 createBean doCreateBean getEarlyBeanReference getSingleton b ...
- 深入分析Spring 与 Spring MVC容器
1 Spring MVC WEB配置 Spring Framework本身没有Web功能,Spring MVC使用WebApplicationContext类扩展ApplicationContext, ...
- block中如何避免循环引用
使用 weak–strong dance 技术 block 可以直接引用 self,但是要非常小心地在 block 中引用 self.因为在 block 引用 self,可能会导致循环引用.如下例所示 ...
- 深入分析PHP优化及注意事项
深入分析PHP优化及注意事项 1.尽量静态化: 如果一个方法能被静态,那就声明它为静态的,速度可提高1/4,甚至我测试的时候,这个提高了近三倍. 当然了,这个测试方法需要在十万级以上次执行,效果才明显 ...
- Java多线程之ConcurrentSkipListMap深入分析(转)
Java多线程之ConcurrentSkipListMap深入分析 一.前言 concurrentHashMap与ConcurrentSkipListMap性能测试 在4线程1.6万数据的条件下, ...
- Android关于Theme.AppCompat相关问题的深入分析(转)
http://www.jianshu.com/p/6ad7864e005e 先来看这样一个错误: No resource found that matches the given name '@sty ...
随机推荐
- tomcat - 部署Web应用
概述 以前,安装李刚的JavaEE里面说的方法部署应用的时候,无意中成功,但是后来每次要录视频的时候,又报错,思来想去,tomcat都重启了好多次了,配置文件也试过很多次了,还是不行.无意中发现了问题 ...
- Android客户端采用Http 协议Post方式请求与服务端进行数据交互(转)
http://blog.csdn.net/javanian/article/details/8194265
- NSString截取字符串
NSString 是经常会用到的,很多时候需要对字符串进行一些处理,本文简单介绍字符串截取操作: 比如: 1.定义一个字符串a, 截取a的某一个部分(子串) NSString *a = @" ...
- java事件监听机制(自定义事件)
java中的事件机制的参与者有3种角色: 1.event object:事件状态对象,用于listener的相应的方法之中作为参数,一般存在与listerner的方法之中 2.event source ...
- Neutron/ML2学习
Neutron/ML2 Neutron ML2 模块层2(ml2)插件是一种允许OpenStack网络同时地利用在复杂现实数据中心发现的各种第二层网络技术的框架.目前它与存在的openvswitch. ...
- Unique Binary Search Tree
Given n, how many structurally unique BST's (binary search trees) that store values 1...n? For examp ...
- Mybatis3.0防止SQL注入
一.什么是SQL注入 引用搜狗百科: SQL注入,就是通过把SQL命令插入到Web表单提交或输入域名或页面请求的查询字符串,最终达到欺骗服务器执行恶意的SQL命令,比如很多影视网站泄露VIP会员密码大 ...
- css伪元素
CSS 伪元素用于向某些选择器设置特殊效果. 1.:first-line 伪元素 "first-line" 伪元素用于向文本的首行设置特殊样式.注意:"first-li ...
- django group_by
from django.db.models import Count Members.objects.values('designation').annotate(dcount=Count('desi ...
- 钟表维修管理系统技术解析(一) MVC架构搭建
钟表维修管理系统技术解析(一) MVC架构搭建 1.1新建项目 第一步:打开VS2010界面,点击左上角文件,点击新建,选择项目 1.1(图1) 第二步:点击网站Web类型,选择ASP.net MV ...