C++中引用和指针的不同
引用,其本质就是指针,将它用在一些特别的场合,会比指针更简洁,更方便。具体说来,指针多用于动态内存管理和对数组的操作等,C风格的代码接收和返回指针;引用则往往用在接收和返回类类型的名字空间域函数或类域函数,以避免类对象的复制开销。但是请注意,引用毕竟不完全等同于指针,它们有一些差异:
1、引用必须初始化,指针则不然。
int *pi;//可以
int &ri;//不行,未初始化
int i;int &ri=i;//可以
2、引用不能为空引用,指针则不然。
int *pi=NULL;//可以
int *pi=NULL;int &ri=*pi;//会引发问题。
3、引用在初始化后,不能再引用其他对象,指针则不然。
void f(int &ri)
{
int i=3;
ri=4;//改变所引用的实参
ri=&i;//错误,类型不符
ri=i;//ri并未转为引用局部变量i
}
虽然每次调用f时,都有可能会使形参ri,引用不同的实参,但是在f函数内,无法在调用处,引用初始化后,再改变其所引用的对象。显然包括引用在内,在很多时候,初始化与赋值运算符的语义有很大区别。
4、引用在必要时实现为指针,但是常规语法取不到这个内部指针的地址。
int i=3;int *pi=&i;//i的值为3,地址为&i;pi的值为&i,地址为&pi
int i=3;int &ri=i;//i的值为3,地址为&i;ri的值为3,地址为&i,初始化后ri和i基本为同义语。
实际上,当引用ri初始化为i后,语言实现可能只将ri优化处理成i的别名,而不将其实现为指针;也可能使用一个内部指针来完成工作。比如第3条中的f函数的形参ri,每次具体调用函数时,都可能会传入不同地址的实参。因为设计引用就是要避免对象复制的,因此它会压入堆栈一个指向被引用类型的指针。有可能这样来实现:
int i=3;
int &ri=i;//可实现为int *temp_pi=&i;以后每次源程序中使用ri时,就会被相应替换成*temp_pi
即使实现为这样的内部指针,也无法用正常的语法来取得它的地址。因为按照上边的分析,初始化后,取地址操作&ri将等价于&*temp_pi。那么这对用户来说,有什么会造成影响的不同吗?来看看一种不太常见的情况:可变个数参数表的省略号...前一个参数,如果是引用类型,将无法正常工作;如果是指针类型或简单类型等,则不会有问题。如有以下声明:
void f(int i,...);
则在实现代码中,可以使用C标准库的stdarg.h来取得可变个数部分的参数。有兴趣的话可以去看看stdarg.h的具体代码,它是用宏来完成的,针对不同的环境,采用了相应的手段。我用一段功能类似的伪代码来说明一下:
void f(int i,...)//此函数用i来表示可变个数参数的个数
{
int ix;
void *base=&i;
for(ix=0;ix<i;ix++)
{
base+=sizeof(int);//或者依实现为base-=sizeof(int)
cout<<"第"<<ix+1<<"个int参数的值为:";
cout<<*((int *)base)<<endl;
}
}
如果有调用f(5,1,2,3,4,5);则5,4,3,2,1,5将从右到左依次被压入堆栈,然后调用f函数。在f函数内部来看,那几个未命名的可变参数,是每个占一个sizeof(int)大小,一个接一个挨着放在堆栈上的,并且局部变量i指向了堆栈顶的位置。这时可以用相对于堆栈顶位置的位移量来取得每一个局部变量。当函数返回时,由调用点来清理堆栈。这样,f(5,1,2,3,4,5);和f(3,10,11,12);均可正确调用和返回,因为每处调用均知道自己用了几个参数,所以它可以在函数返回后,正确地在堆栈上弹出参数(其缺点就是每处调用都要自己清理,这样方式的程序长度,要比清理只出现在被调函数返回处的方式,要长一些)。这就是所谓的cdecl调用约定。然而,如果...前的参数为引用类型,如:
void f(const int &ri,...);//如果使用非左值进行调用,引用必须为const
调用f(5,1,2,3,4,5)将会发生什么呢?
因为int &ri是个引用参数,所以实际上会是:
push 5;
push 4;
push 3;
push 2;
push 1;
const int temp_i=5;
const int *temp_pi=&temp_i;
push temp_pi;
也就是说,和5个可变个数参数并排挨着的实参ri,在实际调用时,会被处理成向堆栈压进一个const int *类型的地址值。那么在f函数内的代码中,void *base=&ri;又将指向何处呢?按前面的分析,&ri会被处理成&*temp_pi,其结果就是temp_pi的值,temp_i的地址。试图取回和1、2、3、4、5挨着的这个内部指针的地址,其结果却是内部指针temp_pi的值,temp_i的地址,它并不在可变个数参数的1、2、3、4、5中1的旁边。所以调用将无法正常取得...部分的参数。
发表于 @ 2009年03月01日 14:19:00 | 评论( 0 ) | 编辑| 举报| 收藏
新一篇:精解C++的switch语句
本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/myliupp/archive/2009/03/01/3947023.aspx
C++中引用和指针的不同相关推荐
- C++中引用与指针的区别(详细介绍)
转载:http://www.cnblogs.com/tracylee/archive/2012/12/04/2801519.html C++中的引用与指针的区别 指向不同类型的指针的区别在于指针类型可 ...
- Java 基础 | Java 中引用与指针的关系
前言:关键字包含 #指针,java 引用,空指针,地址访问,引用类型,在 Java 编程语言中,程序员不需要担心程序的内存使用.Java 语言的自动垃圾收集器会不时地清理那些变成垃圾的对象. 如果垃圾 ...
- C++中引用,指针,指针的引用,指针的指针
定义一个指针的三种写法都对:1. int * p; 2. int* p; 3. int *p; 习惯不同而已 定义一个函数指针的三种写法都对:1. int *p(); 2. int * p(); ...
- c++中引用及指针详解
这里写目录标题 1.指针 1.1.什么是指针 指针的本质 指针与地址 程序中如何声明指针以及如何使用运算符&和* 1.2.指针有什么作用 指针与函数参数 2.引用 2.1.什么是引用 2.2. ...
- 浅谈C++中引用和指针的区别
之前我们介绍了什么是引用,错过的小伙伴们可以戳这里 ↓ https://blog.csdn.net/Sun_Life_/article/details/89304920 既然引用底层是用指针形式实现的 ...
- c++中引用和指针的区别
1.指针是一个实体,需要分配内存空间.引用只是变量的别名, 不需要分配内存空间. 2.引用在定义的时候必须进行初始化,并且不能够改变.指针在 定义的时候不一定要初始化,并且指向的空间可变.引用的初始 ...
- c++中的引用和python中的引用_【总结】C++、C#、Java、Javascript、Python中引用的区别...
首先分两大阵营:C++中引用是一块阵营, C#.Java.Javascript.Python中引用是另一块阵营. 之所以这样分是因为同一阵营中引用使用方法基本一样. C++引用本质是个常量指针,而其他 ...
- c++中的引用和指针
引用和指针 1.引用: 2.指针: 区别: 1.引用: C++是 C 语言的继承,它可进行过程化程序设计,又可以进行以抽象数据类型为特点的基于 对象的程序设计,还可以进行以继承和多态为特点的面向对象的 ...
- C++中引用传递与指针传递区别(进一步整理)
C++中引用传递与指针传递区别(进一步整理) 博客分类: C/C++ CC++C#J# 从概念上讲.指针从本质上讲就是存放变量地址的一个变量,在逻辑上是独立的,它可以被改变,包括其所指向的地址的改变 ...
最新文章
- 目标跟踪之卡尔曼滤波---理解Kalman滤波的使用
- jmeter中文_JMeter安装配置
- 正则表达式三 :编译
- Docker镜像加速器配置
- 卷积的C语言实现的MFC版本
- Java Thread pool的学习笔记
- 2021 NOI游记
- 线程池默认多少个线程_我需要多少个线程?
- 前端开发者必备的20个文档和在线工具
- a start job is running for延迟90s的解决办法
- [linux/ unix] 查看占用端口的 进程ID 的区别
- equals方法 和 ==的区别
- matlab求带参数二重定积分,matlab二重定积分
- 大学应用计算机应用基础课程介绍,大学计算机应用基础(Windows 7+Office 2010)(刘艳)...
- ESP32 INMP441麦克风驱动
- 软件工程(1)软件开发方法
- nginx小技巧-动态域名(微信,小程序80端口)
- WordPress 5.2中的致命错误恢复模式
- 服务器数据恢复的两种方法
- 【云原生-K8s】cka认证2022年12月最新考题及指南
热门文章
- javascript高精度计算解决方案
- Java IO流--练习2
- Oracle Database_buffer_cache大小的设置及依据
- 什么是缓存里的脏数据.
- yar java_Yar 的传输协议学习以及 Java 版本的实现
- python贪婪匹配顺序_Python正则表达式:贪婪模式返回多个空匹配
- imdb导mysql_keras如何导入本地下载的imdb数据集?
- SpringCloud 应用在 Kubernetes 上的最佳实践 — 线上发布(可灰度)
- mac怎么合并两个容器_PDF怎样合并?在Mac上合并PDF文件的最佳方法
- xamarin textview 滚动_Apple Music有原生滚动歌词了!喜大普奔!