C++中的指针与引用详细解读
作者:网络转载 发布时间:[ 2015/8/18 13:37:43 ] 推荐标签:测试开发技术 编程语言
写在前面
指针和引用形式上很好区别,但是他们似乎有相同的功能,都能够直接引用对象,对其进行直接的操作。但是什么时候使用指针?什么时候使用引用呢?这两者很容易混淆,在此我详细介绍一下指针和引用,力争将真实的一面展现给大家。如果我喷得不够好,希望嘴下留情、手下留命,还请指点一二;如果感觉还不错,请大家鼓掌。
1、指针和引用的定义
在深入介绍之前我们首先来看一下指针和引用的定义、指针和引用的区别,然后分别针对指针和引用展开讨论,深入细节为何有这些差异。
指针的权威定义:
In a declaration T D where D has the form * cv-qualifier-seqopt D1 And the type of the identifier in the declaration T D1 is “derived-declarator-type-list T”, then the type of the identifier of D is “derived-declarator-type-list cv-qualifier-seq pointer to T”. The cv-qualifiers apply to the pointer and not to the object pointer to.
——摘自《ANSI C++ Standard》
注:可能有些读者并不明白cv-qualifier-seq
CV-qualifiers(CV限定符)
CV-qualifiers有三种:const-qualifier(const限定符)、Volatile-qualifier(volatile限定符)、以及const-volatile-qualifier(const-volatile限定符)。
const类对象的非静态、非mutable、以及非引用数据成员是const-qualified;
volatile类对象的非静态、非引用数据成员是volatile-qualified;
const-volatile类对象的非静态、非引用数据成员是const-volatile-qualified。
当CV-qualifiers用于限定数组类型时,实际上是数组成员被该CV-qualifiers限定,而非该数组类型。
复合类型并不因其成员被CV-qualifier限定而被该CV-qualifier限定,也是说,即使复合类型的成员有CV-qualifier限定,该复合类型也不是CV-qualified对象。
引用的权威定义:
In a declaration T D where D has the form& D1 And the type of the identifier in the declaration T D1 is “derived-declarator-type-list T”, then the type of the identifier of D is “derived-declarator-type-list cv-qualifier-seq reference to T”. Cv-qualified references are ill-formed except when the cv-qualifiers are introduced through the use of a typedef or a template type argument, in which case the cv-qualifiers are ignored.
——摘自《ANSI C++ Standard》
上面这些定义初看有些难懂,如果是这样的话,那说明你对C++还不够熟悉,你还有很长的路要走。下面用通俗易懂的话来概述一下:
指针-对于一个类型T,T*是指向T的指针类型,也即一个T*类型的变量能够保存一个T对象的地址,而类型T是可以加一些限定词的,如const、volatile等等。见下图,所示指针的含义:
引用-引用是一个对象的别名,主要用于函数参数和返回值类型,符号X&表示X类型的引用。见下图,所示引用的含义:
2、指针和引用的区别
首先,引用不可以为空,但指针可以为空。前面也说过了引用是对象的别名,引用为空——对象都不存在,怎么可能有别名!故定义一个引用的时候,必须初始化。因此如果你有一个变量是用于指向另一个对象,但是它可能为空,这时你应该使用指针;如果变量总是指向一个对象,i.e.,你的设计不允许变量为空,这时你应该使用引用。如下图中,如果定义一个引用变量,不初始化的话连编译都通不过(编译时错误):
而声明指针是可以不指向任何对象,也正是因为这个原因,使用指针之前必须做判空操作,而引用不必。
其次,引用不可以改变指向,对一个对象”至死不渝”;但是指针可以改变指向,而指向其它对象。说明:虽然引用不可以改变指向,但是可以改变初始化对象的内容。例如++操作而言,对引用的操作直接反应到所指向的对象,而不是改变指向;而对指针的操作,会使指针指向下一个对象,而不是改变所指对象的内容。见下面的代码:
#include<iostream>
using namespace std;
int main(int argc,char** argv)
{
int i=10;
int& ref=i;
ref++;
cout<<"i="<<i<<endl;
cout<<"ref="<<ref<<endl;
int j=20;
ref=j;
ref++;
cout<<"i="<<i<<endl;
cout<<"ref="<<ref<<endl;
cout<<"j="<<j<<endl;
return 0;
}
对ref的++操作是直接反应到所指变量之上,对引用变量ref重新赋值”ref=j”,并不会改变ref的指向,它仍然指向的是i,而不是j。理所当然,这时对ref进行++操作不会影响到j。而这些换做是指针的话,情况大不相同,请自行实验。输出结果如下:
再次,引用的大小是所指向的变量的大小,因为引用只是一个别名而已;指针是指针本身的大小,4个字节。见下图所示:
从上面也可以看出:引用比指针使用起来形式上更漂亮,使用引用指向的内容时可以之间用引用变量名,而不像指针一样要使用*;定义引用的时候也不用像指针一样使用&取址。
后,引用比指针更安全。由于不存在空引用,并且引用一旦被初始化为指向一个对象,它不能被改变为另一个对象的引用,因此引用很安全。对于指针来说,它可以随时指向别的对象,并且可以不被初始化,或为NULL,所以不安全。const 指针虽然不能改变指向,但仍然存在空指针,并且有可能产生野指针(即多个指针指向一块内存,free掉一个指针之后,别的指针成了野指针)。
总而言之,言而总之——它们的这些差别都可以归结为”指针指向一块内存,它的内容是所指内存的地址;而引用则是某块内存的别名,引用不改变指向。”
相关推荐
更新发布
功能测试和接口测试的区别
2023/3/23 14:23:39如何写好测试用例文档
2023/3/22 16:17:39常用的选择回归测试的方式有哪些?
2022/6/14 16:14:27测试流程中需要重点把关几个过程?
2021/10/18 15:37:44性能测试的七种方法
2021/9/17 15:19:29全链路压测优化思路
2021/9/14 15:42:25性能测试流程浅谈
2021/5/28 17:25:47常见的APP性能测试指标
2021/5/8 17:01:11