Contents  1-5  6-11  12-16  17-21  22-27   28-33  34 - 38  39-46  Projects   MFC

   Contact
   Search
   C
   C++
   Visual Basic
   Java
   JavaScript
   DHTML
   Style Sheets
   About
   Active X
   TDC Binding
   PHP
   Perl and CGI
   Flash
   XML
   SQL
   Messages
   Chat
   MCSE
   Linux
   Cabling   
   ActionScript
   Downloads
   E-Cards   
 
    
    

  "As far as the laws of mathematics refer to reality, they are not certain, and as far as
they are certain, they do not refer to reality.
"
- Albert Einstein

Note: Updated!  See top of introduction page c1.html for using a C++ .Net compiler for these standard C++ tutorials.

Classes are more complete way of encapsulating objects than functions.  A class encapsulates both member data and methods.  Each instance of a class has its own separate methods and data members.  Classes more closely model the real world than functions alone.  A type is an object with a size, a state, and a set of abilities.  New types can be created and have the functionality and power of built in types.  A class become an object - a user-defined data type.  Classes, like objects in the real world, have a "has-a" relationship in regard to their data members, and an "is-a" relationship in regard to inheritance.  You make a new type by declaring a class.  Example:  

  • A cat is a mammal, a mammal is an animal, an animal is a living thing   This is an "is-a" relationship, so it would govern inheritance.

  • A cat has whiskers, mammals have eyes and are endothermic, and animals have mouths and reproduce.  This is a "has-a" relationship, so these would make data members of our classes rater than become part of its inheritance hierarchy.

Has-a Is-a Is-a
Mammal

Variables: hair, eyes, ears, mouth, nose.
Methods: Reproduce(), Eat(), Sleep()
Animal

Mammal

Human

Charles Germany
(instance of human)

Animal

Mammal

Cat

Felix
(instance of cat)

Key Concepts

Class - a collection of variables, often of different types, combined with a set of related functions.  Classes provide for encapsulation, everything is in one place so it is easier to manipulate, copy, and understand data.

Clients - other classes or functions that make use of your class.  Encapsulation enables them to use it without knowing or caring how it works. 

Member variables - (data members) The variables in a class.  Like wheels and an engine are part of a car.

Member functions - (methods) The functions in a class that manipulate the member variables.  Methods of a Car class might include the Start() and Brake() functions.  While a Cat class might have data members that represent age and weight, its methods might include the functions Sleep(),
Meow(), and ChaseMice().  Member functions determine what the objects of a class can do.

Declaring a class - use the class keyword followed by an opening brace and then list the data members and methods of that class.  End it iwth a closing bracket and a semicolon.  Example of a Cat class declaration:

class Cat
{
     unsigned int itsAge;            
//data member
     unsigned int itsWeight;         
//data member
     Meow();                         
//method
};

Declaring the class Cat doesn't allocate memory for the cat, it just tells the compiler what a Cat is and what data it contains  (itsAge and itsWeight) and what it can do (Meow()).  It also tells the compiler how big a Cat is and how much room to set aside for each Cat you create.  If itsAge is 2 bytes and itsWeight is 2 bytes then 4 bytes are set aside for a Cat.  Meow() takes up no room because no storage space is set aside for member functions (methods).  Defining an object of a new type is done just as you would define an integer variable.  Example:

unsigned int GrossWeight;  //define an unsigned integer
Cat Felix;               
//define a Cat

This defines a variable called GrossWeight whose type is an unsigned integer.  It also defines Felix, which is an object whose class (or type) is Cat.  This is referred to as creating an "instance" of Cat, or "instantiating" an object of the Cat class.  The class Cat is merely the idea of a cat.   The object Cat is a legitimate, real Cat.   So Felix is an object of the type Cat as GrossWeight is a variable of the type unsigned int.  An object is an individual instance of a class.

Once you define an actual Cat object (Felix), you use the dot operator (.) to access the members of the object. To Assign 50 to Felix's Weight member variable you'd write:     Felix.Weight = 50    In the same way to call the Meow() function you'd write;   Felix.Meow();  Remember to assign to instances of a class and not to the class itself - you don't assign values to types, you assign values to variables.  You'd never write:  int = 5;   The compiler would flag this as an error because you can't assign 5 to an integer.  Rather you must define an integer variable and assign 5 to that integer variable.  Example:

int x;
x = 5;

This says "Assign 5 to variable x which is of type int."  In the same way you couldn't write:  Cat.age=5; You must define a Cat object first and then assign 5 to a data member of that object.  Example:

Cat Felix;
Felix.age = 5;

Private vs. public - All members of a class, data and methods, are private by default.  Private members can only be accessed within methods of the class itself.  When these methods take private member data and make it accessible to objects outside the class instance, they are know as "accessor methods".  Public members can be accessed through any object of the class.  Example:

class Cat
{
unsigned int itsAge;
unsigned int itsWeight;
Meow();
};

The variables "itsAge" and "itsWeight" and the function "Meow()" are all private because the data members of a class are private by default.  So if you write:

Cat Boots;
Boots.itsAge=5;

You will get an error.  Just because "Boots" is an object of the class "Cats" doesn't mean you can access the parts of "Boots" that are private.  The way to access the class "Cat" so that you can access its members is to declare a section of "Cat" to be public like so:

class Cat
{
        public:
        unsigned int itsAge;
        unsigned int itsWeight;

        Meow();
};  
//notice that classes, unlike functions, end with a semicolon.

Now that "itsAge", "itsWeight" and "Meow()" are all public you can compile without any errors by writing:

Cat Boots;
Boots.itsAge=5;

Generally you should keep the member data of a class private.  Use public functions (Accessor Methods) to get and set your private member variables.  Once again, accessor methods are public functions that enable you to separate the details of how the data is stored from how it is used.  It enables you to change how the data is stored without having to rewrite functions that reuse the data. Use access control keywords to declare sections of a class as public or private.  Each keyword changes the access control from that point on to the end of the class or until the next access control keyword.  Class declarations end with a closing brace and a semicolon.

Note: ::
- Explicit calls to class methods when defining functions from outside the class include the class name followed by 2 colons "::" and the function's name.  Example:  Cat::GetAge().  The way to access a method of a class instance is with the dot operator.  Example:

//Define the class
class Monster {
         Monster(){}
         ~Monster(){}

         public:
         int getLife() {return life;}
         void setLife(int x) {life=x;}
         AttackTokyo();

         private:
         int strength;
         int life;
};

void main() {

//Create and instance of the class
Monster Godzilla;

//call the method for that instance using dot operator
Godzilla.AttackTokyo();

} 

Defining a class's functions and methods within its specification makes them inline.  In cases where this is inefficient or uncalled for, or where a class's methods or data may be static or friend functions, the declaration of a method is within a class and the definition (implementation) of that method is outside the class.  When so doing it is necessary to use scope resolution :: .  Example:

#include <iostream.h>  

class Cat
{
       public:
       int GetAge();
       void SetAge (int age);
       void Meow();

       private:
       int itsAge;
};
 

//Since we are defining the functions outside the class, we must use the class name and "::".

int Cat::GetAge()
{
     return itsAge;
}
 
void Cat::SetAge(int age)
{
       itsAge = age;
}

void Cat::Meow()
{
       cout << "Meow.\n";
}

//------------------------------------------------------------------------------------------------------------------- 

int
main()
{
    Cat Felix;
    Felix.SetAge(5);
    Felix.Meow();

    cout << "Felix is a cat who is " ;
    cout << Felix.GetAge() << " years old.\n";
    Felix.Meow();

    return 0;
}


Output:
Meow.
Felix is a cat who is 5 years old.
Meow.

Constructors and Destructors

Initialization - combines the definition of the variable with its initial assignment - it ensures that your variable is never without a meaningful value which you can always change later.

Constructor - creates and initializes objects of a class.  It is a special member function used to initialize the member data of a class.  It can take parameters as needed but it cannot have a return value, not even void.  It is a class method with the same name as the class itself.

Destructor
- clean up after objects and free any memory allocated to them.  It always has the name of a class with a tilda (~) placed before it.  They take no arguments and have no return value.  Example: ~Cat();

Default constructor - constructor with no parameters. If you write:    Cat Felix(5);

You invoke the constructor for "Cat" that takes on a parameter, the value of 5.  If, however you write:    Cat Felix;
you call the default constructor which takes no parameters. 

If you declare no constructors at all,  the compiler will create a default constructor for you.  This default constructor takes no action, it is as if you declared a constructor that took no parameters and whose body was empty.  The default constructor is any constructor that takes no parameters, whether you declare it or get it free from the compiler.  If you declare any kind of constructor, the compiler will not provide a default constructor for you.  You must declare a default constructor yourself in this case.
 

If you fail to declare a destructor the compiler will also provide you with one.  It will have an empty body and do nothing.  If you declare a constructor be sure to declare a destructor even if the destructor does nothing.  This is good etiquette.  The default destructor will work correctly, but declaring your own makes your code clearer.  Note that destructors never take parameters. Both constructors and destructors never return a value, not even void. The following example uses a construtor to initialize the "cat" object and sets its age to whatever age is provided, and calls a destructor:

#include <iostream.h>

class Cat  {

        public:

        Cat(int initialAge);        
//constructor
       
~Cat();                      //destructor

        int GetAge();                //accessor function
       
void SetAge(int age);        //accessor function
       
void Meow();

        private:
        int itsAge;                  
//member variable
};

//constructor of Cat defined outside of class (needs ::)
Cat::Cat(int initialAge)
{  itsAge = initialAge;  }

//destructor defined outside class, takes no action
Cat::~Cat()
{   }

//Accessor method defined outside class
int Cat::GetAge()
{ return itsAge; }

void Cat::SetAge(int age)
{ itsAge = age; }

void Cat::Meow()
{ cout << "Meow.\n"; }

//------------------------------------------------------------------------------------------------------------------- 

int
main() {

    Cat Felix(5);
   
Felix.Meow();

    cout << "Felix is a cat who is " ;
   
cout << Felix.GetAge() << " years old.\n";

    Felix.Meow();
   
Felix.SetAge(7);
 
   
cout << "Now Felix is " ;
   
cout << Felix.GetAge() << " years old.\n";

    return 0;
}

Output:
Meow.
Felix is a cat who is 5 years old.
Meow.
Now Felix is 7 years old.
Meow.

Constant member functions - if you declare a class member function to be "const", you are promising that the method will not change the value of any of the members of the class.  This is useful for insuring that functions that should only retrieve data, rather than change it, perform as expected.  Place the keyword "const" after the parenthesis but before the semicolon.  To declare a constant member function called "SomeFunction()" that takes no arguments and returns void you'd write:   void SomeFunction() const;

In the Cat class, "SetAge()" cannot be const because it changes the member variable "itsAge".  "GetAge()" can and should be const because it doesn't change the class at all - it simply returns the current value of the member variable "itsAge".  Therefore declaration of these functions should be:

void SetAge()(int anAge);
int GetAge() const;

Remember, if you declare a function to be "const" and then the implementation of that function changes the object by changing the values of any of its members, you will get an error.  Example: If you wrote GetAge() in such a way that it kept count of the number of times that Cat was asked its age, you would get an error because you would be changing the Cat object by calling this method.  It is good to declare as many methods const as possible so the compiler will reveal your errors before they become bugs in a finished program.

Interface vs. Implementation

Clients - parts of programs that create and use the objects of your class.
Interface - a "contract" with clients and the class declaration.  The contract tells what data your class has available and how your class will behave.

In the "Cat" class declaration you create a contract that every "Cat" will have a member variable "itsAge" that can be initialized in its constructor, assigned to by its "SetAge()" accessor function, and read by its "GetAge()" accessor.  You also promise that every "Cat" will know how to "Meow()".  If you make "GetAge()" a const function as you should, the contract also promises that "GetAge()"  won't change the "Cat" on which it is called.

Function implementation - the definition of a function that you declare for a class.  It has a header and a body.  It must be in a file the compiler can find (.cpp, etc.).  You need to add these .cpp files to your project or makefile.  Look for a command such as "Add Files to Project".  Every .cpp file must be added to the project so that it will be compiled and linked into the final executable. 

One should put class declarations in header files.  You are free to put the declaration in the source code file but it is not always good programming.  Most programmers put it into a header file ending with an .H or .HP or .HPP.  The declaration of the "Cat" class file would be in a file called "Cat.HPP".  You would incorporate the .HPP header file into the .CPP source code file by writing the following at the top of "Cat.cpp" :

#include "Cat.h"

Most of the time clients don't care about the implementation specifics.  Reading the header file tells them what they need to know and they can ignore the implementation files.

Declaration of a class - tells compiler what the class is, what data it holds and what functions it has.  It is called the class's "interface" because it tells the user how to interact with the class.  The "interface" is usually stored in a header ".hpp" file.

Function definition - tells the compiler how the function works.  It is called the "implementation" of the class method.  It is kept in a ".cpp" file. The implementation details are of concern only to the author of the class.  The "clients" of the class, the parts of the program that use the class, don't know or care how the functions are implemented.

Inline implementation - you can make class methods inline, the same as functions. Insert the "inline" before the return value.  Example:

inline int Cat::GetWeight()
{ return itsWeight; }

