C++的那点事,const,指针和引用的混合使用

来源:互联网 发布:手机网络连通性异常 编辑:程序博客网 时间:2024/04/28 05:45

对于学习Java或者C#的程序员来说,学习C++的时候,大概看到那些使用const int*& a之类的当参数时都会蒙了吧··

老实说,尽管当时我觉得自己C++书都看差不多了,学得也可以,但实际上,看到const,"*","&"的混合使用时,我也蒙了。

这篇文章就我自己的一些看法来谈谈不同的混合方式都有什么作用。

 

  • 没有const的时候。

 

没有const时,也就是*和&的混合使用。这里又分&是当取地址运算符或者是引用运算符两种情况,怎么区分&是取地址还是引用呢?

很简单,如果&之前没有类型就是用作引用,否则就是当取地址符。例如:int& 这是引用,int* p = &a 这是取地址。

 

1.&是取地址时:

 

这种情况在谭浩强的C++程序设计里面有说明 P168

如果有int* p = &a;那么 &*p 是什么含义呢?

由于"&"和"*"的优先级都为3,但按自右至左方向结合。所有&*p = &(*p) = &a = p,也就是a的地址

 

下面程序的输出结果是一样的。

 

 

那么 *&a 的含义呢?同样可以分析,*&a = *(&a) = *p = a,也就是说,*&a与a等价。

同样的,下面程序的输出结果是一样的。

 

2.&是引用时:

 

这种情况大多出现在函数形参里,当初也是这种情况把我搞混了。

例如如果一个函数的形参是 int*& p ,那么它代表的是什么意思,又有什么作用呢?

 

可以这样理解:int*& = (int*)&,也就是一个整型指针的引用。这又有怎么作用呢?

这里用一个例子来说明,引自谭浩强的C++程序设计里的P173

上面这段代码试图通过函数更改两个指针的指向来达到交换的功能,即不改变a和b的值,但改变pointer_1和pointer_2的指向来达到使pointer_1指向较大值,而pointer_2指向较小值。但通过输出的结果看,这并不成功。

 

为什么呢?

 

我们都知道,函数调用时会虚实结合,即把实参拷贝给形参(引用除外),这里的形参是指针也是一样的。

也就说调用时,系统在堆栈上创建了两个整型指针变量(它们确实占用了另一段内存),所以更改它们不会影响到实参。

具体过程如下图所示:

 

那么怎么在函数内改变实参指针的指向呢?答案就是用*&,也就是指针的引用。首先要强调一点的是,有些初学C++的人会搞不清楚引用的实现机制,以为引用跟指针用法一样(我当初就这样想的),但其实它们区别很大。下面说说我对引用的一些看法,或许对你有帮助。

 

书上一般会说:引用是为一个变量取一个别名。

我觉得这样反而不好理解,如果这样说呢:引用是与变量使用同一块内存。

如果将变量看成是一小块内存,那么使用不同内存的变量自然不能当成是同一个变量,尽管它们的值可以一样,但更改一处并不会改变另一处。但引用就是使用相同内存的,所以引用可以看成是与变量是同一个变量。

 

看下面的例子:

从结果中可以看到,a和b的地址是一样的,而且在函数f1的形参与实参的地址也是一样的,而不是用引用的f2的地址就不同。而我们也可以用指针指向引用变量,也可以用引用当作整型参数来传递。所以说引用跟原变量完全就是同一个变量。

 

可以用下面一段代码来实现在函数内改变实参指针的指向:

运行上面的代码,可以看到,调用Fun1后,p的指向依然是a,但调用Fun2后,p的指向就改到b了。也验证了上面那个说法。

 

至于另一种情况,也就 int&* 的情况,这个情况大家上机一试就知道了,是不同通过编译的。原因很简单,没有这样的定义。

 

 

  • 有const的情况

 

在搞懂了没有const的情况后,有const的情况无非就是加了一层常量限定了。

 

1.const与*的结合

首先是3个常见的const和指针的结合:const int* p,int* const p,const int* const p。

这3种在大部分的C++书籍上都有介绍了。分别是:

const int* p ------------- 指向常量的指针

int* const p ------------- 常指针

const int* const p ------ 指向常量的常指针

 

这3种也是一般用在函数参数里比较多。

这里稍微介绍一下:

const int* p 不能改变指针指向的值,可以改变其指向。即*p = 1是非法的,而p = &b是合法的。

int* const p 能改变指针所指向的值,不可以改变其指向。即*p = 1是合法的,而p = &b是非法的。

const int* const p 不能改变指针所指向的值,也不可以改变其指向。即*p = 1和p = &b都是非法的。

 

怎么记忆着三种奇怪的写法呢?这里是我的记忆方法:

使用左结合:

const int* p => (const int)* p 也就是一个指针所指向的是常量

int* const p => ((int*) const) p 也就是一个指针本身是常量

而const int* const 就是两者的结合。

 

2.const与&的结合

下面看看const 和 & 的结合使用。

最常见的就要数: const int& a 了,这个最常使用在类的拷贝构造函数里,这就是默认的写法。

这个理解起来很简单,就是使用引用,同时又是常量。跟const int a的区别就在于:

在函数虚实结合时,有&的使用引用方式,而没有的就是值传递。

 

我刚开始以为也会有 int& const a 的形式,后来试了一下,确实有,但是没用。

看下面的代码:

这段代码可以通过编译,最后结果是实参a的值改为3了,也就是说int& const a 是等价于int& a的。

 

本来我猜想, const int& const a 是等价于const int& a的。后来才发现这种写法是编译不过的。呵呵··

 

3.const、*、&的结合

最后就是3种形式的结合,const 和 * 和 &的结合。

 

1. const int*& p 的使用

这个应该算是比较常见到一种了吧,第一次看的时候相信很多人都会蒙了吧,呵呵

上面提到了int*&是指针的引用,不要以为const int*&是(const) (int*&)是这两组的组合意思,根据左结合,

const int*&是(const int*)&的意思,前面也提到const int*是指向常量的指针的意思,那么

const int*&就是指向常量的指针的引用的意思

看下面的代码:

综合地说,const int*&的功能如下:

不能改变指针所指向的值,可以改变指针的指向,改变形参指针的指向会改变实参的指向。

 

2.int*& const p 的意思

经过测试,int*& const是等价于int*&的,也就说后面的const不起作用。

 

3.同理,const int*& const 是不能通过编译的。

 

各位看客是不是以为到此为止呢,呵呵,还有一些可能你想都没想到的用法呢!

4.int* const &p 的使用

通过前面那么多的分析,大家也试试猜猜这个用法的意思。采用左结合

int* const &p => (int* const)& p 也就是一个常指针的引用。

同样用一小段代码来测试一下:

老实说,这是个只有无聊的人才会想到的用法(狂晕),我们分析一下:

我们在指针型的形参加引用是为了可以改变实参的指向,但我们又定义了形参是一个不能改变指向的常指针。所以:

int* const& p 是等价于 int* const的。

 

  • 总结:

 

可能会有人说这种用法int const *,这个···翻翻书就知道了,这个是等价于int* const的,也就是const 和 * 的位置可以换的。

上面说了很多组合,但实际有用的也就那么几种。这里总结一下:

 

1.int*& p 这应该是最有用的一个,因为可以用它当形参,在函数体内改变实参的指向。

2.const和*的3种结合都比较常用,特别是前2种。

3.const int& a 这也是很常用的一种用法,特别在面向对象里面,引用是提高效率的钥匙。

4.const int*&,这个虽不常用,但某些场合还是会看到的。

 

到此为止,希望各位看客多多支持~~看过后没那么蒙的就顶顶吧。

原创粉丝点击