.. _lecture13: C++ Pointers ############ .. include:: /header.inc .. vim:filetype=rst spell: All of the work done in designing our Poolball simulation up to this time focused on the basic properties of the Poolball and Pooltable objects themselves. We already saw a simple solution, using a fixed size array of Poolball objects. But what if we want to let the user control how many balls are on the table? Maybe we want to hand the Poolball to the Pooltable, and ask it to save that ball for later use. Objects as Parameters ********************* As we discussed earlier, actually passing a Poolball object to another object is a bit difficult to do. We can pass a `copy` of an object to another one, but the original object stays behind, under control of the originator of this action. C++ provides a way out of this problem by allowing us to pass a `reference` to an object to another method. Unfortunately, we cannot store that referenced object in an array, which is what we need to do in our Poolball simulation Exactly what C++ does when we pass an object by `reference` is left to the compiler to figure out, and the C++ standard just says that we are not allowed to put a reference into an array. Using References ================ When we pass a `reference` to another method, we do not use any special notation to use the object in the second method. We use it like any normal object, modifying the values as we need to. When the calling method gets control back, the changes will be felt in the original object. If we try to make a copy of that variable (the one referring to the caller's object) things get messy quickly: how is this new copy actually implemented. Is it a piece of memory holding all the original objects attributes, a copy of those, or a copy of a copy of those? Phew? C++ Pointers ************ We get out of this mess, and introduce a huge new capability in our language, by introducing a new data type: the `pointer`. A `pointer` is just a memory container containing the `address` of some object that occupies memory in the computer when your program runs. C++ requires that we identify exactly what this address `points` to. Once we know this, we can access that object indirectly. We cannot use the name of the object, since we will not know that when we receive just an address, so we use the name of the container we set up to hold the pointer, and some notation that tells the system to follow the pointer to find the real object to play with. Here is what this looks like: .. literalinclude:: code/ex01/test1.cpp :linenos: :language: c The critical new declaration is on line 13. Read it like this: ``obj_ptr`` is a `pointer` (*) to a ``SimpleObj`` object Here is what you should get when running this code: .. command-output:: g++ -o demo test1.cpp :cwd: code/ex01 .. command-output:: ./demo :cwd: code/ex01 The new notation is that "->" thing that was used to access the attribute of the object being pointed to by this new container, `obj_ptr`. (Notice how I name pointer variables. I do not want to be confused about what this thing is!) In my past teaching, I came up with an analogy that helps explain what is going on in the C++ system. Variables ========= When you first learned about programming, you were introduced to the idea of a ``variable``, right? A ``variable`` is a chunk of memory holding a bunch of bits. Pretend that this container is a physical box with a lid on it. On the side of the box, you write the name of the variable. When you declared this variable, the system manufactured this box for you using a blueprint we call a ``data type``, and stuck the new box on a shelf somewhere in the system (in memory). Exactly where, you do not care (normally). When you open the lid of the box, you usually see a bunch of switches, all set on or off at random. If you ``initialized`` your variable, the switches are set according to the encoding scheme used by the ``data type`` you used to describe the box when you first set it up. Got this so far? Objects ======= An object is the same kind of thing, with one major difference. When we open up this box, we find a set of other boxes, each manufactured exactly the same way, then collected and put into this new ``object`` box. The inner boxes hold the object's ``attribute`` variables. We must open them up to get at actual places to put information. The proper term for this ``object`` box is ``data structure``, meaning a box that holds a collection of other things. When we access the object box, we use the name written on the side of the box, something like ``obj``. When we mean that we want to access one of the attribute inner boxes, we use notation like ``obj.value``, meaning open up the object box, then open up the inner ``value`` attribute box. .. note:: We use the same concept to access methods defined in the class that set up the object. The dot notation lets us access a method that will work on the attribute data of one specific object. Pointers ======== A ``pointer`` variable is exactly the same thing as a simple variable, except for one new thing. When you open up the lid of this box and look inside, you do not find a bunch of switches. Instead, you find a hook. This new box is called a ``pointer variable``, and the hook helps you find the thing it points to. When you build a new ``pointer variable``, the box is manufactured, put on a shelf somewhere, just as before. The hook has nothing hanging from it. It is ``uninitialized``. .. warning:: Just as with normal variables, we should explicitly make sure it does not point to some random thing in memory by making its value ``NULL``, meaning "points to nothing". NULL is defined as part of the "iostream" library. If we place the ``address`` of a real object variable of the type we told the system we would be pointing to, the system goes to the box we want to point to and ties a piece of rope around that box. It ties the other end of the rope on the hook in the ``pointer variable`` box. Now, when you open up the pointer variable box, you see a hook with a piece of rope tied on it. If you drag in that rope, the box you are pointing to will end up in your hands (well, not rally, it is actually glued to the shelf, so you will have to follow the rope to find that box.) Opening up the box you find will let you access that boxes switches. Simple, and the analogy works pretty well at explaining how things work in C++ programs. The "->" notation tells the system to follow the rope to a box. When you find it, the box has a second box labeled "value" inside. Open up that one to proceed. Phew! And Furthermore =============== Of course, funny things can happen when you open up the box at the end of the rope. What would happen if that box was actually an object? Simple, we just open it up and access the inner box. In our example, that box was an integer, and had switches we interpret as an integer number. But what if when we opened up the inner box, we find a second hook? YIKES, what will we do now. Just follow the rope and see where it leads. We will see more of this in a later lecture. For now, let your imagination run wild on what you can set up and how you will find your way through this new tangle of ropes! Passing Pointers to Methods *************************** Once we have the idea of a pointer under control, we can pass an address to a method as a second way to access the caller's object. Here is what it looks like: .. literalinclude:: code/ex02/test2.cpp :linenos: :language: c And here is the output: .. command-output:: g++ -o demo test2.cpp :cwd: code/ex02 .. command-output:: ./demo :cwd: code/ex02 This version obviously accessed the object that was being pointed to, but can the new method actually modify the original one? Try this version: .. literalinclude:: code/ex03/test3.cpp :linenos: :language: c Here it the final output: .. command-output:: g++ -o demo test3.cpp :cwd: code/ex03 .. command-output:: ./demo :cwd: code/ex03 Looks like it can! .. vim:filetype=rst spell: