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