Many students and programmers, even professionals, find declarations in C++ very confusing. In fact, many professionals propagate false information and then give (reasonable) advice based on the false information.
The following was written as an answer to a question on Piazza, and so it is not all that thorough and could benefit from additional text and examples. However, even in its current form, I hope that it proves helpful!
In C and for all but reference variables in C++, the rule for
declarations is that you
show how to use a variable to get a simple type
(int
, float
, char
, bool
,
a struct
/union
/enum
,
class). A declaration is NOT a type followed by a variable.
You show C++ how to use a variable to get something it knows
about.
int n; int na[...]; int nf(); int *np; int &nr = n;
int n;
means n
is a variable that can
hold int
values, it is an integer variable.
int na[...];
means that na
is a variable
that you can subscript (na[i]
) to get an
integer; na
contains an array of int
variables.
int nf();
means nf
is a thing you can call
to get an int
; it holds a function that returns
an int
.
int *np;
means you can dereference np
(*np
) to get an int
; np
is a
variable that can hold a pointer value that is the address of a
variable containing an int
.
Nice and consistent so far! Show C++ how you intend to use the variable to get to a thing of the named type.
int &nr = n;
means that nr
is a
reference to another variable containing an int
.
Because a reference by definition is an alias for another variable,
you can't have one that is uninitialized. This example now says
that n
and nr
both refer to the same
variable, the same place in memory! You cannot change what a
reference refers to after it's set. It is just a name for some
other variable.
A reference parameter is initialized when a function is called.
That is, in int frob(Snail &gary);
, every time the
function is called, the caller has to call the function with a
variable containing a Snail
instance, and then
inside frob
, gary
will will refer to that
exact same variable (place in memory).
So, you can write n = frob(pink)
if pink
is
a variable that holds a Snail
.
Pause. This also
works:
Snail *cargo = new Snail; ... n = frob(*cargo); ...
Inside frob
, gary
will be another name for
the Snail
pointed to by cargo
. This means
that &gary
inside frob
, the address of
the Snail
object stored in gary
, will be
equal to the contents of cargo in the calling function!
That is what is going on in the assignment
operator. this
is a parameter/local variable that
contains the address of the instance the member function was called
on. The variable I usually call rhs
is a reference
to the variable on the right of the assignment. So, we check
whether something is
assigning to itself thus: if &rhs == this