参数传递 ============= 当形参是引用类型时,称对应实参被 **引用传递** (passed by reference)或者函数被 **传引用调用** (called by reference)。 当实参的值被 **拷贝** 给形参时,形参和实参时两个相互独立的对象。这样的实参被 **值传递** (passed by value)或者函数被 **传值调用** (called by value)。 传值参数 -------------- 当初始化一个非引用类型的变量时,初始化被拷贝给变量。此时,对变量的改动 **不会** 影响初始值。 **指针形参** 指针的行为和其他 **非引用** 类型一样。当执行指针拷贝操作时,拷贝的是指针的值。拷贝之后, **两个指针是不同的指针** 。因为指针 使我们可以间接地访问它所指的对象,所以通过指针 **可以修改它所指的对象的值** 。 .. code-block:: cpp :linenos: void reset(int* p) { *p = 0; // 改变了指针p所指对象的值 p = 0; // 只改变了p的局部拷贝,实参未被改变 } templtate void swap(T* x, T* y) { T* tmp = x; x = y; y = tmp; } // 只交换了拷贝指针的值,实际指针并未改变,因此无法达到交换的目的。 为了改变实参指针的值,可以使用指针的引用或者使用指向指针的指针。 .. code-block:: cpp int val = 1; int* p = &val; // 调用: reset(p) void reset(int* &p) { *p = 0; // 改变了指针p所指对象的值 p = 0; // 改变了指针p的值 } // 调用: reset(&p) void reset(int** p) { **p = 0; // 改变了指针*p所指对象的值 *p = 0; // 改变了指针*p的值 } 传引用参数 ------------ 通过使用引用形参,允许函数改变实参的值。 使用引用避免拷贝:拷贝大的类类型对象或者容器对象比较低效,甚至有的类类型(比如IO类型)根本不支持拷贝操作。当某种类型不支持拷贝操作时,函数只能通过 引用形参访问该类型的对象。例如,需要比较两个string对象,而这样的对象可能会很长,为了避免拷贝且不改变对象的值,可以将形参声明为常量引用(const &)。 使用引用形参返回额外信息:通过给函数传入一个额外的引用形参,让其保存需要的值,而不需要作为函数返回值返回(避免函数返回值太多)。 删除指针 ---------- 如果实参是一个动态申请的指针(new),在函数内 delete 该指针需要慎重。下例基于 Visual Studio 2013。 - 值传递:删除之后实参指针本身的值不变,指向的值仍然可以访问,但结果是未知的。 .. code-block:: cpp :linenos: void delPtr(int* p) { delete p; } int main() { int* p = new int(6); cout << p << ends << *p << endl; // 00746AE0 6 delPtr(p); cout << p << ends << *p << endl; // 00746AE0 -572662307 return 0; } - 引用传递:删除之后实参指针本身改变,指向的值不能访问(报错),说明空间得到释放。 .. code-block:: cpp :linenos: void delPtr(int* &p) { delete p; } int main() { int* p = new int(6); cout << p << ends << *p << endl; // 006F6AE0 6 delPtr(p); cout << p << endl; // 00008123 cout << *p << endl; // runtime error return 0; } 参考资料 ----------- 1. 《C++ Primer 第5版 中文版》 Page 187 -- 190。