const T*& 指针的引用、指针的指针、const

我们用T来表示类型,这里的类型可以是系统内置类型,也可以是用户自定义类型。

我们先来熟悉一下这种表示方法。这样的表示在模板中是很常见的。


const T* 表示指针指向的是一个T类型的变量,该指针具有底层const属性,也就是说通过该指针,只能读取指向对象的值,但不能修改其指向对象的值。

同理,const T&表示常引用,所引用的也是T类型的也是底层const,也就是说通过该引用,只能读取指向对象的值,但不能修改其指向对象的值。


热身运动完毕。开始进入正题。

我们知道,对于函数形参,有三种传参方式,传值调用、传指针调用、传引用调用。

对于传指针调用,实际用的也是传值方式,只不过传的是指针的值。

那么问题来了,如果我们既想修改指针所指对象的值,又想修改指针本身的值,怎么做?

C功底好的同学马上就会说,来个二维指针就搞定了。是的,确实可以。不过,对于C++来说,还有一种方法也可以做到。那就是指针的引用

T data;
T* pData = &data;
T* &myRef = pData;

在这里myRef就是指针pData的别名。

我们可以将T用int替换,来验证一下。

int data;
int* pData = &data;
int* &myRef = pData;
cout << "addr of  data: " << &data << endl;
cout << "        pData: " << pData << endl;
cout << "        myRef: " << myRef << endl;
cout << "addr of pData: " << &pData << endl;
cout << "addr of myRef: " << &myRef << endl;

输出结果为:

addr of  data: 0x22fef8
        pData: 0x22fef8
        myRef: 0x22fef8
addr of pData: 0x22fef4
addr of myRef: 0x22fef4

可以清楚地看到,myRef和pData是同一个变量的两个名字。

可以这样记忆,T* &r,声明一个变量r,这个r是一个引用,指向T*类型的一个指针。


好的,介绍完T*&,下面我们进更进一步,介绍一下const T*&。

第一个闯入大脑中的问题,肯定是这个const是修饰谁的。换句话说,有两种理解方式。

第一种理解是:这是一个普通指针的const引用。第二种理解是:这是一个普通引用,指向一个const指针。

对于const T*& myRef; 来说,第二种理解是正确的,const T*& 和 T const*& 产生相同的结果,const T*& 和 T const*& 是等价的,都表示一个普通引用,指向一个const指针。

也就是说,const是修饰指针的。

如果想定义一个指向普通指针的const引用,则应该按照下面的方式定义:

T* const& myRef = pData;

我们知道,引用天生具有顶层const属性,也就是说,引用一经初始化,就无法再指向其他变量。

所以不存在T* & const myRef = pData;

经过上面的介绍,指向const指针的const引用怎么表示呢?

答案是:T const* const& 或 const T* const&

好,现在我们再结合typedef来练习一下。

定义   typedef  T* T_ptr;

那么请问 const T_ptr& 表示什么意思?

答案是:T* const&,即T*的const引用,该引用是T*类型的指针的别名。


关于类型转换

int data;
int* pData = &data;
const int* &  myRef2 = pData;
const int** myPtr = &pData;
error: invalid initialization of reference of type ' const int*& '   from   expression of type '  int*  '

error: invalid conversion from ' int** ' to ' const int** ' [-fpermissive]|

const int* &  myRef2 = pData; 这一句出错。

const int** myPtr = &pData;这一句出错,表明不存在从int** 到const int**的隐式转换。

这里只讲第一个错误,对于第二个错误,我们单独开一篇博文来讲,因为那是个相当大的问题,足够重开一篇博文来讲述了。

第二个问题的相关讨论在这里 : http://bbs.csdn.net/topics/40321011 


对于第一个问题:const int* &  myRef2 = pData; 这一句出错,原因很简单,因为我们定义的是const指针的引用,普通引用是一定要和指向的变量类型完全一致的。如果类型不一致,编译器会自动进行类型转换,生成一个类型符合要求的中间变量,并让引用指向中间变量,中间变量为右值。而普通引用不能指向右值的,const引用则可以。我们不能把const对象、字面值或者需要类型转换的对象传递给普通的引用形参。而const引用就可以,说的就是这个道理。

再强调一下,虽然const引用可以,但是此时,const引用指向的是一个临时变量。

所以修改方法有两个:

法一:

把const int* &  myRef2 = pData;  修改为  int* &  myRef2 = pData; 即 去掉const

法一是把类型修改一致,此时myRef2就是pData的别名。

法二:

把const int* &  myRef2 = pData; 修改为 const int* const& myRef2 = pData;

法二是把引用改为const引用,此时,

如果不相信myRef2是中间变量的别名,而不是pData的。我们可以做下面这个实验。

int data;
int* pData = &data;
const int*const &  myRef2 = pData;
cout << "addr of myRef2: " << &myRef2 << endl;
cout << "addr of pData: " << &pData << endl;
输出结果为:

addr of myRef2: 0x22fef8
addr of  pData: 0x22fef0
显然,此时的myRef2根本不是pData的别名。


Done!




  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值