1.什么是“引用”?申明和使用“引用”要注意哪些问题?

  引用就是某个目标变量的“别名”(alias),对应用的操作与对变量直接操作效果完全相同。

  申明一个引用的时候,切记要对其进行初始化。

  引用声明完毕后,不能再把该引用名作为其他变量名的别名。

  声明一个引用,不是新定义了一个变量,它本身不是一种数据类型,因此引用本身不占存储单元,系统也不给引用分配存储单元。

  不能建立数组的引用。

2. 将“引用”作为函数参数有哪些特点?

  传递引用给函数与传递指针的效果是一样的。这时,被调函数的形参就作为(原来主调函数中的实参变量或对象的)一个别名来使用,所以在被调函数中对形参变量的操作就是对其相应的目标对象(在主调函数中)的操作。

  使用引用传递函数的参数,在内存中并没有产生实参的副本,它是直接对实参操作;而使用一般变量传递函数的参数,当发生函数调用时,需要给形参分配存储单元,形参变量是实参变量的副本;如果传递的是对象,还将调用拷贝构造函数。因此,当参数传递的数据较大时,用引用比用一般变量传递参数的效率和所占空间都好。

  使用指针作为函数的参数虽然也能达到与使用引用的效果,但是,在被调函数中同样要给形参分配存储单元,且需要重复使用"*指针变量名"的形式进行运算,这很容易产生错误且程序的阅读性较差;另一方面,在主调函数的调用点处,必须用变量的地址作为实参。而引用更容易使用,更清晰。

3.在什么时候需要使用“常引用”? 

如果既要利用引用提高程序的效率,又要保护传递给函数的数据不在函数中被改变,就应使用常引用。常引用声明方式:const 类型标识符 &引用名=目标变量名;

例1


int a;
constint &ra = a;
ra = ; // 错误
a = ; // 正确

例2


string foo( );
void bar(string&s)
// 那么下面的表达式将是非法的:
bar(foo( ));
bar("hello world");

  非法原因在于foo( )和"hello world"串都会产生一个临时对象,而在C++中,这些临时对象都是const类型的。因此上面的表达式就是试图将一个const类型的对象转换为非const类型,这是非法的。

  引用型参数应该在能被定义为const的情况下,尽量定义为const 。

4.将“引用”作为函数返回值类型的格式、好处和需要遵守的规则?

格式:


类型标识符 &函数名(形参列表及类型说明)
{
  //函数体
}

