In Java, you have two kinds of objects: those always passed by value, which are exclusively the native data types: int, long, double, ... and the non-native ones, implicitly inheriting from Object, which are stored in variables as references and passed on as such on assignment (e. g. to other variables or function parameters).
In C++, any data type can show both types of behaviour, being passed by value or passed by reference. And in C++, you have to be explicit about.
In C++, you have three ways, not just two, how you can pass on objects:
- by value
- by reference
- by pointer
Java references are far closer to C++ pointers than to C++ references, though: You can re-assign pointers to different objects, you cannot do so for references. It helps considering C++ references just as an alias (another name) for a concrete object, ignoring that under the hoods this might really apply in some cases (then no memory is allocated for at all) and in others (especially function parameters) not.
Now to be precise: Even in Java every variable is copied, even the reference variables. But for the latter, it is only the reference itself that is copied, not the object! So to show up the parallels:
// Java // C++
int n = 10; int n = 10;
String s = "hello"; std::string* s = new std::string("hello");
f(n, s); f(n, s);
voidf(int n, String s) void f(int n, std::string* s)
{ {
n = 12; n = 12; // in both cases, only local variable changed
s += "ads"; *s += "ads";
// ^ solely: special syntax for pointers!
s = "world"; s = new std::string("world");
// now s refers/points to another object in both cases
} }
Should be known so far... To be honest, above is simplified too much: In Java, we have automatic garbage collection, in C++, we don't. So actually, the string objects created above in C++ are never cleaned up any more and we have a memory leak! Modern C++ introduced smart pointers to facilitate the issue, consider the garbage collection in Java as well, the C++ code might rather look like:
int n;
std::shared_ptr<std::string> s = std::make_shared("hello");
f(n, s);
void f(int n, std::shared_ptr<std::string> s)
{
n = 12;
*s += "ads";
s = std::make_shared("world");
}
where std::shared_ptr does all the reference counting that in Java is hidden in the Object base class...
Unlike in Java, you can pass the string by value, too, though:
void f(int, std::string s);
Now the string will be copied into the local variable, just like the int. Solely: How???
That's where the copy constructor comes into play. If you want so, it is a recipe for how to create that copy, i. e. how to copy the internal representation into the new object. For a std::string, this would be some internal, dynamically allocated array holding the string's contents, its current capacity (i. e. total length of the array) and its size (how much of the array actually is occupied).
Finally the C++ reference:
void f(int, std::string& s);
In this case, s will always refer to the object that was assigned to the function, you cannot change the reference (at least not legally, in some cases you could with some really dirty hacks...), only the referred object.
Actually, in C++ the issue is more complex:
In Java, you get automatic memory management, there's a garbage collector selecting all objects that aren't referred to any more. Such thing doesn't exist in C++, we need to care for cleanup manually. Actually, the strings I created in the sample above aren't cleaned up at all, so we got a memory leak!!!
A more modern way is