Suppose you have an Object class. You instantiate three objects locally:
Object o1, o2, o3;
Then you have a function:
void f(Object o1, Object &o2, Object * o3);
This summarises the three ways you can pass an object to a function: by value, by reference and by reference via a pointer (let’s call it for simplicity call by pointer). Say you call the function like this:
f(o1, o2, &o3);
Inside the function, you may access these objects’ fields like this (note o3):
o1.x += 3;
o2.x += 3;
o3->x += 3;
These are the take home messages:
- [Call by value]: o1 is going to be copied inside the function f, then after f returns the copy is going to be destroyed. This means that any changes made by f onto o1 are not going to be visible outside f. In addition to being unsuitable to persist changes, the copy overhead can be very deleterius in certain high-performance applications – however, there is no access overhead.
- [Call by reference]: o2 is NOT going to be copied, so any changes made to o2 inside f are going to remain even after f returns. This is very efficient: no copy and methods/fields have no access overhead.
- [Call by pointer]: you are actually passing a pointer to o3 to f, so to access the objects’ fields and methods you need to dereferentiate every time (using the -> operator). This makes it averagely efficient: no copy but access overhead.
It’s clear that, even when you don’t actually need to modify an object, call by reference should be your default approach.