
CLASSES
-------

Classes are the foundation of object-oriented programming in the C++
language. 

A C++ class is a collection of DATA MEMBERS (which may be of different
types such as int, char, float, int*, etc.)  and MEMBER FUNCTIONS (which
are given the special name of METHODS). 

The class data type allows for the concept of ENCAPSULATION - a grouping of
data members and the functions which operate on this data into a unified
"object". 

The class construct allows for information hiding - a class can restrict
access to either its data members or its methods.  Information within a
class can be hidden by declaring the information to be 'private'.  Conversely, information may be visible to users of the class by declaring it to be
'public'.

Here is a conceptual view of a class:

        ----------------
        |              |
        | data members |   usually private
        |              |
        |              |
        ---------------
        | member       |  usually public
        | methods      |  the private data members of a class
        |              |  are only accessible through the member 
        |              |  functions (which are made public)
        ---------------- 


Circle Class Example
---------------------

Here is a very simple example of a circle class in C++.
A circle has associated with it a radius (stored as a float).
We can define two methods called Area and Circumference which will
return the area of a circle.  We will also define a method called
SetRadius(float r) which will set the radius to a certain value which
is passed as a parameter.


// Author: Ted Obuchowicz
// April 23, 2002
// example program illustrating use of
// a simple Circle Class

const float pi = 3.1415926;


#include <iostream>
#include <string>

using namespace std;




// define a class called Circle, class is a C++ keyword

class Circle
{
float radius;   // everything in a class is private by default

public:         // we want the following methods to be public, so we
                // make them public by using the public keyword followed
                // by a colon :

float Area();
float Circumference();
void SetRadius(float r);

};


// we now define the methods of the class, we use the scope resolution
// operator to inform the compiler that the method belongs to the class
// called Circle

float Circle::Area()
{
 return ( pi * radius * radius) ;
}

float Circle::Circumference()
{
 return ( 2 * pi * radius) ;
}

 void Circle::SetRadius(float r)
{
radius = r;
}




// let's use the class definition and the definitions of the three methods
// in a main program

int main()
{
 
// create two Circle "objects"

Circle mick, keith;

mick.SetRadius(2.00) ; // set the Radius of circle mick to 2.00
cout << "Circle mick has area " << mick.Area() << endl;
cout << "Circle mick has circumference " << mick.Circumference() << endl;

keith.SetRadius(5.00);
cout << "Circle keith has area " <<  keith.Area() << endl;
cout << "Circle keith has circumference " << keith.Circumference() << endl;

return 0;
}



The program output is:

Circle mick has area 12.5664
Circle mick has circumference 12.5664
Circle keith has area 78.5398
Circle keith has circumference 31.4159

Some comments on the program:

1) Note how we give the full name of the  methods when we define
   them using the form :

   return_type   class_name::method_name

   (note there is no space between the class_name::method_name)

   This is because there may be similaryly named methods belonging to
   different classes.

2) We could have also defined the methods within the class declaration.
   This style of defining a method is known as INLINE DEFINITION.
   Here is the same program using the inline definition form for the
   method definitions:


// Author: Ted Obuchowicz
// April 23, 2002
// example program illustrating use of
// a simple Circle Class using inline definition for the methods

const float pi = 3.1415926;


#include <iostream>
#include <string>

using namespace std;




// define a class called Circle, class is a C++ keyword

class Circle
{
float radius;   // everything in a class is private by default

public:         // we want the following methods to be public, so we
                // make them public by using the public keyword followed
                // by a colon :

// use the inline form to define the three class methods

float Area() { return ( pi * radius * radius) ; } ;
float Circumference() { return ( 2 * pi * radius) ;} ;
void SetRadius(float r) { radius = r;};

};






// let's use the class definition and the definitions of the three methods
// in a main program

int main()
{
 
// create two Circle "objects"

Circle mick, keith;

mick.SetRadius(2.00) ; // set the Radius of circle mick to 2.00
cout << "Circle mick has area " << mick.Area() << endl;
cout << "Circle mick has circumference " << mick.Circumference() << endl;

keith.SetRadius(5.00);
cout << "Circle keith has area " <<  keith.Area() << endl;
cout << "Circle keith has circumference " << keith.Circumference() << endl;

return 0;
}


Of course, the output produced by this version is exactly the same as the
output produced by the earlier version:

ted@flash Programs 7:35pm >class_circle_inline
Circle mick has area 12.5664
Circle mick has circumference 12.5664
Circle keith has area 78.5398
Circle keith has circumference 31.4159


3) IT IS AN ERROR TO ATTEMPT TO DIRECTLY ACCESS THE PRIVATE 
   DATA OF A  CLASS.  Suppose in a main program we try to
   read the value of mick's radius:

For example, with the same class definition as above (either the
inline one or the first one), if we write a main program such as:

// let's use the class definition and the definitions of the three methods
// in a main program
// and we try to read mick's radius directly..

int main()
{

// create two Circle "objects"

Circle mick, keith;

mick.SetRadius(2.00) ; // set the Radius of circle mick to 2.00
cout << "Circle mick has radius " << mick.radius<< endl;
return 0;

}


When we compile this program , the following errors are reported:

ted@flash Programs 7:38pm >g++ -o circle_class_read_private circle_class_read_private.C
circle_class_read_private.C: In function `int main()':
circle_class_read_private.C:21: `float Circle::radius' is private
circle_class_read_private.C:68: within this context




USING HEADER FILES FOR CLASS DEFINITIONS
----------------------------------------

Just as we used header files to include function prototypes, we may
make use of header files to include class definitions. The following
example is our class Circle example redone using header files.  We
also make use of the #ifndef compiler directive to prevent multiple
redefinitions of identifiers in cases where a header file is included
more than one time:


We can put the definition of the class Circle in a file called
circle.h (any file name may be used... it is good to follow
the class_name.h  convention):


all this goes into the file called circle.h

-------------------------------------------------------------

#ifndef circle_h
#define circle_h

const float pi = 3.1415926;

// define a class called Circle, class is a C++ keyword

class Circle
{
float radius;   // everything in a class is private by default

public:         // we want the following methods to be public, so we
                // make them public by using the public keyword followed
                // by a colon :
Circle();   // default constructor
Circle(float r); // overloaded constructor
float Area();
float Circumference();
float GetRadius();
};  // NOTE: THIS LAST SEMICOLON IS REQUIRED !!!!

#endif

-------------------------------------------------------------------



Next, we can have another file containing the implementation of the methods
found in the class . This file can be called circle_methods.C :


file: circle_methods.C
------------------------------------------------------------------

#include "circle.h"   // this will read the file circle.h which contains the class 
                      // declaration
#include <iostream>

using namespace std;






float Circle::Area()
{
 return ( pi * radius * radius) ;
}

float Circle::Circumference()
{
 return ( 2 * pi * radius) ;
}

float  Circle::GetRadius()
{
return radius;
}

// define the default constructor

Circle::Circle()
{
  cout << "Default constructor called... " << endl;
  cout << "Setting circle's radius to 1.00 " << endl;
  radius = 1.00 ;
}

// define the overloaded constructor

Circle::Circle(float r)
{
 cout << "Overloaded constructor invoked ... " << endl;
 radius = r;
}



------------------------------------------------------------------------


Next, the main program can be written in a third file. Let us
call it circle_main.C:


file: circle_main.C
--------------------------------------------------------------

#include "circle.h"
#include <iostream>

using namespace std;





int main()
{
 
// create two Circle "objects"

Circle mick, keith(456.89);

cout << "Circle mick has radius " << mick.GetRadius() << endl;
cout << "Circle keith has radius " <<  keith.GetRadius() << endl;

return 0;
}

----------------------------------------------------------------------



We can compile the above files using the command:

g++ -o circle_main circle_methods.C circle_main.C




LINKING YOUR PROGRAM WITH A PRE-COMPILED CLASS IMPLEMENTATION
-------------------------------------------------------------


The above example showed how we separated the class DEFINITION
from its IMPLEMENTATION into two separate files.  It is even
possible (and desirable in some cases) to further isolate the user
of the class from its implementation by providing only the precompiled
version of the class implementation (that is providing only the .o file
(object file) ).  All the user of a class needs to know is the interface
of the class: the class name, the name of its methods, etc. All this
information is provided in the class definition. The actual details of
how the methods operate are left to the implementor to decide. 

We can precompile our class_methods.C program into a binary object
file called class_methods.o using the following option to
the g++ compiler:

-c   Compile or assemble the source files, but do not  link.
          The  compiler output is an object file corresponding to
          each source file.


(this was generated from the man page for g++ with the command man g++)

ted@townshend Programs 9:01pm >g++ -c circle_methods.C


This will create a binary object file called circle_methods.o
Binary files are not human readable, try doing a more
on circle_methods.o :

ted@townshend Programs 9:02pm >more circle_methods.o
EL4(
.shstrtab.text.rodata.eh_frame.symtab.strtab.rela.text.rela.eh_frame.commentã¿Å Ç@ #Ç # "Çà
èã¿Å Ç@ # "Çèã¿Å "Çèã¿ ` @       @` @    @`ÒÒ$°Çèã¿ ò' H` @      @Ð HÐ$°Çè@IÚ@ÉÚDefault constructor called... Setting circle's radius to 1.00 ?Overloaded constru
-tor inveÿñ!t$480K\aXlh «½Ç8Õcircle_methods.Cgcc2_c
mpiled.pi__FRAME_BEGIN__Circumference__6Circleendl__FR7ostreamcout__6Circlef__ls__7ostreamPFR7ostream_
R7ostream_Q_qtodGetRadius__6Circle__ls__7ostreamPCc__6CircleArea__6Circle__throw^L      ^LD     H^L

^L     ^ °              ´       ^L¸^LÀ
        Ä
^LÈ     (Ì^L(Ðà         ä       ^Lè^Lð  Lô^LL 
        $
^L(     P,^LP0@         D       ^LH^L88Thpas: Sun WorkShop 6 99/08/18
GCC: (GNU) 2.95.3 20010315 (release)4V
                                      løp #+@Ý3 h^L><^LMÄC


This is what you will see... lots of garbage.

Next, we can link our circle_methods.o with our main program by doing:

ted@townshend Programs 9:04pm >g++ -o circle_main circle_methods.o circle_main.C


This command instructs the g++ compiler to compile the source code in file
circle_main.C and LINK it together with the precompiled binary file circle_methods.o
and create a single executable file called circle_main.  


When you compile and link a program which makes use of library routines such
as cin , cout, etc. the linker uses precompiled object files for these routines.
Some of these routines are found in the directory /usr/lib. For example, there is
a file called /usr/lib/libCrun.so.1  which contains various C runtime library utilities.
The .so file name extension is the so called "shared object" library extension name.
There is a very nice explanation of libraries and shared libraries in the textbook
"Deep C Secrets: Expert C Programming".  This is a wonderfully written book; I
read it over my summer vacation at the cottage during the rainy evenings...



CONSTRUCTORS
-------------

The above circle class contains a method called SetRadius which must
be manually invoked by the user to set the radius of a certain circle
object to a specific value.  This is burdensome and error-prone, a
user of the class may forget to do so.

C++ has a way of automatically initializing the data members of a class.
The method makes use of CONSTRUCTORS .  Constructors are special purpose
methods (which have the same name as the class), constrcutors are 
automatically called by the compiler when an object of the class is defined.

Constructors differ from ordinary functions and methods in that NO RETURN
TYPE (NOT EVEN A RETURN TYPE OF VOID) is specified in the definition of
a constructor.  

DEFAULT CONSTRUCTORS
--------------------

If a constructor takes no arguments, it is known as a default constructor.

OVERLOADED CONSTRUCTORS
----------------------

A class defintion may contain more than one definition of a constructor,
we may define different versions of the constructor function by 
OVERLOADING the constructor (that is multiple defintions which vary in their
argument list).


Circle class with a default and overloaded constructor:
-----------------------------------------------------

We will modify our circle class example to include a default constructor
(which will set the radius of a circle object to 1.00) and an overloaded
constructor (which will set the radius to some user specified value). We
will also include a new method called GetRadius, this method will return
the radius of the circle object:



// Author: Ted Obuchowicz
// April 23, 2002
// example program illustrating use of
// a simple Circle Class
// using constructors

const float pi = 3.1415926;


#include <iostream>
#include <string>

using namespace std;




// define a class called Circle, class is a C++ keyword

class Circle
{
float radius;   // everything in a class is private by default

public:         // we want the following methods to be public, so we
                // make them public by using the public keyword followed
                // by a colon :
Circle();   // default constructor
Circle(float r); // overloaded constructor
float Area();
float Circumference();
float GetRadius();
};


// we now define the methods of the class, we use the scope resolution
// operator to inform the compiler that the method belongs to the class
// called Circle

float Circle::Area()
{
 return ( pi * radius * radius) ;
}

float Circle::Circumference()
{
 return ( 2 * pi * radius) ;
}

float  Circle::GetRadius()
{
return radius;
}

// define the default constructor

Circle::Circle()
{
  cout << "Default constructor called... " << endl;
  cout << "Setting circle's radius to 1.00 " << endl;
  radius = 1.00 ;
}

// define the overloaded constructor

Circle::Circle(float r)
{
 cout << "Overloaded constructor invoked ... " << endl;
 radius = r;
}



// let's use the class definition and the definitions of the three methods
// in a main program

int main()
{
 
// create two Circle "objects"

Circle mick, keith(456.89);

cout << "Circle mick has radius " << mick.GetRadius() << endl;
cout << "Circle keith has radius " <<  keith.GetRadius() << endl;

return 0;
}



The output is:

ted@flash Programs 8:23pm >circle_class_with_constructors
Default constructor called... 
Setting circle's radius to 1.00 
Overloaded constructor invoked ... 
Circle mick has radius 1
Circle keith has radius 456.89


Operator Overloading
-------------------

C++ allows to overload built-in operators such as +, - , *, etc.
Let us overload the + operator such that it will "add" two circle
objects together.  For the purposes of our example, we will define
the addition of two circles to give a third circle  whose radius
is the sum of the two circles being added together.

// Author: Ted Obuchowicz
// April 23, 2002
// example program illustrating use of
// a simple Circle Class
// using constructors

const float pi = 3.1415926;


#include <iostream>
#include <string>

using namespace std;




// define a class called Circle, class is a C++ keyword

class Circle
{
float radius;   // everything in a class is private by default

public:         // we want the following methods to be public, so we
                // make them public by using the public keyword followed
                // by a colon :
Circle();   // default constructor
Circle(float r); // overloaded constructor
float Area();
float Circumference();
float GetRadius();
Circle operator+(Circle);
};


// we now define the methods of the class, we use the scope resolution
// operator to inform the compiler that the method belongs to the class
// called Circle

float Circle::Area()
{
 return ( pi * radius * radius) ;
}

float Circle::Circumference()
{
 return ( 2 * pi * radius) ;
}

float  Circle::GetRadius()
{
return radius;
}

// define the default constructor

Circle::Circle()
{
  cout << "Default constructor called... " << endl;
  cout << "Setting circle's radius to 1.00 " << endl;
  radius = 1.00 ;
}

// define the overloaded constructor

Circle::Circle(float r)
{
 cout << "Overloaded constructor invoked ... " << endl;
 radius = r;
}


Circle Circle::operator+(Circle a_circle)
{
 Circle temp ; // note default constructor will be called on temp
               // so the class better contain a definition of it
 
 temp.radius = radius + a_circle.radius;
 
 return temp;
}

// let's use the class definition and the definitions of the three methods
// in a main program

int main()
{
 
// create two Circle "objects"

Circle mick, keith(456.89);

// create a third circle

Circle ron;


cout << "Circle mick has radius " << mick.GetRadius() << endl;
cout << "Circle keith has radius " <<  keith.GetRadius() << endl;


// add mick and keith to get ron

ron = mick + keith ; // ron's radius should be 1.00 + 456.89

cout << "Circle ron has radius " << ron.GetRadius() << endl;

return 0;
}


The program output is:

ted@flash Programs DING! >circle_class_overload
Default constructor called... 
Setting circle's radius to 1.00 
Overloaded constructor invoked ... 
Default constructor called... 
Setting circle's radius to 1.00 
Circle mick has radius 1
Circle keith has radius 456.89
Default constructor called... 
Setting circle's radius to 1.00 
Circle ron has radius 457.89


NOTE:

The line

ron = mick + keith ;

can also be written as:

ron = mick.operator+(keith);


Written in this manner, it is clearer that we are actually invoking the
method called operator+ belonging to the circle mick and passing to this
method the circle keith as a parameter. The return value of the operator+
method is then assigned to the circle ron.

If we write it as ron = mick + keith, it is more apparent that we are
"adding" two circles together and assigning the result of the "addition"
to another circle.




DIFFERENCES BETWEEN A C++ STRUCT AND A C++ CLASS
------------------------------------------------

A C++ struct  is very similar to a C++ class.  In fact , the only
difference between C++ structs and classes is that in A STRUCT
EVERYTHING IS CONSIDERED PUBLIC (unless explicitly denoted as private)
BY DEFAULT AND IN A CLASS EVERYTHING IS CONSIDERED PRIVATE (unless
explicitly denoted as public by use of the public keyword).  Traditionally,
C++ programmers use the class construct when we want to encapsulate 
the data members togethers with the methods which operate on these members.
A struct is traditionally used only when there are data members (all public)
and no methods.  As always, one can abandon tradition and be a rebel. So,
let us be a bit rebellious and use a struct which has some methods in addition
to data members:

// Author: Ted Obuchowicz
//  Oct. 29, 2002
// file: fraction_struct_class.C



#include <iostream>
#include <string>

using namespace std;


struct fraction
{
 private: // in a struct everything is public unless explicitly 
          // made private

int numerator, denominator;

 public:

fraction() {  numerator = 1; denominator = 1; } ; // inline definition of default
                                                 // constructor

fraction(int top, int bottom ) { numerator = top; denominator = bottom; };

fraction  add(fraction x) 
{
 fraction temp;
 temp.numerator = numerator * x.denominator + x.numerator * denominator;
 temp.denominator = denominator * x.denominator;
 return temp;
};

void print_fraction()
{
 cout << numerator << " / " << denominator << endl;
}

};




int main()
{

fraction f1(2,3) ;
fraction f2(3,4) ;
fraction sum;
f1.print_fraction();
f2.print_fraction();
sum =  f1.add(f2);
sum.print_fraction();





return 0;
}


This example illustrates the INLINE method of defining the methods of the struct (or a class
as well) .  Note if we use the inline methos there is no need to use the scope resolution
operator together with the class name to give the "full name" as was done in the previous
circle class examples.  Note that we use a method called add (instead of overloading the
+ operator which we could have done if we so desired... this is left as an exercise
to the interested reader) which performs the addition of two fraction objects. No reduction
of the fraction to its "lowest common denominator" is performed. Again, the interested
reader is encouraged to do this as an exercise.




A COMPLEX NUMBER CLASS
---------------------

Here is a more representative example of a C++ class which
provides for addign two complex numbers together (by overloading
the + operator).  Recall that a complex number consists of a
real part and an imaginary part:

complex_number = real_part + i (imaginary_part)

where i is the square root of -1.

Complex numbers are used frequently in electrical engineering,
most notably in the study of electromagnetic theory. Complex
numbers are less frequently used in digital design ... but I digress..

Some comments on the program follow:

#include <iostream.h>

class Complex
{
 double real;
 double imag;

public:


Complex() {real = 0.0; imag = 0.0;}
Complex(double,double);
void write()
{
 cout << "Real = " << real << endl;
 cout << "Imaginary = " << imag << endl;
}

Complex operator+(const  Complex) const  ;

};

Complex::Complex(double r, double i)
{
 real = r;
 imag = i;
}

Complex  Complex::operator+(const  Complex c) const
{
 Complex temp; // note default constructor will be called on object temp
               // hence one must be provided or else 
 temp.real = real + c.real;
 temp.imag = imag + c.imag;
 return temp;

}

void main(void)
{
 Complex c1;
 Complex c2(7.7,4.4);
 Complex c3(1.1,2.2);
 c1 = c2 + c3;
 c1.write();
}


The output is:

ted@flash Programs 9:11pm >complex
Real = 8.8
Imaginary = 6.6


Comments:
--------

The const at the end of the declaration of the operator+

Complex  Complex::operator+(const  Complex c) const
                                              ^^^^^
   
                                            This const over here
simply guarantees that the object which is calling
(ie. object c2 in our sample program)  the method 
operator+ will NOT be changed by the method.  

The const in the :

Complex  Complex::operator+(const  Complex c) const
                            ^^^^
                          this const guarantees that the
operator+ method will not change the object which is passed to it
as a paramter (ie. the object c3 in the sample program).

If the method operator+ attempted to do something stupid like change
the values of either the calling object or the object received
as a parameter, it would be flagged as an error by the compiler.



DESTRUCTORS
-----------

Constructors are used to perform INITIALIZATION of data members.
This initialization may  involve some DYNAMIC MEMORY allocation
(for example assign some pointer an address returned by the new
operator).  Recall that when an object which dynamically allocates
some memory goes out of scope, the memory used for that object's data
members are returned to the operating system (and given back to the
heap space0, HOWEVER ANY DYNAMICALLY ALLOCATED MEMORY IS NOT RETURNED.
Thus, a memory leak is said to occur, and we have the possibility
of exhausting the heap space causing the program to crash.

This is illustrated in the program below:

#include <iostream.h>
#include <stdlib.h>

const long OneMillion = 1000000;

class Big
{
 char* string ; // a data member which is a pointer to a character..i.e a string

public:
 
 Big(); // default constructor which will do some DYNAMIC memory allocation

};

Big::Big()
{
 string = new char [OneMillion];  // get 1 000 000 char cells
 if (!string) 
   {
    cout << "OUT OF MEMORY!!!!" << endl;
    exit(1);
   }
}


void garbage(void)
{
 Big oops;

 // do some local processing of object oops

}

void main(void)
{
 
int i;

for(i = 0; i < 10000; i++)
 {
   cout << "I = " << i << endl;  // eventually we will get a segmentation fault
   garbage();
 }

}


We have a class which has a single character pointer has a data member.
There is also a default constructor defined which assigns the pointer
the starting address of a dynamically allocated array of 1 000 000 bytes.

There is a function called garbage which simply creates an object
of class Big (recall that the default constructor will be called 
whenever an object of class Big is declared).

In the main program, we have a for loop which calls the function garbage
10000 times.  Each time through the loop, the default constructor
will be called (allocating 1 000 000 bytes from the heap), eventually
we will exhaust all of the available memory and the program will crash.
On my workstation , this occured during loop iteration 229:

My output is:

I = 223
I = 224
I = 225
I = 226
I = 227
I = 228
I = 229
Abort


Solutions:
----------

There are two solutions. One is to have the user of the class,
explicitly give back any dynamically allocate memory with the delete
operator when that memory is no longer needed:

#include <iostream.h>
#include <stdlib.h>

const long OneMillion = 1000000;

class Big
{
 char* string ; // a data member which is a pointer to a character..i.e a string

public:
 
 Big(); // default constructor which will do some DYNAMIC memory allocation
void  clear(); // method  which will deallocate dynamic memory

};

Big::Big()
{
 string = new char [OneMillion];  // get 1 000 000 char cells
 if (!string) 
   {
    cout << "OUT OF MEMORY!!!!" << endl;
    exit(1);
   }
}

void  Big::clear()
{
 delete [] string;
}

void garbage(void)
{
 Big oops;

 // do some local processing of object oops

 // using this cumbersome method we must remember to invoke the method 
 // clear before returning from from the function garbage

 oops.clear();

 // this is not elegant as it relies upon the person implementing function garbage
 // to remember to delete any memory which was dynamically allocated by the
 // constructor function Big()

 // woudn't it be simpler if there were a way to have this done automatically somehow..?

}

void main(void)
{
 
int i;

for(i = 0; i < 10000; i++)
 {
   cout << "I = " << i << endl;
   garbage();
 }

}




Now, there is no problem.  However, this method is cumbersome. It
relies upon the user to call the method clear() explicitly.


There is a better way which uses DESTRUCTORS.

DESTRUCTOR functions are special functions inside of class objects,
they NEITHER TAKE ANY ARGUMENTS, NOR DO THEY RETURN AVALUE; DESTRUCTORS
ARE HIGHLY SPECIALIZED FUNCTIONSWHICH EXIST ONLY TO RELEASE ANY MEMORY
WHICH WAS DYNAMICALLY ALLOCATED BY A CONSTRUCTOR!!!!!!

A DESTRUCTOR's name is similar to the constructor in the respect that
each is the same as the class name. However, a destructor name is
preceded with the tilde (~) symbol.

Here is a program which makes use of the destructor ~Big() 

#include <iostream.h>
#include <stdlib.h>

const long OneMillion = 1000000;

class Big
{
 char* string ; // a data member which is a pointer to a character..i.e a string

public:
 
 Big(); // default constructor which will do some DYNAMIC memory allocation
 ~Big(); // destructor which will deallocate dynamic memory

};

Big::Big()
{
 string = new char [OneMillion];  // get 1 000 000 char cells
 if (!string) 
   {
    cout << "OUT OF MEMORY!!!!" << endl;
    exit(1);
   }
}

Big::~Big()
{
 delete [] string;
}

void garbage(void)
{
 Big oops;

 // do some local processing of object oops

}

void main(void)
{
 
int i;

for(i = 0; i < 10000; i++)
 {
   cout << "I = " << i << endl;
   garbage();
 }

}



This program complets its for loop with no memory problems:

I = 9988
I = 9989
I = 9990
I = 9991
I = 9992
I = 9993
I = 9994
I = 9995
I = 9996
I = 9997
I = 9998
I = 9999
ted@flash Programs 9:43pm >








