Code:
It's similar to a pointer, but not as useful...
Why isn't a reference as useful? Some of the most experienced people on this forum advocate using references instead of pointers.
[a reference] doesn't need to be dereferenced. Other than that, why would you use it instead of a pointer?
The syntax is simpler. For instance,
Code:
#include <iostream>
using namespace std;
class Apple
{
public:
int num;
};
void changeIt(Apple& anApple)
{
anApple.num = 30;
}
int main()
{
Apple myApple;
myApple.num = 10;
changeIt(myApple);
cout<<myApple.num<<endl; //30
return 0;
}
All I had to do was put a '&' symbol in the parameter name, and I could "pass by reference" and change the original object in main(). Especially note that I didn't have to declare an extra pointer variable and assign it the address of myApple, and then pass the pointer to the function.
Also, I've seen this, which is really confusing me: int*& var, for example, usually as a function parameter. What does *& mean?
That notation gets to the very essence of what "passing by value" and "passing by reference" really mean. You could say there is really no such thing as "passing by reference" and everything is "passed by value", by which I mean to say that all function parameters are passed the same way--they are copied for the function. Typically, C++ texts will make a big point of the differences between "passing by value" and "passing by reference". They will give an example of "passing by value" similar to this:
Code:
#include <iostream>
using namespace std;
class Apple
{
public:
int num;
};
void changeIt(Apple anApple)
{
anApple.num = 30;
}
int main()
{
Apple myApple;
myApple.num = 10;
changeIt(myApple);
cout<<myApple.num<<endl; //10
return 0;
}
C++ texts will explain that when you pass myApple to the function, a copy of myApple is made for the function and stored in the function parameter variable anApple. Then, the function changes anApple which is just a copy of myApple, which leaves the original myApple unchanged. Therefore, the function isn't able to change the original object.
However, the C++ texts will say that if you "pass by reference", then the original object isn't copied, so the function can change the original object. For instance,
Code:
#include <iostream>
using namespace std;
class Apple
{
public:
int num;
};
void changeIt(Apple* aPtr)
{
aPtr->num = 30;
}
int main()
{
Apple myApple;
myApple.num = 10;
Apple* myPtr = &myApple;
changeIt(myPtr);
cout<<myApple.num<<endl; //30
return 0;
}
It's true that the function can permanently change the object, however when you send a pointer to a function, why would the original object ever get copied? The original object was never sent as an argument to the function. The fact of the matter is: the pointer is the argument being sent to the function, and just like when you send an object to a function, the pointer is copied for the function. So, the function gets a copy of the pointer, and since a copy of a pointer points to the same place as the original pointer, the function can use the pointer to change the object. As the example above shows, the object reflects the changes made by the function.
Ok, so now that you know a copy of the original pointer is made for the function, what happens if instead of changing the object, you want the function to be able to change the pointer, i.e. assign it another address? Well, you're in the same predicament as when you send an object to a function: the function cannot change the original pointer because all it has is a copy of the pointer. Here is an example:
Code:
#include <iostream>
using namespace std;
class Apple
{
public:
int num;
};
void changeIt(Apple* ptr1, Apple* ptr2)
{
ptr1 = ptr2;
}
int main()
{
Apple myApple;
myApple.num = 10;
Apple* myPtr = &myApple;
cout<<myPtr->num<<endl; //10
Apple yourApple;
yourApple.num = 30;
Apple* yourPtr = &yourApple;
changeIt(myPtr, yourPtr);
cout<<myPtr->num<<endl; //10
return 0;
}
The example shows that the function was unable to change the pointer myPtr that was passed to the function. After calling the function, myPtr still points to the same object. However, there is a way to solve that problem. The solution is identical to when you have an object and you use pointers to "pass by reference", so the function can change the object. In this case, if you think of myPtr as the object you are passing to the function, how can you enable the function to make changes to that object? The answer is: you pass a pointer to the object--which means you can pass a pointer to myPtr. Your function parameters would look like this:
void changeIt(myPtr* ptr1, Apple* ptr2)
But, myPtr isn't a type, so you can't list it as one. myPtr is of type Apple*, so substituting you get:
void changeIt(Apple* *ptr1, Apple* ptr2)
Here is a complete example:
Code:
#include <iostream>
using namespace std;
class Apple
{
public:
int num;
};
void changeIt(Apple* *ptr1, Apple* ptr2)
{
*ptr1 = ptr2;
}
int main()
{
Apple myApple;
myApple.num = 10;
Apple* myPtr = &myApple;
Apple* *ptr = &myPtr;
cout<<(*ptr)->num<<endl; //10
Apple yourApple;
yourApple.num = 30;
Apple* yourPtr = &yourApple;
changeIt(ptr, yourPtr);
cout<<(*ptr)->num<<endl; //30
return 0;
}
The notation is pretty tortured and confusing, but here is an explanation. In the function, dereferencing ptr1 gets you an Apple pointer, which points to myApple. If the function was able to change the 'ptr' variable that was sent as an argument, then back in main(), ptr should hold the address of the function parameter ptr2. But, ptr2 is a copy of yourPtr, and a copy of yourPtr and yourPtr hold the same address. Since ptr was assigned ptr2, ptr should hold the address of yourPtr. In turn, yourPtr holds the address of yourApple. So, back in main(), you should end up with:
ptr------>yourPtr---->yourApple
The output shows that was the case.
Since references are nearly equivalent to pointers, you are able to accomplish the same thing as the last example with much cleaner syntax:
Code:
#include <iostream>
using namespace std;
class Apple
{
public:
int num;
};
void changeIt(Apple* &ptr1, Apple* ptr2)
{
ptr1 = ptr2;
}
int main()
{
Apple myApple;
myApple.num = 10;
Apple* myPtr = &myApple;
cout<<myPtr->num<<endl; //10
Apple yourApple;
yourApple.num = 30;
Apple* yourPtr = &yourApple;
changeIt(myPtr, yourPtr);
cout<<myPtr->num<<endl; //30
return 0;
}
As you can see, the syntax is much less tortured than when pointers were used.