Pointers, Big 3, Operator Overloading, Growable Arrays, Friends

In Java, if you have:Person p = new Person(...);

then p is not a Person object but it is a reference to a Person object.

In C++, if you have:Person p(....);then p is a Person object.

The difference is that in the first case, the person object is allocated from heap memory whereas in the second case, it is allocated on the stack (or data segment, if it is a global variable).

Objects can be allocated from the heap in C++, but that means that you need to use pointers. And unlike Java, which has garbage collection, C++ requires YOU to do the memory management! In C++, allocating an object dynamically looks quite a bit like Java:

Person * p = new Person(....);

However, to access a pointer, you need to "dereference" it by placing an asterisk in front of the variable. So if Person has a Jog method, it would be called as: (*p).Jog();

An alternative (and preferred) syntax uses another operator:p->Jog();

When the object pointed to by p is no longer used anywhere in the program, it must be deleted:

delete p; // Doesn't delete p - it gives back the memory pointed to by p!

Of course, problems such as forgetting to delete it (memory leak) or deleting an object that is being pointed to and used somewhere else in the program are two of several errors that one can potentially make when dealing with memory management!

You can also make dynamic arrays, similar to what was done in Java:int * a = new int[n];

You use it just like you did in Java:a[i] = x + y;

When you are done with this, you delete it as:delete[] a;

To make dynamic array of objects, such as:Person * list = new Person[n];

Person must have a default constructor. You can also make dynamic arrays of Person pointers,

such as:Person * * list = new Person * [n];

In this case, Person doesn't need a default constructor, but allocating and deleting become a little trickier!

Besides its other uses (and, bit-wise and, reference), the and-sign (&) is also used to mean "address of", so if we can do: int * p = &x; assuming x is an int variable.

One final point: We can finally tell you the secret about C++ arrays: they are not objects, as in Java. They are really just pointers - constant pointers. C++ allows pointer arithmetic. Assume we have: int a[5]; int * p = &a[0]; // could also have put: p = a;

Then:p = p + 1; moves p ahead sizeof(int) bytes and points at a[1].

So an array access such as:a[i]

is treated in C++ (as per C) as:*(a + i )

where a is a constant pointer (can't be pointed anywhere else) to a[0].

Below is the start of a Person class. The name is stored in a dynamic array to illustrate a number of concepts. I have not commented the following code correctly (according to our ground rules).

Instead, I have used "editorial" comments, pointing out special notes. You can look at the ground rules to see how this should have been commented.

Below is part of the Person.h file - not commented correctly!

#ifndef __PERSON_H

#define __PERSON_H

#include <iostream>

usingnamespace std;

class Person

{

public:

Person( constchar * initName, int initID );

// Big 3: can't be "Person p" - otherwise chicken and egg problem!

Person ( const Person & p )

{ name = NULL; *this = p; } // NULL so operator= works correctly

~Person() { delete[] name; }

Person & operator= ( const Person & p );

// Some operator overloading examples

booloperator< ( const Person & p ) const

{ return strcmp(name, p.name) < 0; }

intoperator== ( const Person & p ) const

{ return strcmp(name, p.name) == 0; }

intoperator!= ( const Person & p ) const

{ return !(*this == p); }

// Growing an array

void Hyphenate ( constchar * addon );

// ... And any other methods that make sense

private:

staticconstint MAX_NAME_LEN = 100; // Could do away with this.

char * name;

int id;

// ... And any other private data and methods that make sense

// friends: allow access to private members

friend ostream & operator< ( ostream & os, const Person & p );

friend istream & operator> ( istream & is, Person & p );

};

#endif

Below is part of the Person.cpp file - not commented correctly!

#define _CRT_SECURE_NO_DEPRECATE

#include <iomanip>

usingnamespace std;

#include <cstring>

#include "Person.h"

#include "LeakWatcher.h"

Person::Person( constchar * initName, int initID )

{

id = initID;

if( initName == NULL ) // just in case they passed a NULL

name = NULL;

else

{

name = newchar[strlen(initName) + 1]; // room for terminating '\0'

strcpy(name, initName);

}

}

Person & Person::operator= ( const Person & p )

{

if ( this != &p ) // Handle the case: a = a;

{

delete[] name; // get rid of the old

if ( p.name == NULL )

name = NULL;

else

{

name = newchar[strlen(p.name) + 1];

strcpy ( name, p.name );

}

id = p.id;

}

return *this; // To allow: a = b = c = ...

}

void Person::Hyphenate ( constchar * addon ) // I now pronounce you...

{

if ( addon == NULL )

return; // Cold feet!

char * temp = newchar[strlen(name) + strlen(addon) + 2];

strcpy( temp, name );

strcat( temp, "-" );

strcat( temp, addon );

delete[] name; // Get rid of the old

name = temp; // Assign the new

}

// Note that these are not methods

istream & operator> ( istream & is, Person & p )

{

char buff[Person::MAX_NAME_LEN + 1];

is > p.id > buff;

delete[] p.name;

p.name = newchar[strlen(buff) + 1];

strcpy ( p.name, buff );

return is;

}

ostream & operator < ( ostream & os, const Person & p )

{

os < setw(3) < p.id < ": " < p.name;

return os;

}

Below is the some sample usage of Person - not commented correctly!

#include "Person.h"

// Memory Leak checking declarations

#define CRTDBG_MAP_ALLOC

#include <stdlib.h>

#include <crtdbg.h>

void main()

{

try // very similar to Java

{

Person * p1 = new Person("sam", 10034 );

Person * p2 = new Person("sue", 51162);

cout < "P1: " < *p1 < endl;

cout < "P2: " < *p2 < endl;

cin > *p1 > *p2;

cout < "P1: " < *p1 < endl;

cout < "P2: " < *p2 < endl;

if ( *p1 < *p2 )

cout < "p1 less p2" < endl;

else

cout < "p1 not less than p2" < endl;

p1->Hyphenate ( "Jones" );

cout < "P1: " < *p1 < endl;

// .... etc to test the rest

delete p1;

delete p2;

}

catch ( ... ) // catch anything

{

cerr < "Caught an error!" < endl;

}

_CrtDumpMemoryLeaks();

}