You can also put the function definition into the declaration of the class which automatically makes the function inline.  You can see this in the first Cat class inteface above.  Let's recreate the Cat class but put the declaration in "cat.hpp" and the implementation of the functions in "cat.cpp". Since the accessor functions and the "Meow()" function are in "cat.hpp", they will become automatically inline:

Contents of "cat.hpp":

#include <iostream.h>

class Cat
{
public:
Cat (int initialAge);
~Cat();

int GetAge() { return itsAge;}             //automatically inline!
void SetAge (int age) { itsAge = age;}     //automatically inline!

void Meow() { cout << "Meow.\n";}          //automatically inline!

private:
int itsAge;
};

  Contents of "cat.cpp":

#include "cat.hpp"               //include header file

Cat::Cat(int initialAge)         //constructor defined outside class
{  itsAge = initialAge;  }

Cat::~Cat()                      //destructor defined outside class          
{  }  

//------------------------------------------------------------------------------------------------------------------- 

int main() {

    Cat Felix(5);
   
Felix.Meow();

   
cout << "Felix is a cat who is " ;
   
cout << Felix.GetAge() << " years old. \n";
   
   
Felix.Meow();
   
Felix.SetAge(7);

    cout << "Now Felix is " ;
   
cout << Felix.getAge() << " years old. \n";

    return 0;
}

Output:
Meow.
Felix is a cat who is 5 years old.
Meow.
Now Felix is 7 years old.

Classes With Other Classes As Member Data

It is not uncommon to build up a complex class by declaring simpler classes and including them in the declaration of the more complex class.   In this way, things fit together like, dare we say, LEGOS?  :)  Example:   You declare a Wheel class, a Motor class, and a Transmission class and combine them into the Car class.  This represents a "has-a" relationship, which although this is used to refer to data members, it may also refer to other classes if they themselves make up a class's data members.  Another example would be geometrical shapes.

A Square is composed of lines.  A line is defined by 2 points.  A point is defined by an x and y coordinate.  The Square is composed of 4 lines connecting 4 points, each line contains 2 of those points, and each point has an x and a y coordinate.  A "Point" class is declared to hold the x,y coordinates of each point.  It then becomes part of a Square class, thus an instance of one class becomes the data member of another class in the "Has-a" relationship.   A wheel within a wheel ? Curioser and curioser said Alice . . . Down the rabbit hole we go!   Example: 

Contents of "rect.hpp":

#include <iostream.h>

class Point  {

        public:
       
void SetX(int x) { itsX = x; }
       
void SetY(int y) { itsY = y; }
       
int GetX()const { return itsX;}
       
int GetY()const { return itsY;}

        private:
       
int itsX;
        int itsY;

}; 
// end of Point class declaration



class Square {

        
public:
        
Square (int top, int left, int bottom, int right);
        
~Square () {}

         int GetTop() const { return itsTop; }
        
int GetLeft() const { return itsLeft; }
        
int GetBottom() const { return itsBottom; }
        
int GetRight() const { return itsRight; }
      
        
//The accessor methods below return an object of type "Point", declared in the class above
        
Point GetUpperLeft() const { return itsUpperLeft; }
        
Point GetLowerLeft() const { return itsLowerLeft; }
        
Point GetUpperRight() const { return itsUpperRight; }
        
Point GetLowerRight() const { return itsLowerRight; }

        
//The accessor methods below take an object of type "Point", declared in the class above
       
 void SetUpperLeft(Point Location) {itsUpperLeft = Location;}
        
void SetLowerLeft(Point Location) {itsLowerLeft = Location;}
        
void SetUpperRight(Point Location) {itsUpperRight = Location;}
        
void SetLowerRight(Point Location) {itsLowerRight = Location;}

         void SetTop(int top) { itsTop = top; }
        
void SetLeft (int left) { itsLeft = left; }
        
void SetBottom (int bottom) { itsBottom = bottom; }
        
void SetRight (int right) { itsRight = right; }

         int GetArea();

         private:
        
//Create instances of the Point class as the private member data of this class
        
Point itsUpperLeft;
        
Point itsUpperRight;
        
Point itsLowerLeft;
        
Point itsLowerRight; 

         int itsTop;
        
int itsLeft;
        
int itsBottom;
        
int itsRight;

};   //end class

Contents of "rect.cpp":    

#include "rect.hpp"

//Define Square constructor outside class using ::
Square::Square(int top, int left, int bottom, int right)  {

                 itsTop = top;
                
itsLeft = left;
                
itsBottom = bottom;
                
itsRight = right;    

                 itsUpperLeft.SetX(left);
                
itsUpperLeft.SetY(top);
                
itsUpperRight.SetX(right);
                
itsUpperRight.SetY(top);

                 itsLowerLeft.SetX(left);
                
itsLowerLeft.SetY(bottom);
                
itsLowerRight.SetX(right);
                
itsLowerRight.SetY(bottom);
}  

