Please send all questions & assignments to:
dsolarek@utnet.utoledo.edu
 
CSET 3150
Advanced Programming

Using C++ Classes

In this lesson we will look at the use of C++ classes. Classes are the biggest difference between C and C++. In fact, one of the earliest names for C++ was "C with Classes."

Classes and Objects

A class is a definition of an object. It is a type just like int. A class resembles a struct with one major difference: all struct members are public by default. All class members are private by default.

Remember : A class is a user-defined type, and an instance of this type is just an object. When you instantiate an object you assign an identifier (variable name) to the object.

Before we can use an object, it must be created. The simplest definition of a class is of the form shown below:

 class name 
 {
   // list of members
 }
where the members can be data items (data members) or fumctions (function members, member functions or methods).

This example class below models a simple book. Using OOP lets you abstract the problem and think about it and not just arbitrary variables.

// example one
#include <iostream>
#include <stdio.h>

using namespace std;

class Book
{
  int PageCount;
  int CurrentPage; 
  public:
  Book( int Numpages); // Constructor
  ~Book(){}; // Destructor
  void SetPage( int PageNumber);
  int GetCurrentPage( void );
}; 

Book::Book(int NumPages) 
{
  PageCount = NumPages;
}

void Book::SetPage( int PageNumber) 
{
  CurrentPage=PageNumber;
}

int Book::GetCurrentPage(void) 
{
  return CurrentPage;
}

int main() 
{
  Book ABook(128) ;
  ABook.SetPage( 56 ) ;
  cout << "Current Page " << ABook.GetCurrentPage() << endl;
  return 0;
}

All of the code from class Book down to the int Book::GetCurrentPage(void) function is part of the class. The main() function is there to make this a complete program - one that you can compile and run.

Understanding the Book Class

In the main() function a variable ABook of type Book is created with the value 128. As soon as execution reaches this point, the object ABook is constructed. On the next line the method (function member) ABook.SetPage() is called and the value 56 assigned to the object variable (data member) ABook.CurrentPage. Then cout outputs this value by calling the Abook.GetCurrentPage() method.

When execution reaches the return 0; the ABook object is no longer needed by the application. The compiler generates a call to the destructor.

Declaring Classes

Everything between class Book and the }; is the class definition. This class has two private members, both of type int. These are private because the default access to class members is private.

The public: directive tells the compiler that access from here on is public. Without this, it would still be private and prevent the three lines in the main() function from accessing Abook members. Try commenting the public: line out and recompiling to see the ensuing compile errors.

This line below declares a constructor. This is the function called when the object is first created.

  Book( int Numpages) ; // Constructor 

It is called from the line

  Book ABook(128); 

This creates an object called ABook of type Book and calls the Book() function with the parameter 128.

More about the Book Class

In C++, the constructor always has the same name as the class. The constructor is called when the object is created and is where you should put your code to initialize the object.

In Book the next line after the constructor the destructor. This has the same name as the constructor but with a ~ (tilde) in front of it. During the destruction of an object, the destructor is called to tidy up the object, and ensure that resources such as memory and file handles used by the object are released.

Remember : A class abc has a constructor function abc() and destructor function ~abc(). Even if you do not explicitly declare them the compiler will automatically add them.

The destructor is always called when the object is terminated. In this example the object is implicitly destroyed when it goes out of scope. To see this, modify the destructor declaration to this.

  ~Book(){ std::cout << "Destructor called\n";} ; // Destructor

This is an inline function with code in the declaration. Another way to inline is adding the word inline.

  inline ~Book() ; // Destructor
and add the destructor as a function like this.
  inline Book::~Book (void) 
  { 
    std::cout << "Destructor called\n";
  }

Inline functions are hints to the compiler to generate more efficient code. They should only be used for small functions, but if used in appropriate places such as inside loops can make a considerable difference in performance.

Writing Class Methods

Best practice for objects is to make all data private and access it through functions known as accessor functions. SetPage() and GetCurrentPage() are the two functions used to access the object variable CurrentPage. Change the class declaration to struct and recompile. It still compiles and runs correctly. Now the two variables PageCount and CurrentPage are publicly accessible. Add this line after the Book ABook(128); and it will compile.

  ABook.PageCount = 9;

If you change struct back to class and recompile, that new line will no longer compile as PageCount is now private again.

The :: Notation

After the body of Book Class declaration there are the four definitions of the member functions. Each is defined with the Book:: prefix to identify it as belonging to that class. The double colon notation (::) is called the scope identifier. It identifies the function as being part of the class. This is obvious in the class declaration but not outside it.

If you have declared a member function in a class you must provide the body of the function in this way. If you wanted the Book class to be used by other files then you might move the declaration of book into a separate header file perhaps called book.h. Any other file could then include it with

  #include "book.h" 

