Any more detailed course or explanation of pointers but referring to classes in c ++?
There are no differences in the use of pointers with basic data or with objects. In both cases the pointers work in the same way: they contain a memory address which can be (or not be) the memory address of a data.
Basic notions.
The functions that you have set, as long as they belong to a 1 object, would return respectively:
int getEdad() { return edad; }
copy of edad
.
int& getEdad() { return edad; }
reference to edad
.
int* getEdad() { return &edad; }
pointer to edad
.
These three styles of returning data from a function have elementary differences.
- In the first case you get a copy of the internal data and any modification on it will not affect the original data; On the other hand, this copy may have a life cycle different from the original data.
- In the second case you get a reference to the internal data , this allows you to make changes to the reference that will be reflected in the original data; but if the original data is deleted you will have a hanging reference and operate on this reference will cause unexpected behavior in your program ... this reason (among others) is considered a bad practice to return a reference to an internal data.
- In the third case you get a pointer to the internal data , through the pointer you could modify the original data so it has the same disadvantages as the reference.
Broadly speaking, the difference between pointer and reference to an internal data is that once the reference is created it can not point to another data while the pointer does. On the other hand, a pointer can be null while a reference can not.
Intermediate notions.
Returning a reference does not imply that you are going to have a reference. In other words: the return type of a function does not have to be the type used to store the return; Suppose we have this class:
struct S
{
int edad{};
int copia() { return edad; }
int& referencia() { return edad; }
int* puntero() { return &edad; }
};
We can save a reference to the returned data in all cases:
S s;
const int& referencia1 = s.copia();
int& referencia2 = s.referencia();
int& referencia3 = *s.puntero();
Both referencia2
and referencia3
would be a reference to s.edad
and any operation on one of those references would be reflected in both the other and the original data.
Regarding referencia1
would be a reference to a temporary data ( S::copia
returns one data per copy) and C ++ does not allow this type of references unless they are constant. A constant reference to a temporary data extends the life cycle of the data until the end of the reference life cycle, otherwise we would have a hanging reference.
In the same way we can save a pointer to the returned data:
S s;
int* puntero1 = &s.copia();
int* puntero2 = &s.referencia();
int* puntero3 = s.puntero();
Both puntero2
and puntero3
contain the memory address of s.edad
and s.edad
could be modified through these pointers.
The case of puntero1
is a compilation error: it is not possible to obtain the memory address of a temporary value
Finally we can the data per copy regardless of what the function returns:
S s;
int dato1 = s.copia();
int dato2 = s.referencia();
int dato3 = *s.puntero();
In all three cases, including the dato2
, we will have a copy of s.edad
.
Advanced notions.
The et ( &
) can be used in another context in the declaration of a member function:
struct S
{
int edad{};
int copia() && { std::cout << "c&&\n"; return edad; }
int& referencia() && { std::cout << "r&&\n"; return edad; }
int* puntero() && { std::cout << "p&&\n"; return &edad; }
int copia() & { std::cout << "c&\n"; return edad; }
int& referencia() & { std::cout << "r&\n"; return edad; }
int* puntero() & { std::cout << "p&\n"; return &edad; }
};
The version with an et ( &
) corresponds to the calls of the member function when the owner object is not a temporary object. The version with two et ( &&
) is for when the member function is called from a temporary object:
S s{};
auto a = s.copia(); // muestra c&
auto b = s.referencia(); // muestra r&
auto c = s.puntero(); // muestra p&
auto d = S{}.copia(); // muestra c&&
auto e = S{}.referencia(); // muestra r&&
auto f = S{}.puntero(); // muestra p&&
Keep in mind that in the previous example e
is a hanging reference and f
is a pointer to data that no longer exists, because they obtained references or pointers to temporary data.
1 And each one had a different name, since you can not overload it by return ... well yes it can (with a bit of witchcraft) but it's not what you have to talk about this question:)