现在的位置: 首页 > 综合 > 正文

传值和传引用

2012年09月21日 ⁄ 综合 ⁄ 共 1944字 ⁄ 字号 评论关闭

传值和传引用

    在现在常用的文本编程语言(C++, Java, C#)中,调用子函数时的传参方式主要是传引用方式,就是说,告诉被调用的函数的是参数所在的位置,而不是参数的数据。C++ 为了保持和 C 语言的兼容,一般的简单数据还是使用值传递,但对于大块的数据,比如数组,字符串,结构,类等等,也基本上都是引用形式传递的。
    值传递的方式的缺点是显而易见的:每次调用子函数的时候,需要把数据拷贝一份,耗费大量的内存。传引用的方式,不需要每次都拷贝数据,节省了内存空间,和复制数据的时间。但是传引用的安全性不如直接传值,因为传引用的时候,数据所在的内存也可以被其它函数访问,这在单线程下,问题不大。但是多线程下,就不能保证数据的安全了。

 

规则:

1、用传引用给 const 取代传值。典型情况下它更高效而且可以避免切断问题(实现不了多态)。

2、这条规则并不适用于内建类型及 STL 中的迭代器(iterators)和函数对象(function objects)类型。对于它们,传值通常更合适。STL 中的迭代器(iterators)和函数对象(function objects),因为,作为惯例,它们就是为传值设计的。迭代器(iterators)和函数对象(function objects)的实现有责任保证拷贝的高效并且不受切断问题的影响。

 

“引用”的知识点:

       ●引用型变量。定义一个整型引用型变量yi的格式:
  int&yi = i;// 变量i是已经被定义过的整型变量
  意义:yi是i的别名,两者指向同一变量,是同一个变量的两个名字,无论修改谁,变量都将发生修改。
  注意事项:引用型变量在定义的时候一定要初始化,不能先定义,再初始化,这一点与java不同。
  ●引用型参数(传引用,传址)。定义引用型参数的格式如下:
  返回类型函数名(参数类型&参数名){ 函数体 },与非引用参数的不同之处在于参数名前多了一个引用符号“&”。
  意义:C++默认传值,也就是说在函数体内对形参做的任何修改不会影响到实参,在函数运行之前先调用实参的拷贝构造函数生成一个临时变量,这个临时变量在函数体内部代替形参参与运算,这就是为什么不用引用或者指针就无法通过函数实现交换两个变量的值,也就是C++中调用拷贝构造函数的时机之一,如果出于效率或者想修改实参,就必须用引用型参数,这样进入函数体内部参与运算的就是实参本身。
  
  ●引用型返回值。定义引用型返回值的格式如下:
  返回类型&函数名(参数类型参数名){ 函数体 }
  意义:函数体内的任何临时变量在函数运行完毕后都要销毁,如果要返回某个变量,那么将会调用这个变量所属类型的拷贝构造函数构造一个临时变量返回,除非使用引用型返回值。假设有如下程序,其中类A有一个函数fun意图返回对象自己,我们看它这样做能办到吗?
  
  运行,打印以下结果:
  构造函数
  拷贝构造
  拷贝构造
  程序运行结果显示调用了两次拷贝构造函数,为什么会这样呢?两次拷贝构造函数调用时机为:一次是执行“return *this; ”,编译器会在以*this为实参构造临时变量时调用拷贝构造函数,另一次是执行“A a1 = a.fun ();”,编译器会在以上一步构造的临时变量为实参初始化a1时调用拷贝构造函数。现在把“A fun (){ return *this; }” 改为“A& fun (){ return *this; }”,再运行可以得到如下的结果:
  构造函数
  拷贝构造
  可以看出只在初始化a1时运行了一次拷贝构造函数,返回的正是对象自己。
  注意事项:引用型返回值一般用在返回引用型参数(如C++中重载的输出运算符“<<”),或者返回对象自己(如重载的赋值运算符),不能返回函数体内临时变量的引用,因为函数运行完毕后临时变量全部都要销毁,对象已不存在了,无法返回对象本身[1]。
  总结:C++中引用的使用比较复杂,原因在于两个方面:首先在C++中默认是传值的,而不是传址(传引用),其次在C++中用不同的方法造出来的变量的存储位置不同、生命周期不同、销毁方法和销毁责任也不相同。所以在C++中使用引用要十分小心,需要对引用的透彻理解,而且在某些方面必须使用引用,比如拷贝构造函数。所以可以说学好引用是掌握C++实现面向对象机制的重要的语言基础。

 

注意:

上述的例子中,我的测试结果是

无论函数fun返回是否引用,结果都一样:

      构造函数
  拷贝构造
虽然结果一样,但跟踪代码可发现执行过程不同

返回引用时,fun中不调用拷贝构造函数,而在A a1 = a.fun ()这里的赋值时调用构造函数

返回非引用时,fun中的return *this直接调用构造函数,而在A a1 = a.fun ()这里不调用任何函数,直接就跳过了...

抱歉!评论已关闭.