c/c++ 中的传值调用和传引用

本文通过C++示例代码详细对比了传值和传引用的区别。传值会产生变量的副本,而传引用则是直接操作原始变量。此外还讨论了引用在对象传递中的优势,以及对象切片问题。
代码:
  
// Reference.cpp // Different between pass by Reference and pass between value #include <iostream> using namespace std; void f(int&, int); main() { int i = 0, j = 0; cout << "i= " << i << "/t" << "j= " << j << endl; cout << "&i= " << &i << "/t" << "&j= " << &j << endl; f(i, j); cout << "i= " << i << "/t" << "j= " << j << endl; // wait(); return 0; } void f(int& x, int y) { cout << "x= " << x << "/t" << "y= " << y << endl; cout << "&x= " << &x << "/t" << "&y= " << &y << endl; x++; y++; cout << "x= " << x << "/t" << "y= " << y << endl; }

屏幕输出:

i= 0 j= 0
&i= 0x22ff6c &j= 0x22ff68
x= 0 y= 0
&x= 0x22ff6c &y= 0x22ff44
x= 1 y= 1
i= 1 j= 0

可以看到给函数 f() "传引用(pass by reference)"和"传值(pass by value)"在使用上类似,但实际中有很大区别:

"传值"传递的是原始变量 j 的一份拷贝 y,编译器为新的拷贝 y 重新分配了内存空间,因此本例中变量 j 和 变量 y 有不同的内存地址.对函数 f() 体内 y 的附新值,不会影响函数 f() 体外 j 的值.

"传引用"传递的是变量 i 的地址,并没有额外分配新的内存空间.x 就相当于 i 在 f() 体内的一个别名(我的理解),x 同 i 使用相同的地址空间,使用 x 就相当于引用了 i 的值,显然对 f() 体内 x 赋新值,就会影响到函数 f() 体外 i 的值.这点其实也就是我们使用"传引用"的目的之一,能影响 "outer object".

有的时候你希望引用函数如 f() 不能修改被引用的变量如 i,那么可以这样定义函数:
void f(const int& x, int y)

这样的话,如果你还是在 f() 里使用 x++,那么编译时就会提示你引用的是一个只读变量.

这是一种良好的编程习惯, 比起传值调用,优点在于不需要额外分配内存空间.

 

 

 

---------------------------------

引用实际上是一个常量指针,不会再指向别的对象。但在作为函数参数时,特别是在涉及对象时,引用比指针和传值有优势。如果对象采用传值方式传递,必然会调用自身的构造函数和并递归调用基类的构造函数。如果继承的层次多,这会造成很大的开销。但是在使用指针时,又会发生对象切片问题,所以在传递对象时,最好使用安全和高效的引用。

 

----------------------------------

对象切片问题:指在多态使用对象时,派生类对象在复制过程中发生向上类型转换,使得本来应该复制的是派生类对象,结果却只复制了派生类对象的基类对象部分,相当于派生类对象被切掉了一部分。

 

----------------------------------

传引用只有在传递对象时才有优势,引用本身也需要4个字节的空间,和int是一样的,所以传int是不应该使用引用的。

----------------------------

 

 

 

 

 

转帖自http://www.linuxsir.org/bbs/thread54887.html 特此感谢

