Java和C++按值传递并通过引用传递

ace*_*ace 2 c++ java

据说在Java方法中,参数是通过值传递的,对于基元和对象都是如此,对象的引用是按值传递的.为了说明考虑代码:

class Test {
 private static void dateReplace (Date arg) {
        arg = new Date (arg.getYear(), arg.getMonth(), arg.getDate() +1);
        System.out.println ("arg in dateReplace: " + arg);
    }

 public static void main(String[] args) {

      Date d1 = new Date ("1 Apr 2010");
        dateReplace(d1);
        System.out.println ("d1 after calling dateReplace: " + d1);
    }
}

this will print:
arg in dateReplace: Fri Apr 02 00:00:00 2010
d1 after calling dateReplace: Thu Apr 01 00:00:00 2010.
Run Code Online (Sandbox Code Playgroud)

什么是C++等价物,会产生相同的结果?

什么是C++等价物,在调用方法后将d1的值赋予与方法中相同的值,即调用者看到修改后的值?

zne*_*eak 5

对于值和引用,C++没有与Java相同的语义.首先,每种类型都有可能通过复制或引用或地址传递(但是,您可以通过隐藏复制构造函数来防止类型通过复制传递).

与Java的"引用"传递最密切相关的传递类型是指针.以下是三个例子:

void foo(std::string bar); // by copy
void foo(std::string& bar); // by reference
void foo(std::string* bar); // by address
Run Code Online (Sandbox Code Playgroud)

作为旁注,对于大于指针大小的类型,通过副本传递总是比通过引用或指针传递更昂贵.出于这个原因,您可能也经常更喜欢通过const引用传递,这将允许您读取对象而无需复制它.

void foo(const std::string& bar); // by const reference
Run Code Online (Sandbox Code Playgroud)

但是,这一切都很棘手,您需要了解Java细微之处,才能正确地确定您在C++中的需求.在Java中,您实际上并没有通过引用传递对象:您正在通过复制传递对象引用.也就是说,如果将新对象分配给参数,则父作用域的对象不会更改.在C++中,这更接近地通过地址传递对象而不是通过引用.以下是一个重要的示例:

// Java using "object references":
public static void foo(String bar)
{
    bar = "hello world";
}

public static void main(String[] argv)
{
    String bar = "goodbye world";
    foo(bar);
    System.out.println(bar); // prints "goodbye world"
}

// C++ using "references":
void foo(std::string& bar)
{
    bar = "hello world";
}

int main()
{
    std::string bar = "goodbye world";
    foo(bar);
    std::cout << bar << std::endl; // prints "hello world"
}

// C++ using pointers:
void foo(std::string* bar)
{
    bar = new std::string("goodbye world");
    delete bar; // you don't want to leak
}

int main()
{
    std::string bar = "goodbye world";
    foo(&bar);
    std::cout << bar << std::endl; // prints "hello world"
}
Run Code Online (Sandbox Code Playgroud)

换句话说,当您在C++中使用引用时,您实际上处理的是您传递的相同变量.您对它所做的任何更改,甚至是分配,都会反映到父范围.(这部分是由于C++如何处理赋值运算符.)使用指针,您可以获得与Java引用更紧密相关的行为,代价是可能必须通过一元运算&符获取对象地址(请参阅foo(&bar)在我的例子中),需要使用->运算符来访问成员,以及使用运算符重载的一些额外复杂性.

另一个值得注意的区别是,由于引用参数的使用在语法上与副拷贝参数的使用密切相关,因此函数应该能够假设您通过引用传递的对象是有效的.即使通常可以传递引用NULL,但这是非常不鼓励的,因为唯一的方法是取消引用NULL,它具有未定义的行为.因此,如果您需要能够NULL作为参数传递,则您更愿意按地址而不是引用传递参数.

大多数情况下,当你想要修改函数中的参数时,你会希望通过引用而不是地址传递,因为它更"C++友好"(除非你需要NULL值),即使它不完全像是什么Java确实如此.