int main() 
{
  Book ABook(128) ;
  ABook.SetPage( 56 ) ;
  std::cout << "Current Page " << ABook.GetCurrentPage() << std::endl;
  return 0;
}

Inheritance and Polymorphism

This example will demonstrate inheritance. This is a two class application with one class derived from another.

#include <iostream>
#include <stdio.h>

class Point
{
  int x,y;
  public:
  Point(int atx, int aty ); // Constructor
  inline virtual ~Point(); // Destructor
  virtual void Draw();
}; 

class Circle : public Point 
{
  int radius;
  public:
  Circle(int atx, int aty, int theRadius);
  inline virtual ~Circle();
  virtual void Draw();
};


Point ::Point(int atx,int aty) 
{
  x = atx;
  y = aty;
}

inline Point::~Point (void) 
{ 
  std::cout << "Point Destructor called\n";
}

void Point::Draw(void) 
{
  std::cout << "Point::Draw point at " << x << " " << y << std::endl;
}


Circle::Circle(int atx, int aty, int theRadius) : Point(atx,aty) 
{
  radius = theRadius;
}

inline Circle::~Circle() 
{
  std::cout << "Circle Destructor called" << std::endl;
}

void Circle::Draw(void) 
{
  Point::Draw();
  std::cout << "circle::Draw point " << " Radius "<< radius << std::endl;
}

int main() 
{
  Circle ACircle(10,10,5);
  ACircle.Draw();
  return 0;
}

The example has two classes Point and Circle, modelling a point and a circle. A Point has x and y coordinates. The Circle class is derived from the Point class and adds a radius. Both classes include a Draw() member function. To keep this example short the output is just text.

Inheritance

The class Circle is derived from the Point class. This is done in this line:
  class Circle : Point

Because it is derived from a base class (Point), Circle inherits all the class members.

  Point(int atx,int aty ); // Constructor
  inline virtual ~Point(); // Destructor
  virtual void Draw();
  Circle(int atx,int aty,int theRadius);
  inline virtual ~Circle();
  virtual void Draw();
Think of the Circle class as the Point class with an extra member (radius). It inherits the base class Member functions and private variables x and y.

It cannot assign or use these except implicitly because they are private, so it has to do it through the Circle constructor's Initialiazer list.

This is something you should accept for now, we'll come back to initializer lists later.

In the Circle Constructor, before theRadius is assigned to radius, the Point part of Circle is constructed through a call to Point's constructor in the initializer list. This list is everything between the : and the { below.

  Circle::Circle(int atx,int aty,int theRadius) : 
  Point(atx,aty) 

Incidentally, constructor type initialization can be used for all built-in types.

  int a1(10);
  int a2=10;
Both do the same.

What is Polymorphism?

Polymorphism is a generic term that means 'many shapes'. In C++ the simplest form of Polymorphism is overloading of functions, for instance several functions called SortArray( arraytype ) where sortarray might be an array of ints, or doubles.

We're only interested here though in the OOP form of polymorphism. This is done by making a function (e.g. Draw() ) virtual in the base class Point and then overriding it in the derived class Circle.

Although the function Draw() is virtual in the derived class Circle, this isn't actually needed - it's a reminder to me that this it is virtual. If the function in a derived class matches a virtual function in the base class on name and parameter types, it is automatically virtual.

Drawing a point and drawing a circle are too very different operations with only the coordinates of the point and circle in common. So it's important that the correct Draw() is called. How the compiler manages to generate code that gets the right virtual function will be covered in a future tutorial.

C++ Constructors

Constructors

A constructor is a function that initilizes the data members of an object. A constructor only knows how to build an object of its own class.

Constructors aren't automatically inherited between base and derived classes. If you don't supply one in the derived class, a default will be provided but this may not do what you want.

Constructors can include parameters or not. If no constructor is supplied then a default constructor is created by the compiler without any parameters.

Tidying Up - C++ Destructors

A destructor is a class member function that has the same name as the constructor (and the class ) but with a ~ (tilde) in front.

  ~Circle();

When an object goes out of scope or more rarely is explicitly destroyed, its destructor is called. For instance if the object has dynamic variables, such as pointers then those need to be freed and the destructor is the appropriate place.

Unlike constructors, destructors can and should be made virtual if you have derived classes.

In the Point and Circle classes example the destructor is not needed as there is no clean up work to be done, it just serves as an example. Had there been dynamic member variables (e.g. pointer) then those would have required freeing to prevent memory leaks.

Also when the derived class adds members that require tidying up, virtual destructors are needed. When virtual, the most derived classe destructor is called first, then its immediate ancestor's destructor is called, and so on up to the base class.

In our example,

  ~Circle();
then
  ~Point();
The base class destructor is called last.




There have been visitors to date.

Added to the Web:
September 3, 2007.

Web page design by Dan Solarek.

http://cset.sp.utoledo.edu/cset3150/