Sunday, January 22, 2006

Pointers, References and Objects in C++

What I notice is that almost all C++ beginners have problems with the way objects are passed and handled in C++. Especially people coming from a Java background. Java basically just have one way of dealing with objects and that is through references (well that is a white lie, basic types are not). C++ on the other hand has 3! Not only that but they can be mixed in all kinds of confusing ways. So this post will be geared towards you Java programmers.

Dealing with objects directly instead of having pointers or references to them is the easy way. For primitive types like int, float, double etc Java and C++ are the same.

You declare a object like this:

int number;

Then you can assign values:

number = 20;

Okay I am not going to dwell on this. It is not a newbie tutorial. What is important to notice is that in C++ even classes can be declared as objects this way. They are then allocated on the stack and not the heap like objects allocated using new. We’ll talk more about the stack and head later.

MyClass obj;
MyClass otherObj;

obj = otherObj;

Unlike Java the last statement copies the whole contents of otherObj to obj. So no clone() or copy() type of statement is needed. You also do not need to create the object using new. So you might wonder. How does one pass arguments to the constructor?

In Java it would be something like this:

MyClass obj = new MyClass("Hello world", 12);

In C++ this can be done like:

MyClass obj("Hello world", 12);

Let us first start with the pointers. They resemble references in Java or other OO languages the most.

int* ptr; // Declares a variable that is a pointer to a int value ptr = new int; // allocates memory for int and sets ptr to point to value int number; // Creates a int value, allocated on stack number = 20; // Assigns it a value of 20 *ptr = 30; // Sets the value pointed to by ptr to 30 number = *ptr; // Assigns 30 to the number variable number = ptr; // Assign the address of ptr points to to number. number = 40; ptr = &number; // Makes ptr point to number variable number = 26; // ptr now points to the value 26

The code snippet above shows the many ways of using pointers.

References lets you write your code as if were dealing with objects direcly as allocated on a stack. The reason why C++ lets you do this is because it is a sort of safe pointer. Little will go wrong by treating the the reference as the object itself. A reference is however little more than a const. This put some limitations on its usage. Once a reference has been set to point to an object it can not be changed to point to another object. So in practice it is almost like an alias.

int number; int value = 20; int& ref = number; // Sets ref to reference (point to) number ref = 30; // Changes the value of number to 30 ref = value; // Changes the value of number to 20.

As can be seen in last line, when reference has first been assigned it is not changed. ref = value will not make ref reference the value variable.

*, &, . *, & and . are symbols that easily have their meaning mixed up in peoples head. Perhaps because what they mean depends on the context.

E.g. here are some different meaning of &:

int var2 = 3; int var3 = 5; int var1 = var2 & var3; // Binary and var2 and var3, Result = 7 bool b1 = false, b2 = true; bool b = b1 && b2; // Logical and b1 and b2, Result = false int* ptr = &value; // Get the address of value int& ref = value; // Declare ref as a reference

Likewise * can have many meanings:

var1 = var2*var3; // Multiply var2 and var3 int* ptr; // Declear a int pointer ptr = &var3; *ptr = var2; // Set value of variable pointed to by ptr to var2

And the situation doesn’t exactly get easier by the fact that these symbols can be combined.

int*& ptrRef = ptr; // Declares a reference to a pointer int** ptrPtr = &ptr; // Declare a pointer to a pointer

Pointer arithmetic and arrays
So what Java programmers probably wonder, is what is it one can do with pointers that one can’t do with references. What is the point with pointers anyway?

Pointers allow you to do operations on the pointers themselves and not just the values they point to. References do not allow this (C++ or Java).

int array[20]; // Creates and array with 20 int elements array[2] = 4; // Assign 4 to the 3rd element in the array int* ptr = array; // Makes ptr point to first element in array; *ptr = 3; // Assign 3 to the first element of array ptr[2] = 5; // Assign 5 to the 3rd element in the array ptr = ptr+2; // Address pointer points to increased by 2 *ptr = 3; // Assign 3 to the 3rd element of array ptr[2] = 5; // Assign 5 to the 5th (3+2) element of array

In C one can even set a pointer to point directly to an arbitrary memory location.

int *ptr = 40; // Set ptr to point to address 40

Back in the day this was actually how one manipulated graphics. Typically one would set a pointer to point to the location in memory where the screen buffer was located. Then the pixels on the screen could be changed by changing the value the pointer was pointing to.

Anyway I think I am getting into nitpicking. If somebody wants me to elaborate more on this I will. Otherwise I will write about other things.

No comments: