引用与指针

来源:互联网 发布:mac 10 少女前线 编辑:程序博客网 时间:2024/05/22 01:31

引用与指针的简单描述

首先要说的是,&有两种用处,一种是取地址操作符,还有一种是引用的标记,这两种用处基本上可以认为是没有联系。同理,*也有两种用处,一种是解引用,也可以称为取某地址的内容,还有一种是指针的标记,这两种用处也是没有联系的。

引用,准确的是定义了一个别名。如,

int a = 2;
int &= a;

可以认为ba的别名,ab的内容相同(a等于b),ab的地址也相同(&a等于&b)。也就是它们根本就是同一个“东西”,改变了其中一个,另一个也必将改变。这有点像Linux中的硬链接,对某一文件创建一个硬链接后,这两个文件名对应同一个inode值,即是这两个文件名代表了同一个文件。

指针,就好比Linux中的符号链接(类似Windows中的快捷方式),产生了新的文件类型,对某一文件创建一个符号链接,这两个文件名对应于两个不同的inode值。如

int a = 2;
int *= &a;

可见ab的类型不同,a是整型,而b是指向整型的指针,一个不同于a的类型。只是b指向a(即存放着a的地址),就好像是一个符号链接(快捷方式)。

从上面可以看出引用和指针基本没什么关系,只是形似神不似。但是我们总喜欢把它们混在一起嚼嚼。

 

引用与指针的比较

不管是硬链接,还是符号链接,总是可以间接的访问另一个对象(文件)。同样,引用和指针也可以间接的访问另一个值(准确的称为对象),只是访问的方式不同。第一,引用总是指向某个对象(可以这么说,一个引用永远指向用来对它初始化的那个对象),在定义引用时没有初始化将报错,还有记住不存在所谓的空引用。没有初始化的引用就好比是没有inode值的硬链接,这是不可想象的。指针则不同,可以不初始化,可以不指向任何对象(空指针),也可以指向任何对象,看如下

int *a; // 没有初始化,只是警告,但建议初始化
int *= NULL; // 空指针,不指向任何对象
void *c; // 可以指向任何对象

第二,赋值时有很大的差异,看如下指针的赋值

int a = 1, b = 2;
int *pa = &a, *pb = &b;
pa = pb;

赋值后,a的值保持不变,pa所指向的对象改变了,papb都将指向对象b

再看如下引用的赋值

int a = 1, b = 2;
int &ra = a, &rb = b;
ra = rb;

赋值操作,只是将rb的值赋给ra,使得raa的值变为了2,但是它们之间的引用关系并未改变。总的来说,给引用赋值修改的是该引用所关联的对象的值,而给指针赋值修改的是该指针本身的值,即指向了另一对象。

引用和指针还有很多不同点,引用主要用作函数的形参,const引用在函数的形参中也很常用。指针比引用更为灵活,用途非常广,也更为不安全,用引用就可以解决问题,就用引用,否则用指针。

 

const、引用和指针

u       const引用:

是指向const对象的引用,被广泛的应用与函数形参。看如下

const int a = 1;
const int &ra = a; // OK,可以读取ra但不可修改ra
int const &ra = a; // 与上等价 


int b = 2;
const int &rb = b; // OK,可以读取rb但不可以通过rb达到修改rb或b的目的
// 可以通过修改b来修改rb的值。这种方式在函数形参中很常见(这得益于传引用性能要高于传值) 


const int c = 3;
int &rc = c; // 错误,一个非const引用类型不可以指向const对象
// 试想,如果这样可以,那么通过rc就可以改变c的值,这是不可想象的


const int &rd = 4; // OK,rd引用的是一个用来保存4的临时变量
// 这种做法在参数传递中尤为可见
// 要注意的是,一个指向非常量的引用是不可以用字面值或临时变量进行初始化

总结,非const引用只能绑定到与该引用同类型的对象。const引用则可以绑定到不同但相关的类型的对象或绑定到右值(如常量)。

 

u       指向const对象的指针(指向常量的指针):

const int *a; a是一个指向int型常量的指针,const限定了a指针所指向的对象,而非a本身。因此在定义时不一定要对其进行初始化(如同未初始化的指针一样,会有警告),如果需要可以为a重新赋一个指向另一个常量对象(如同const引用一样,不一定要常量),但是不能通过a修改其所指向的对象(这一点,很好理解,否则就可以通过指针来达到修改常量的目的)。例子如下(如下情况与const引用类似)

const a = 1;
const int *pa = &a;
int const *pa = &a; 
// 与上等价,这是推荐用法

int b = 1;
const int *pb = &b; // OK,于是指向const的指针可以理解为“自以为指向const的指针”
// 指向常量的指针常用作函数的形参

const int c = 3;
int *pc = &c; // 错误

u       const指针(常量指针):

既然常量指针是一个常量,那么它首先满足的是常量的一些性质,如指针值不可以改变,必须初始化,不允许给常量指针重新赋值,哪怕是赋同样的值。看如下

int a = 1;
int *const ca = &a; // 读作指向int型对象的常量指针,指针值不可以改变
// 即不能使ca指向其他对象,但指向的对象a的值可以改变

const int b = 2;
int *const cb = &b; // 错误,这种错误与上面的错误非常类似

要说明的是this指针的类型是T *const ; 即指向非常量的常量指针。

 

注:当然还有指向常量的常量指针,但是这种“东西”没什么市场价值,PASS掉。有些地方,将这里的const指针称为指针常量,将这里的指向const对象的指针称为常量指针。这种称法也是有一定的道理的,很难分孰优孰劣。

0 0