<think>嗯,用户想了解值调用引用调用。首先,我需要回忆这两个概念的定义区别。值调用应该是函数调用递的是变量的,而引用调用则是递变量的地址或者引用。不过,我得确认自己记得没错,不能搞混了。 然后,可能用户是刚开始学编程,或者对函数参数递机制不太清楚。需要从基础讲起,用简单易懂的例子说明。比如用C语言或者Python的例子?不过Python的参数递有点特殊,可能用C或Java更明确。比如C语言中,就是直接复制到形参,而引用可以通过指针来实现。或者C++引用参数? 接着,要分步骤解释。先定义值调用,然后例子,优缺点。同样处理引用调用。然后比较两者的区别,应用场景。可能用户需要知道什么时候用哪种方式,或者为什么某些语言只有,比如Java实际上只有,但对象变量递的是引用,容易让人误解。 需要注意用户的提问可能涉及不同的编程语言,所以最好指出不同语言中的情况,但不要深入太多,避免混淆。比如在Python中,不可变对象,可变对象引用?或者是否如此?需要准确,避免错误。 另外,用户可能想知道这两种调用方式对程序的影响,比如函数内修改参数是否影响原变量。比如时,函数内部修改不会影响外部变量;引用时则会改变。这点很重要,需要明确举例说明。 可能还要提到术语的正确性,比如有些语言中的引用调用”是否真的是严格意义上的引用调用,还是实际上是共享对象引用。比如Java总是,但对象引用是按递,导致效果类似引用,但其实还是。这点容易混淆,需要澄清。 总结结构应该是:先分别介绍值调用引用调用的定义,各自举例,优缺点,然后对比两者的区别,最后可能提到不同语言中的实现情况。确保结构清晰,逐步引导用户理解。 现在需要检查例子是否正确。比如值调用,函数内修改形参不影响实参;引用调用则会影响。例子是否准确?比如用交换函数的例子,无法交换实参,引用可以。这样比较直观。 还要注意术语的一致性,避免混淆。比如引用调用有时也叫调用,或者按引用递。确保使用用户可能接触到的常见术语,同时说明其他可能的叫法。 最后确保回答符合系统级指令:行内公式用$...$,独立公式用$$...$$,但这里可能数学内容不多,但如果有提到变量或表达式时需注意格式。例如,如果有涉及指针的地址,可能需要用代码块而不是数学公式。不过用户的问题可能更多是编程概念,可能不需要太多数学表达式,但需遵守格式要求。 检查LaTeX语法是否正确,比如变量用$包围,确保没有错误。回答用中文,结构清晰,分点说明,帮助用户逐步理解。</think>值调用引用调用编程中两种重要的参数递机制。它们的核心区别在于**递的内容不同**,进而影响函数内外的变量行为。下面分步骤介绍: --- ### 一、值调用(Call by Value) #### 1. 定义 函数调用时,将**实际参数的**复制一份递给形式参数。函数内部操作的是副本,与原变量无关。 #### 2. 示例 ```c void modify(int x) { x = 10; // 修改的是副本 } int main() { int a = 5; modify(a); // 递a的5 printf("%d", a); // 输出5(原未变) } ``` #### 3. 特点 - **优点**:安全,函数内部修改不影响外部变量。 - **缺点**:复制数据可能带来性能开销(尤其对大型对象)。 - **适用场景**:基本数据类型或不需要修改原数据的场景。 --- ### 二、引用调用(Call by Reference) #### 1. 定义 函数调用时,将**实际参数的地址(引用)**递给形式参数。函数内部通过地址直接操作原变量。 #### 2. 示例 ```c++ void modify(int &x) { // C++引用语法 x = 10; // 直接修改原变量 } int main() { int a = 5; modify(a); // 递a的引用 cout << a; // 输出10(原被修改) } ``` #### 3. 特点 - **优点**:避免复制开销,允许函数修改外部变量。 - **缺点**:可能引入副作用(意外修改外部变量)。 - **适用场景**:需要修改原数据或递大型对象时。 --- ### 三、关键区别对比 | 特性 | 值调用 | 引用调用 | |---------------------|-------------------------|-------------------------| | **递内容** | (副本) | 地址(原变量引用) | | **函数内修改的影响** | 不影响原变量 | 直接影响原变量 | | **内存占用** | 需要额外内存存储副本 | 无额外内存开销 | | **典型语言支持** | C(基本类型)、Java | C++引用)、C#(`ref`) | --- ### 四、常见语言的行为差异 1. **C语言** - 严格,但可通过指针模拟引用调用递指针的)。 ```c void modify(int *x) { *x = 10; } modify(&a); // 递指针(本质仍是) ``` 2. **Java** - 严格,但对象变量存储的是引用递的是引用的副本)。 - 修改对象属性会影响原对象,但重新赋不会(因副本引用被修改)。 3. **Python** - 对象引用(类似,但递的是对象的引用副本)。 - 可变对象(如列表)的属性修改会影响原对象,但重新赋不会。 --- ### 五、如何选择? - 需要保护原数据 → ****。 - 需要高效递大型数据或修改原数据 → **引用**。 理解这两种机制有助于避免逻辑错误(如意外修改变量)优化程序性能。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值