简体   繁体   中英

Java and C++ pass by value and pass by reference

It is said that in Java method arguments are passed by value which is true for primitives and for objects, object's reference is passed by value. To illustrate consider the code:

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.

What is the C++ equivalent that would give same results?

What is C++ equivalent that would give the value of d1 after calling the method to be the same value as within the method ie the caller see the modified value?

C++ does not have the same semantics as Java for values and references. At first, every type has the potential to be either passed by copy or by reference or by address (you can however prevent types to be passed by copy by hiding the copy constructor).

The passing type the most closely related to Java's "by reference" passing is by pointer. Here are an example of the three:

void foo(std::string bar); // by copy
void foo(std::string& bar); // by reference
void foo(std::string* bar); // by address

As a side note, passing by copy is always more expensive than passing by reference or pointer for types that are larger than the size of a pointer. For this reason, you may also often prefer to pass by const reference, which will allow you to read an object without having to copy it.

void foo(const std::string& bar); // by const reference

However, this is all tricky and you need to be aware of Java subtleties to decide correctly what you want in C++. In Java, you're not actually passing objects by references: you are passing object references by copy. That is, if you assign a new object to an argument, the object of the parent scope won't change. In C++, this more closely matches passing objects by address than by reference. Here's an example of how this is important:

// 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"
}

In other words, when you use references in C++, you're really dealing with the same variable you passed. Any change you do to it, even assignations, are reflected to the parent scope. (This is in part due to how C++ deals with the assignation operator.) Using pointers, you get a behavior more closely related to the one you have with Java references at the cost of possibly having to get object addresses through the unary & operator (see foo(&bar) in my example), needing to use the -> operator to access members, and some additional complexity for using operator overloads.

Another notable difference is that since the usage of by-reference arguments is syntactically closely related to the usage of by-copy arguments, functions should be able to assume that the objects you pass by reference are valid. Even though it's usually possible to pass a reference to NULL , this is very highly discouraged as the only way to do it is to dereference NULL , which has an undefined behavior. Therefore, if you need to be able to pass NULL as a parameter, you'll prefer to pass arguments by address rather than by reference.

Most of the time, you'll want to pass by reference instead of by address when you want to modify an argument from a function because it is more "C++ friendly" (unless you need the NULL value), even though it's not exactly like what Java does.

C++ passes by value by default. You can implicitly pass by reference by writing the function to accept a reference, or explicitly by passing a pointer.

Consider the following three examples:

FooByValue(Foo arg)
{
  //arg is passed by value.
}

FooByReference(Foo & arg)
{
  //arg is passed by reference.
  //changes made to arg will be seen by the caller.
}

FooByPointer(Foo * arg)
{
  //arg is passed by reference with pointer semantics.
  //changes made to the derefenced pointer (*arg) will be seen by the caller.
}

You can then call the above as follows Foo anObject;

FooByValue(anObject); //anObject will not be modified.
FooByRefence(anOBject); //anOBject may be modified.
FooByPointer(&anObject); //anObject may be modified.

The & symbol when applied to a variable like &anOBject is used to get the address of the variable, basically giving a pointer to the location in memory that variable is stored in.

FooByValue() operates like your example, and FooByReference() will keep any changes made to the arguments after the function call, as the argument will not be copied, its actual location in memory will be shared.

class Test {
 void dateReplaceReference(Date& arg) {
   // arg is passed by reference, modifying arg 
   // will modify it for the caller
 }
 void dateReplaceCopiedArgument(Date arg) {
   // arg is passed by value, modifying arg 
   // will not modify data for the caller
 }
 void dateReplaceByPointer(Date* arg) {
   // arg is passed as pointer, modifying *arg 
   // will modify it for the caller
 }
};

Note that passing as reference or by pointer is the same thing. The only difference is how you want access the data, by a "." or by "->". Also, you cant pass a null value to a method taking a reference.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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