好处:在内存中不产生被返回值的副本;(注意:正是因为这点原因,所以返回一个局部变量的引用是不可取的。因为随着该局部变量生存期的结束,相应的引用也会失效,产生runtime error!

注意:

(1)不能返回局部变量的引用。这条可以参照Effective C++[1]的Item 31。主要原因是局部变量会在函数返回后被销毁,因此被返回的引用就成为了"无所指"的引用,程序会进入未知状态。

(2)不能返回函数内部new分配的内存的引用。这条可以参照Effective C++[1]的Item 31。虽然不存在局部变量的被动销毁问题,可对于这种情况(返回函数内部new分配内存的引用),又面临其它尴尬局面。例如,被函数返回的引用只是作为一个临时变量出现,而没有被赋予一个实际的变量,那么这个引用所指向的空间(由new分配)就无法释放,造成memory leak。

(3)可以返回类成员的引用,但最好是const。 这条原则可以参照Effective C++[1]的Item 30。主要原因是当对象的属性是与某种业务规则(business rule)相关联的时候,其赋值常常与某些其它属性或者对象的状态有关,因此有必要将赋值操作封装在一个业务规则当中。如果其它对象可以获得该属性的非常量引用(或指针),那么对该属性的单纯赋值就会破坏业务规则的完整性。

(4)流操作符重载返回值申明为“引用”的作用:

  流操作符<<和>>,这两个操作符常常希望被连续使用,例如:cout <<"hello" << endl; 因此这两个操作符的返回值应该是一个仍然支持这两个操作符的流引用。可选的其它方案包括:返回一个流对象和返回一个流对象指针。但是对于返回一个流对象,程序必须重新(拷贝)构造一个新的流对象,也就是说,连续的两个<<操作符实际上是针对不同对象的!这无法让人接受。对于返回一个流指针则不能连续使用<<操作符。 因此,返回一个流对象引用是惟一选择。这个唯一选择很关键,它说明了引用的重要性以及无可替代性,也许这就是C++语言中引入引用这个概念的原因吧。 赋值操作符=。这个操作符象流操作符一样,是可以连续使用的,例如:x = j = 10;或者(x=10)=100;赋值操作符的返回值必须是一个左值,以便可以被继续赋值。因此引用成了这个操作符的惟一返回值选择。 附:单目运算符重载

  例3

 #include <iostream.h>
int &put(int n);
int vals[];
int error = -; void main()
{
  put() = ; // 以put(0)函数值作为左值,等价于vals[0]=10;
  put() = ; // 以put(9)函数值作为左值,等价于vals[9]=20;
  cout << vals[];
  cout << vals[];
} int &put(int n)
{
  if (n>=&& n<= )
  {     return vals[n];
  }
  else
  {
    cout << "subscript error";
    return error;
  }
}

(5)在另外的一些操作符中,却千万不能返回引用:+-*/ 四则运算符。Effective C++[1]的Item23详细的讨论了这个问题。主要原因是这四个操作符没有side effect,因此,它们必须构造一个对象作为返回值,可选的方案包括:返回一个对象、返回一个局部变量的引用,返回一个new分配的对象的引用、返回一 个静态对象引用。根据前面提到的引用作为返回值的三个规则,第2、3两个方案都被否决了。静态对象的引用又因为((a+b) == (c+d))会永远为true而导致错误。所以可选的只剩下返回一个对象了。

5. “引用”与多态的关系?

  引用是除指针外另一个可以产生多态效果的手段。这意味着,一个基类的引用可以指向它的派生类实例(见:关于多态)。

例4

Class A;
Class B : Class A
{
  // ...
};
B b;
A&ref= b;

6. “引用”与指针的区别是什么?

  指针通过某个指针变量指向一个对象后,对它所指向的变量间接操作。程序中使用指针,程序的可读性差;

  而引用本身就是目标变量的别名,对引用的操作就是对目标变量的操作。此外,就是上面提到的对函数传ref和pointer的区别。

7. 什么时候需要“引用”?

  流操作符<<和>>、赋值操作符=的返回值、拷贝构造函数的参数、赋值操作符=的参数、其它情况都推荐使用引用。

CPP-基础:关于引用的更多相关文章

  1. CPP基础

    CPP基础1. 如果没有指明访问限定符(public,private),class中默认的private,而struct中的成员默认是public的. #include <iostream> ...

  2. 在C的头文件中定义的结构体,如何在cpp文件中引用

    解决方案1:在cpp文件中放置.c,且在该文件中引用变量 解决方案2:在一个cpp文件中包含.c,但在另一个cpp文件中使用结构体变量 cpp文件1 cpp文件2 #include "dia ...

  3. 【转载】 Java 7之基础 - 强引用、弱引用、软引用、虚引用

    原文地址:http://blog.csdn.net/mazhimazh/article/details/19752475 1.强引用(StrongReference) 强引用是使用最普遍的引用.如果一 ...

  4. C中头文件在cpp文件中引用和.h文件引用

    1.编译器会单独编译每个cpp文件.头文件会复制到cpp文件中. 2.有时会遇到这样的一个问题a.cpp要调用b.cpp中的函数,而b.cpp又要调用a.cpp中的函数.这就牵扯到相互调用.这时如果我 ...

  5. Java 7之基础 - 强引用、弱引用、软引用、虚引用

    1.强引用(StrongReference) 强引用是使用最普遍的引用.如果一个对象具有强引用,那垃圾回收器绝不会回收它.如下: Object o=new Object();   //  强引用 当内 ...

  6. C++基础之引用与指针的区别与联系、常引用使用时应注意的问题

    什么是引用? 引用就是对变量起一个别名,而变量还是原来的变量,并没有重新定义一个变量.例如下面的例子:   #include<iostream> using namespace std; ...

  7. Java基础之引用(String,char[],Integer)总结

    1.String的引用: 下列代码执行后的结果为: public class Test { public static void main(String[] args) { StringBuffer  ...

  8. Java基础之引用(String,char[],Integer)总结于牛客网的专项练习题

    1.String的引用: 下列代码执行后的结果为: public class Test { public static void main(String[] args) { StringBuffer ...

  9. 【C++】基础及引用

    输出 #include "iostream" //包含c++的头文件 //iostream.h using namespace std; //使用命名空间 std 标准的命名空间 ...

  10. c中头文件在cpp文件里引用和.h文件引用的思考

    我们在编敲代码中头文件是常常使用的. 可是头文件是应该包括在.H文件里还是在.cpp文件里.在这个其中有什么样去差别呢. 假如说我们编写了一个a.cpp  .我们将a.cpp文件的变量和函数申明在a. ...

随机推荐

  1. [翻译] 正式宣布 .NET 5

    原文: Introducing .NET 5 今天,我们宣布 .NET Core 3.0 之后的下一个版本将是 .NET 5 .这将是 .NET 系列的下一个重要版本. 将来只会有一个 .NET ,您 ...

  2. Unity 2D骨骼动画2:创建真实动画

    http://bbs.9ria.com/thread-401781-1-1.html 在这个系列,我们将关注Unity引擎提供的基于骨骼动画工具.它的主要思想是为了把它应用到你自己的游戏来介绍和教基本 ...

  3. 新手安装 hadoop、hive和hbase 笔记

    系统是ubuntu 12.04 , hadoop版本是1.2.1 , hive版本是0.12 , hbase版本我忘记了,不好意思首先是配置好hostnamevi /etc/hosts写入你要配置的i ...

  4. 慕课笔记-Java入门第二季

    1.java对象的使用 (1)创建对象 类名 对象名=new 类名(); (2)使用对象 引用对象的属性:对象名.属性; 引用对象的方法:对象名.方法(); Note: ①Java会给成员变量赋初始值 ...

  5. 全球首款iOS模拟器出炉!在违法的边缘疯狂试探

    对于许多智能手机用户,特别是手游玩家来说,在手机屏幕的方寸之间进行操作显然并非特别方便,而且在多年之前,由于手机配置不足,也导致了用PC来玩手游的需求不断涌现.彼时,BlueStacks及夜神等一众A ...

  6. pycharm 中切换虚拟环境

    在pycharm上创建虚拟环境,网上的资料非常多. 如果pycharm上有多个项目,如何切换每个项目的虚拟环境? cmd 命令进入虚拟环境所在的文件夹(Pycharm在每创建一个新项目时就会创建一个虚 ...

  7. 74HC14D(6反向施密特触发器)

    74HC14D:6反向施密特触发器:延迟特性,反向特性,整形特点. 施密特触发器是具有特殊功能的非门,当加在它的输入端A的电压逐渐上升到某个值时(正阈值电压),输出端Y会突然从高电平跳到低电平,而当输 ...

  8. Ubuntu 18.10 使用VMware克隆后,克隆后的机器再手动更改interfaces配置文件后无法启动网络的解决办法

    克隆过程就略过了 配置interfaces root@client02:~# vim /etc/network/interfaces # interfaces() ) and ifdown() aut ...

  9. MDX之Avg函数使用

    日均值是比较常见的指标,本文对 MDX 计算日均值做一个总结 MDX 计算日均值,表达式一 WITH MEMBER Measures.[日均值] AS   Avg(      Descendants( ...

  10. 访问NopCommerce的Admin 运行Nop.Admin后台管理

    Step 1.下载和安装NopCommerce的源码: Step 2.打开和运行Presentation下的Nop.Web 项目: Step 3.初次运行 会弹出界面 配置管理员账号 和 数据库信息: ...