Suppose we have a class counter with a member function
void increment();And then we declare the following:
counter *bozo = new counter;So bozo now is a pointer to a counter, and *bozo is a counter. How would we invoke the member function increment? How about
*bozo.increment(); ???This would not be correct. The "." operator has a higher precedence than the "*" operator, so the compiler would interpret it as
*(bozo.increment());That's not at all what we want, and the compiler would complain. After all, bozo is not an object, it's a pointer to an object, so we can't invoke a member function. And increment doesn't return a pointer (in fact, because it's void, it doesn't return anything), so we certainly can't dereference what increment returns. So we would have to use parentheses to get the interpretation that we want. This would then be
(*bozo).increment(); //This would be okThere exists a "syntactic sugar" form for this construct, and it involves a new operator. It is the "arrow" operator and is formed by a "-" followed immediately by a ">". To invoke the member function increment() using the arrow operator we would write
bozo->increment();See Demo ptrNotation.cpp
In general, ",code>x ->" is the same as "(*x).
"
whenever x
is a pointer to an object. We can use "->" to
access any members, whether they be functions or data of the object
that x points to.
What if the drop objects in the raindrops program were big? That is to say, what if we needed a lot of memory to store one drop object? An array full of them could use a lot of storage. So what is the solution? We can make an array be of pointer to drop, i.e., each element is a pointer to a drop object rather than a drop object, and allocate space only as it is needed.
drop *theDrops[MAXDROPS];produces the following data structure.
|
theDrops[dropCount++] = new drop(center);
theDrops[thisDrop] -> enlarge();
We can make the above implementation of drops even more space-efficient by deleting drops once they are too big to draw.
newSlot < MAXDROPS && theDrops[newSlot]The first part of the test makes sure we haven't run off the end of the array. The second part checks whether the pointer in position newSlot is NULL. Recall that NULL is actually 0, so the expression
theDrops[newSlot]
is like saying theDrops[newSlot]
!= NULL
. So we keep looping as long as we haven't run off the
end of the array and we have not seen a NULL slot. Note also
how the short-circuiting &&
operator helps us. If
newSlot >= MAXDROPS, then there is no position numbered newSlot in the
array, so we had better not index into it. The short circuiting
prevents us from accessing this nonexistant array entry.
if (newSlot < MAXDROPS) { SysBeep(1); theDrops[newSlot] = new drop(center); }
|
It is important to remember that every "*" means to dereference.
See Demo ptrToPtr.cppA pointer to a pointer in the above demo looks like
|
So now what? Well, now we can have dynamic multidimensional arrays.
Suppose we want an M x N array, but we do not know M or N at compile time. This means that we cannot do the following
int A[M][N]; //Cannot do!!!Instead, we want something else. Something really cool!!! Graphically it looks like this:
|
int **A;Is this declaration of A consistent with wanting A[i][j] to be an int?