5

我读到:

在 Java 中,所有参数都是按值传递的。在 C++ 中,可以通过以下方式传递参数:

value,
reference, or
const-reference

但是,如果我将一个指针传递给一个函数并在该函数中更改指针,这不会更改对象,其标识符用于将其指定为参数,它只会更改传递给函数的指针。

这实际上意味着从技术上讲,在 C++ 中,所有内容都是通过值作为副本传递的,不同之处在于这个复制的值可以用作内存地址(指针或引用),所以如果我想修改作为函数传递的现有指针参数 I 必须传递其内存地址的值,而不是该指针持有的内存地址的值。

那么假设每个函数参数都是从现有对象派生的新副本,该对象专门创建用于在单个特定调用中用作参数,而从来没有一个实际的预先存在的对象是正确的?

4

3 回答 3

4

在 Java 中,所有参数都是按值传递的。

这有点误导,因为当对象引用按值传递时,并且对象支持突变,调用者可以更改传入的对象,有效地使其看起来像按引用传递。

这实际上意味着从技术上讲,在 C++ 中,所有内容都是通过值作为副本传递的,不同之处在于这个复制的值可以用作内存地址(指针或引用),所以如果我想修改作为函数传递的现有指针参数 I 必须传递其内存地址的值,而不是该指针持有的内存地址的值。

这个评价是正确的。通过指针传递和通过引用传递仍然会在被调用函数的空间中创建一个副本,至少在逻辑上是这样:

  • 当对象按值传递时,会创建对象本身的副本
  • 当通过指针传递对象时,会创建指针的副本
  • 通过引用传递对象时,会创建引用的副本

简而言之,传递给调用者的任何内容都是按值传递的。有时,传递的值可用于修改原始对象。

当您考虑优化和内联时,事情开始变得更加混乱:可能没有创建指针或引用的副本,但整体逻辑保持不变。

于 2013-11-03T11:14:29.700 回答
1

这实际上意味着从技术上讲,在 C++ 中,所有内容都是通过值作为副本传递的,不同之处在于这个复制的值可以用作内存地址(指针或引用)

是的,您的假设在技术上是正确的,几乎适用于所有常见的编程语言。为什么?您应该注意,按引用传递 是一种软件抽象。CPU 真正做的是(当然这取决于函数调用约定,我正在简化事情)是将数据复制到寄存器中。

为了模拟您正在使用相同的值,您所做的(以及大多数常见语言所做的)是传递原始数据的内存地址,换句话说,是一个指针。这就是 C 模拟通过引用传递的方法,这就是 C++ 所做的(引用实际上是指针),这就是 Java 所做的。

于 2013-11-03T11:14:01.560 回答
0

传递给函数的确实是一个独特的对象。但是,如果我们有object X, 并且我们做了一个引用object& Y = X;,然后object& Z = X;,那么我们就有了三个“对象”——X一个是 类型object,一个是对YZ类型引用object。仍然只有一个“真实”实例object-Y并且Z都引用相同的X

同样,如果我们传递对函数的引用:

void func(object& R)
{
  ...
}

func(X);

该函数将接收一个引用的对象X- 这使得函数看起来好像它实际上正在修改X,因为这就是引用的工作方式 - 引用的实际值是引用原始对象的东西。

我想说的是“传递给函数的所有内容都是唯一的对象,但在引用的情况下它可能指的是同一个原始对象”。

在 C++ 中,指针和引用非常相似,除了以下两点: 1. 引用只能对特定对象初始化一次 - 并且只能以实际引用对象的方式创建,您可以t 有引用“无”或“尚未设置”的引用 [但是,您可以有“陈旧”的引用,其中最初引用的对象不再存在]。2. 引用使用与基本对象相同的语法,例如r.member = 42;,指针使用*pp->member = 42;来“获取”对象的内容。

[是的,完全有可能在 C++ 规范中定义一个编译器,其中指针和引用“在内部不是同一件事”,但到目前为止我从未见过一个]

于 2013-11-03T11:25:23.250 回答