无法从“int *”转换为“int *&”?详解C++引用(&)使用方法

2021/5/31 12:50:57

本文主要是介绍无法从“int *”转换为“int *&”?详解C++引用(&)使用方法,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

详解C++引用

  • 前言
  • 对普通变量的引用
    • 总结引用&使用规则
  • const的引用
  • 对指针的引用
  • 总结auto:
  • auto在编程时真正的用途
    • 1.代替冗长复杂的变量声明
    • 2.定义模板参数时,用于声明依赖模板参数的变量
    • 3.模板函数依赖于模板参数的返回值

现在我想做下面这样的运算:

int i = 2;
int* &rp = &i;

结果是VS2013编译器报错,显示:无法从“int *”转换为“int *&”。
然后我定义一个指针p,指向i:int *p = &i;
结果是int * &rp = p;并不报错。

为什么会这样呢,按理说p和&i都是int*,为什么一个可以,一个不可以呢?答案就是&i是一个表达式的结果,且不是一个左值,这对引用而言非常重要。

下面我将详细介绍引用(&)的用法,相信看完之后会对你有很大的帮助。

前言

所谓引用,就是给对象起另外一个名字。通常将引用的声明写成&d的形式来定义引用类型,其中d是声明的变量名。如int i = 20;int &d =i;就是定义i的引用,声明的变量名为d。

对普通变量的引用

int ival = 1024;
int &refVal = ival;//refVal和ival绑定,是ival的另一个名字
//int &refVal2;//错误,引用必须被初始化

int &refVal3 = refVal;//可以多重绑定

上述中,ival、refVal和refVal3完全等价。可以用其任意一个给另外的整型变量赋值;给3个中的任意一个赋值,3个值都改变。说白了,这3个对应的是一块内存。

除此之外,定义引用可以在一条语句中:

int i = 1024,i2 = 2048;//i和i2都是int
int &r = i, r2 = i2;//r为引用,和i绑定;r2是int型

现在请判断如下定义是否合法:

int &refVal4 = 10;
double dval = 3.14;
int &refVal5 = dval;

第一个错误,因为引用的初始值必须是一个对象
第二个是正常定义,第三个错误,因为此处引用的类型的初始值必须是int型对象。

总结引用&使用规则

好了,到了这里,我们可以总结一下使用引用的一些限制:

  1. 引用必须初始化;
  2. 所有引用的类型都要和与之绑定的对象一致;
  3. 引用只能绑定在对象上,不能与字面值或某个表达式的计算结果绑定在一起

const的引用

在上一小结中,我们总结使用应用必须注意的3点。其实,对于第3点,有两个例外:

  • 例外1:const int & r = 56;//正确,初始化常量引用时允许使用任意表达式作为初值,只要表达式的结果能转换成引用的类型
  • 例外2:可以将基类的引用绑定到派生类对象上

对于例外2,这里暂不做讨论。关键是要理解例外1,这里用到了const,必须要注意“表达式的结果能转换成引用的类型”要求,如果转换不成引用的类型,是不能使用的。如,

double dval = 3.14;
const int &refVal5 = dval;

dval可以转换为int型,所以上述引用合法。

关于const的引用,可以参考我之前的文章详解const引用和常量指针、指向常量的指针,里面有一小节有详细介绍。

对指针的引用

直接看下面的例子:

int i = 1;
int *p = &i;//正确:&i为int*类型,p也为int *类型

int* &rp = p;//正确:rp与要绑定的p的类型严格匹配
int* &rp2 = &i;//错误:不满足引用限制的第3条。&i不是一个左值

要想让最后一个定义为正确,可以利用第3条限制的例外1。&i是一个非常量地址,它能转换为常量指针,所以如下定义的引用是正确的。

int* const  &rp3 = &i;

再看下面的例子:

const int ci = 10;
const int *pc = &ci;// 正确:对常量取地址,总是看成底层const,即指向常量的指针

const int* &rpc = pc;//正确,rpc与要绑定的pc的类型严格匹配

要想引用&ci,由于它为表达式的结果,所以需要使用引用第3条限制的例外1。由于&ci本身就为底层的const指针,加上指针要转化为常量指针,所以要像引用ci,必须用指向常量的常量指针:

const int* const &rpc3 = &ci;

总结auto:

使用引用时,其实很简单,把握住引用的几条规则即可

  1. 引用必须初始化;
  2. 所有引用的类型都要和与之绑定的对象一致;
  3. 引用只能绑定在对象上,不能与字面值或某个表达式的计算结果绑定在一起;
  4. 对于第3条,若就是像绑定字面值或表达式的计算结果,必须借用const
    除此之外,还需明白:
    对常量对象取地址是一种底层const,即不是对指针(也就是指向)的常量,而是对指针指向内存中的值是常量,一句话就是指向常量的指针

auto在编程时真正的用途

上面我们详细介绍了auto的使用规则,但它仅仅是使用规则而已,在实际编程中我们在明确变量类型情况下,还是使用明确的类型。Auto真正在编程时的实际应用如下:
内容参考至:https://www.cnblogs.com/QG-whz/p/4951177.html

1.代替冗长复杂的变量声明

我们在使用迭代器时常常会这样操作:

list<int> l1;
l1.push_back(1);
l1.push_back(2);
l1.push_back(3);

for (list<int>::iterator i = l1.begin(); i!= l1.end(); i++){
	cout << i.operator->() << endl;
	cout << *i << endl;
}

这样list<int>::iterator i = l1.begin()的声明迭代器i看起来繁琐冗长,我们实际可以用auto代替:auto i = l1.begin();

2.定义模板参数时,用于声明依赖模板参数的变量

template <typename _Tx,typename _Ty>
void Multiply(_Tx x, _Ty y)
{
    auto v = x+y;
    std::cout << v;
}

如上所示:我们获取x+y的值,但是x、y都是模板类型,我们无法知道其类型,这时就可以使用auto。

3.模板函数依赖于模板参数的返回值

template <typename _Tx, typename _Ty>
auto multiply(_Tx x, _Ty y)->decltype(_Tx*_Ty)
{
    return x*y;
}

上面的例子中,返回值依赖于xy的类型,这里我们需要提前查询xy的数据类型,需要用到decltype操作符,它是C++11标准引入的新的运算符,其目的也是解决泛型编程中有些类型由模板参数决定,而难以表示它的问题。
注意:auto在这里的作用也称为返回值占位,它只是为函数返回值占了一个位置

参考:C++ Primer第5版

以上就是auto的详细介绍。如果有疑问,欢迎评论区下方留言;本人水平有限 ,如有错误,也欢迎在评论区下方批评指正。若是喜欢本文,就帮忙点赞吧!



这篇关于无法从“int *”转换为“int *&”?详解C++引用(&)使用方法的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!


扫一扫关注最新编程教程