繁体   English   中英

Function arguments 在 C++ 与 ZD52387880E1EA22817A72D3759213819 中通过

[英]Function arguments passed by in C++ vs in Java

如果你能给我一个答案,我会很高兴。 我知道 Java 仅通过值传递,而 C++ 是通过值传递但也通过引用传递 我将在下面发布一些代码,以便您了解我的困惑是什么。

在 C++ 中按值传递:

void modify(int x, int y){
  x=10;
  y=20;
}
void main(){
  int a=5,b=8;
  cout << a; //outputs 5
  cout << b; //outputs 8
  modify(a,b);
  cout << a; //still outputs 5
  cout << b; //still outputs 8
}

修改(a,b); -> 参数称为实参(传递给函数的参数)和 from void modify(int x, int y) -> 参数称为形(函数接收的参数)。

所有 4 个参数:a、b 和 x、y 具有不同的 memory 位置。 当行修改(a,b); 达到时,形式参数(x 和 y)将具有实际参数(a 和 b)的值的副本。换句话说,x 将为 5,y 将为 8,但通过达到这些行:

x=10; y=20;

形参的值将分别更改为 10 和 20。 之后,修改 function 将从堆栈中删除,返回到实际参数(a 和 b)仍然具有相同值的 main 方法:a=5 和 b=8。

这是按值传递/调用,它也适用于 Java。

现在,关于通过引用传递/调用(仅在 C++ 中):

void modify(int* p) {
    *p = 10;
}
void main()
{
    int a = 5;
    int* p = &a;
    modify(p);
    cout << a << endl; //a is now 10.
}

据我目前了解,这是通过引用调用,可以使用指针来完成。 通过到达行modify(p) 我们将“a”的地址作为参数传递,该地址由“p”存储,因此在这种情况下,通过在 function void modify(int* p)中将引用作为参数,我们在该 memory 中访问了“a”位置并到达这条线: *p=10; (取消引用)我们将“a”的值设置为 10。

我的问题是:为什么 Java 也不被视为通过引用传递,因为我可以看到它的行为与 C++ 的情况相同? 我已经看到下面的代码发布在另一个关于 Java 的问题上,我也会发布那个让我更加困惑的人的答案。

public static void main(String[] args){
            Dog myDog = new Dog("Rover"); //myDog is a reference, a pointer to the object in memory
            foo(myDog); //you're passing the address of the object
    }

//Suppose the Dog object resides at memory address 42. This means we pass 42 to the method.

    public void foo(Dog someDog) {
    someDog.setName("Max");     // AAA
    someDog = new Dog("Fifi");  // BBB
    someDog.setName("Rowlf");   // CCC
    }

    /*Let's look at what's happening.
        the parameter someDog is set to the value 42
        at line "AAA"
            someDog is followed to the Dog it points to (the Dog object at address 42)
            that Dog (the one at address 42) is asked to change his name to Max
        at line "BBB"
            a new Dog is created. Let's say he's at address 74
            we assign the parameter someDog to 74
        at line "CCC"
            someDog is followed to the Dog it points to (the Dog object at address 74)
            that Dog (the one at address 74) is asked to change his name to Rowlf
            then, we return

Did myDog change?
        There's the key.
        Keeping in mind that myDog is a pointer, and not an actual Dog, the answer is NO. myDog still has the value 42; it's still pointing to the original Dog (but note that because of line "AAA", its name is now "Max" - still the same Dog; myDog's value has not changed.)
     If Java had pass-by-reference semantics, the foo method we defined above would have changed where myDog was pointing when it assigned someDog on line BBB.*/

从我注意到的情况来看,在 C++ 的情况下,我们将“a”的值从5更改为10 ,在 Java 中,通过将狗的名称从Rover设置为Max ,是不是也通过引用调用?

通过查看此声明:

/*If Java had pass-by-reference semantics, the foo method we defined above would have changed where myDog was pointing when it assigned someDog on line BBB.*/

根据前面的例子,我也在 C++ 中应用了这个:

void modify(int* p) {
    *p = 10;
    int b = 20;
    p = &b;
}
void main()
{
    int a = 5;
    int* p = &a;
    cout << p << endl; //OUTPUTS memory address 2002(e.g. let's say)
    modify(p);
    cout << a << endl; //a is now 10.
    cout << p << endl; // ALSO OUTPUTS the same memory address 2002
}

但是退出修改function时,“p”并不指向“b”的地址。

那是我的困惑,因为基于If Java has pass-by-reference 语义,我们上面定义的 foo 方法将改变 myDog 在 BBB 行上分配 someDog 时指向的位置。 并在 C++ 中应用相同的方法,结果 JAVA 或 C++ 都没有通过引用,但只能通过值 如果你能告诉我为什么 Java 在 C++ 中的行为就像我所看到的那样(以 DOG 为例)时没有通过引用传递,我将不胜感激!