//Define(Implement) Accessor methos outside class
int
Square::GetArea() {

                     int Width = itsRight - itsLeft;
                    
int Height = itsTop - itsBottom;

                     return (Width * Height);
}


int main()  {

     Square MySquare(200, 50, 90, 100);

     int Area = MySquare.GetArea();
    
cout << "Area: " << Area << "\n";

    
cout << "Upper Left X Coordinate: "
        
 << MySquare.GetUpperLeft().GetX();

     return 0;

} // end main

Output:
Area: 3000
Upper Left X Coordinate: 20

Getting the upper left corner of the Square requires that you access the "UpperLeft" point and ask that point for its "x" value.  Since "GetUpperLeft" is a method of "Square", it can directly access the private data of "Square", including "itsUpperLeft".  Because "itsUpperLeft" is a "Point", and "Point"'s "itsX" value is private, the function "GetUpperLeft()" cannot directly access this data. It MUST use the public accessor function "GetX()" to obtain the value.    

A client of "Square" could create a "Square" object and get its area without ever looking at the implementation of "GetArea()".  What's this?  Data Hiding!  You always knew we'd see that term again.  Just by looking at the header file which contains the declaration of the "Square" class, the programmer knows that "GetArea()" returns an int.  How "GetArea()" does its magic is not of concern to the user of the class, "Square".  The author of "Square" could change "GetArea()" without affecting the programs that use the "Square" class.   Let's look at the Monster class:

Contents of Monster.hpp:

#include <iostream.h>

class Monster {
public:
             
	Monster(int MonStrength = 10)  {
	       Strength = MonStrength;
	       cout << "You hear a monstrous, chilling, blood curdling "
                    << "sound in the distance.\n";
                }
	~Monster() { cout << "A monster has been destroyed!\n"; }

        //Accessor Methods - Needed to Access Private Data Members
	int getStrength() { return Strength; }
	void setStrength(int MonsStrength) { Strength = MonsStrength; }
	

        //OtherMethods
        void DestroyTokyo() { cout << "Ahhhh! Godzilla!"; }


        void Talk() {

	     int SayWhat;
             cout << "O.k. tough guy, pick a number (1-4)";
	     cin >> SayWhat;
	     cout << "\nThe monster looks at you and says, \n\""; 
	     switch(SayWhat) {
                                   
                    case 1 : cout << "C. Germany watches too many B movies.";
		             break;
                    case 2 : cout << "It\'s like Legos!  LEGOS, baby!";
		             break;
	            case 3 : cout << "Unfortunately, I have had a very bad day, and\n";
	                     cout << "you happen to be the first creature I\'ve met\n";
	                     cout << "that I can take it out on...\n";
		             break;
	            case 4 : cout << "How do you taste?  I don\'t think I\'ve eaten"
		                  << " your kind before...";
		             break;
	            default : cout << "Uh oh, tastes like chicken..."; 
             }  //close switch
	        
             cout << "\".\n";

	} //close talk function


private:
	int Strength;

}; //closes class specification

Contents of Monster.cpp:

#include  "Monster.h"

void main() {

       Monster Godzilla;           
//no argument passed in so default parameter will be used

       Godzilla.Talk();
       Godzilla.setStrength(100);
       Godzilla.DestroyTokyo();

  

       Monster Mothra(50);        
//passes in argument to constructor
       Mothra.Talk();

}
//close main()

copy constructor - Enables you to copy one object's data members to another using the assignment operator.  In other words, the expression Monster1 = Monster2; would copy the value of all of Monster2's data members to Monster1's data members.  This is accomplished using a reference to the object itself, that is to say by making the "rhs" or "right hand side" object the argument.

Summary:

We have discussed creating classes, constant member functions, and the difference between a class's interface (specification and declaration) and the implementation of a class's methods (either within the class or outside of it).  It is considered good programming practice by some to isolate the interface (declaration) of the class in a header(.hpp) file.   Then, the implementation (definition) of the class methods are written in a ".cpp" file.  

That being said, many times the interface and implementation will be combined for reasons of simplicity and convenience.  In small programs, where defining class methods inline does not make much of a difference in performance, this method may actually produce code that is easier to follow and maintain because it is encapsulated and contained neatly within the class specification, rather than spread and splattered piece-meal all over multiple source and header files.


©2004 C. Germany