当前位置:首页技术教程第九章:引用难道只是别人的替身,了解C++基本语言特性变量和类型
  • 素材类型: 精品-素材
  • 上传时间:

  引用是我们多次讨论的概念了,引用只是默认值的别名。对引用唯一的操作就是将其初始化。一旦引用初始化结束,引用就只是其默认值的另一种写法罢了。引用变量没有地址,甚至它们可能不占用任何存储空间。

  注意事项

  (1) 声明引用的引用、指向引用的指针、指向引用的数组都是非法的。

  (2) 引用不可能带有常量性和挥发性,因为别名不能带有常量性和挥发性。用关键字const和volatile修饰引用会造成编译错误。

  (3) 用const或volatile修饰引用类型,不会造成编译错误,但是编译器会默认忽略这些修饰。

inta=12;
int &ra =a;
int &p =&ra;      //p指向a的地址
a=42;             //ra和a的值都变成了42
int &&rri=ra;     //错误
int&*pri;         //错误
int &ar[3];       //错误

  我们一直在说引用就是别名,既然是别名,就要是“某个已存在变量”的别名,并且这个变量必须真实存在才行。其实引用不只是简单变量名的别名,其任何可作为左值的复杂表达式都可以作为引用的默认值。只要类型确定,有明确的内存地址,可做左值,就可初始化引用。引用和函数相结合时,有如下几种功能:

  (1) 如果一个函数返回一个引用,这说明此函数的返回值可重新赋值。我们经常使用的 STL库中所有的下标操作基本上都是这样返回引用的形式。例如 vector 数据类型的下标操作声明:

template <class T, class Alloc =alloc> // vector STL模板类声明
class vector
{
public:
  typedefT
  value_type; // 数据类型
  typedef value_type  reference;
  typedef size_t       size_type;
  typedef value_type*iterator;
  ...
protected:
  iterator start;
public:
  iterator begin() { return start;}
  reference operator[] (size_type n) { return *(begin() + n);
}

  (2) 引用的另一个用途即让函数在其返回值之外多传递几个值。例如:

typedef int failure;
char *FindStr(const char *pszMainStr, failure &reason);

  (3) 另外一个需要特别注意的地方是,指向数组的引用保留了数组的长度信息,而指针不会保留数组的长度信息。例如下面的代码,Array_Test1 函数可记住实参必须为长度为 3 的数组,而Array_Test2 却无法记录,导致长度为 2 的数组也可作为实参传给函数。

//引用形式数组测试函数
void Array_Test1(int (&array)[3])
{
  array[2]=3;
}
//非引用形式数组测试函数
void Array Test2(int array[3])
{
  array[2]=3;
int _tmain(int argc, char* argv[])
{
  int n3[2]={2, 4};
  Array_Test1(n3); //错误“Array_Test1”:不能将参数1 从“int [2]”转换为“int(&)[3]”
  Array_Test2(n3);//可正常编译通过
}

  (4) 最后,我们讨论一下常量引用(const reference)。为了阐述常量引用的特殊之处,我们看下面的代码:

int &rInt=12;       //错误
constint&rInt=12;  //正常编译通过

  可以看出常量值不能给普通引用初始化,但是可以给const引用初始化。

小心陷阱

  ● 如果初始化值是一个左值(可以取得地址),则可以初始化引用,没有任何问题。

  ● 如果初始化值不是一个左值,则只能对constT&(常量引用)赋值,且赋值过程包括3个阶段:首先将值隐式转换到类型T,然后将这个转换结果存放在一个临时对象里,最后用这个临时对象来初始化这个引用变量。

  ● 在这种情况下,constT&(常量引用)过程中使用的临时对象会和constT&(常量引用)共“存亡”。

  上述代码中,引用 rInt指向编译器隐式分配内存并创建的匿名int类型临时对象。对 rInt引用的任何操作都会影响匿名临时变量,而不会影响常量 12。同时编译器也会确保这样的匿名临时对象会将生命期扩展到初始化后的引用存在的全部时域。这无形之中也开启了临时生命期问题的万劫不复之门。我们来看下面这段普通代码:

shorts=123;
const int &rIntegrate = s;
s=321;
const int *ip = &rlntegrate;
printf("rIntegrate =%d, s = %dr\n", rIntegrate, s);
printf("ip = %d, &s = %d", ip, &s);

  输出结果为:

rIntegrate = 123, s =321
ip=2030760,&s =2030784

  可看出 rIntegrate引用的默认值并不是 s,而是常量引用初始化过程中隐式使用的匿名对象。接着,我们看一下const引用作为函数形参存在的问题。来看下面这段代码:

const int&GetMax(const int &a, const int &b)
returm ((a>b)?(a): (b));

  乍一看,此函数完全无害:函数功能很简单,就是返回两个参数中的一个。引发问题的是那个 retun 语句。因为 a、b都是const引用,在函数参数实参传值时,函数首先会生成两个临时对象将实参的值复制到临时对象中,然后用这两个临时对象初始化a、b。现在你也许明白了:函数返回了临时变量的引用。

 请谨记

  ● 若非必要请不要使用const引用,因为const引用有时会伴随着临时对象的产生。

  ● 在函数声明时,请尽量避免const引用形参声明,使用非const引用形参替代,以防因返回const引用生成的临时变量而导致程序执行错误。

第九章:引用难道只是别人的替身,了解C++基本语言特性变量和类型
温馨提示:

文章标题:第九章:引用难道只是别人的替身,了解C++基本语言特性变量和类型

文章链接:https://www.xiciw.com/jsjc/1489.html

更新时间:2024年02月14日

本站大部分内容均收集于网络!若内容若侵犯到您的权益,请发送邮件至:xiciw#qq.com我们将第一时间处理!

资源所需价格并非资源售卖价格,是收集、整理、编辑详情以及本站运营的适当补贴,并且本站不提供任何免费技术支持。

                               

所有资源仅限于参考和学习,版权归原作者所有,更多请阅读菜鸟资源服务协议

声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。

给TA打赏
共{{data.count}}人
人已打赏
技术教程

新版宝塔的 SQL 注入漏洞

2024-2-17 12:53:52

技术教程

第十章:枚举和一组预处理的#define 有何不同,了解C++基本语言特性变量和类型

2024-2-19 10:34:00

0 条回复 A文章作者 M管理员
    暂无讨论,说说你的看法吧
个人中心
购物车
优惠劵
今日签到
有新私信 私信列表
搜索