谈论“pass-by-whatever”时最大的问题是不同的人对这些术语有不同的定义。 因此,出于此答案的目的,我将首先给出我对按值传递和按引用传递的定义。 如果直接分配给 function 内部的参数对调用 scope 中的传递变量没有影响,则 function 参数是按值传递的。 如果直接分配给 function 内部的参数与直接分配给调用 scope 中的传递变量的效果相同,则 function 参数是按引用传递的。

Under this definition, Java (as well as many other languages like C, JavaScript, Python, Ruby, Scheme) are always pass-by-value. Under this definition, C++ is always pass-by-value when the function parameter has & (including both the C++ examples you put here), and is always pass-by-value when the function parameter does not have & . 您的第二个 C++ 示例是按值传递的,因为如果您在modify()中直接分配给p (即p = something; ),它对调用 scope 没有影响。 modify()中,您从未直接分配给p 您改为使用*运算符取消p的引用,并将其分配给结果。 这与分配给p不同。

C++和Java最大的区别是有哪些类型。 Java 中的唯一类型是基元类型和引用类型。 引用类型的值是“引用”,即指向对象的指针。 没有“对象类型”,因此变量的值不能直接是 object。 没有指向原语的指针,或指向对象的指针,或其他指针组合。

您的 Java 示例:

public static void main(String[] args) {
    Dog myDog = new Dog("Rover");
    foo(myDog);
    // here, "myDog" points to the first Dog object, and has the name "Max"
}

public static void foo(Dog someDog) {
    someDog.setName("Max");
    someDog = new Dog("Fifi");
    someDog.setName("Rowlf");
}

相当于这个 C++ 代码(忽略 memory 管理方面):

void main(void) {
    Dog *myDog = new Dog("Rover");
    foo(myDog);
    // here, "myDog" points to the first Dog object, and has the name "Max"
}

void foo(Dog *someDog) {
    someDog->setName("Max");
    someDog = new Dog("Fifi");
    someDog->setName("Rowlf");
}

这两个示例都是按值传递的,因为它们都直接分配给参数( someDog = ),并且在这两种情况下,它们都对调用 scope 没有影响——它们都只是更改了 function 内的指针指向不同的 object,但它们不影响main中的指针指向的内容。 (Note that the syntax is a little different: the equivalent of the Dog type in Java is the Dog * type in C++, and the equivalent of -> in C++ is . in Java.)

C++ 具有 object 类型,其中变量的值可以是 object 本身。 在这种情况下,这种类型的参数意味着 object 在传递时被复制:

void main(void) {
    Dog myDog("Rover");
    foo(myDog);
    // here, the Dog object in the local variable "myDog" has the name "Fifi"
}

void foo(Dog someDog) {
    // this calls the object's assignment operator, which by default
    // copies all the fields
    someDog = Dog("Fifi");
}

Java 中没有与此等效的,因为 Java 没有 object 类型。 对象总是通过引用(指向对象的指针)来操作。

您还可以通过 C++ 中的引用传递 object,如下所示:

void main(void) {
    Dog myDog("Rover");
    foo(myDog);
    // here, the Dog object in the local variable "myDog" has the name "Fifi"
}

void foo(Dog &someDog) {
    // this calls the object's assignment operator, which by default
    // copies all the fields
    someDog = Dog("Fifi");
}

在这里,直接赋值给参数 ( someDog = ) 与调用 scope 中的相同赋值具有相同的效果。 Java 没有等效项,因为它既没有 object 类型也没有传递引用。

您还可以通过引用传递指向 object 的指针:

void main(void) {
    Dog *myDog = new Dog("Rover");
    foo(myDog);
    // here, "myDog" points to the second Dog object, and has the name "Fifi"
    // the first Dog object still has the name "Rover"
}

void foo(Dog *&someDog) {
    someDog = new Dog("Fifi");
}

在这里,直接赋值给参数 ( someDog = ) 与调用 scope 中的相同赋值具有相同的效果,这会导致指针指向不同的Dog object。 Java 没有等效项,因为它没有传递引用。 但是,有些语言的类型与 Java 相似,但它们具有传递引用。 例如,如果参数标记为refout ,则 C# 会按引用传递,如果参数标记为& ,则 PHP 会按引用传递。 这是 C# 中的等效代码:

static void Main() 
{
    Dog myDog = new Dog("Rover");
    foo(ref myDog);
    // here, "myDog" points to the second Dog object, and has the name "Fifi"
    // the first Dog object still has the name "Rover"
}
static void foo(ref Dog someDog)
{
    someDog = new Dog("Fifi");
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM