Previous Lecture | Next Lecture | Exercises | Top Level

Inheritence, Virtual Functions, Abstract Classes

Contents


Next Section | Contents

Inheritance

Let's write a little traffic simulation program. We will have:

Cars
They move around carrying a small number of passengers. You can usually steer them, they can accelerate and slow down.
Trains
They move around pulling waggons. You can't really steer them, but you can decide if you go forwards, backwards and how fast you go.
Airplanes
They move in three dimensions. Not only can you decide on a heading, but you can also go up and down.
Let's try to write down these 3 classes in C++:

vehicle.C

You will note that the class definitions share common elements. In C++, we can factor out the common elements and create a base class, from which the specialized classes may be derived. This technique is called inheritance, and this is what it looks like:

Vehicle.C

The public keyword ensures that we can access all elements of the base class when using the derived class. The two code fragments above behave exactly the same way when using the three specialized classes, but inheritance gives us the following advantages:


Next Section | Previous Section

Virtual Functions

Let's think about implementing the move() function. We can't really do it here, since it will probably be very complex, but let's just try to think of what we would like to have.

It certainly makes sense to talk about moving a vehicle. After all, that's what vehicles are for. This is why we defined move() in that base class.

Let's make a naive implementation of the move() function:

Vehicle::move(Position new_position)
{
  heading(new_position);
  accelerate(max_speed);
  cruise(new_position - current_position);
  accelerate(-max_speed);
}
The point is that the base class doesn't know which specialized class is going to use the code above.

If we declare the functions used above as virtual, a pointer will be allocated and initialized to point to the right function when the class is built.

This allows us to code the general form of the algorithm in the base class and leave the testy little details open, to be defined in the specialized class.

This is how the vehicle class looks with virtual functions:

virtual.h


Next Section | Previous Section

Abstract Classes

In the real world, we never ride vehicles. We always use the specialized end-products like cars, trains or airplanes. Therefore, it rarely makes sense to implement virtual functions at the base class level.

Since the virtual function is in fact a pointer to a function, it can be initialized. Initializing it to 0 indicates that there is no implementation of that member function in that class. The implementation is left up to the classes inheriting our base class.

I virtual function initialized to 0 is called a pure virtual function. A class containing pure virtual functions is called abstract base class, and it is illegal to define a variable (an instance) of that class.

This is how it looks like:

abstract.h


Next Section | Previous Section | Contents

More on Constructors

The best way to find out how constructors work is to try them out:

constructor.C

Running this program shows that constructors are called in order of inheritance. The Vehicle constructor is called first, the Car constructor comes next.

If we want to initialize our data, we have a problem:

motivate-init.C

Even though the proper constructor for Car was called, it still used the basic constructor for Vehicle. We have to use the following syntax to call the proper constructor:

init.C

Note that it wouldn't make sense to call Vehicle's constructor from within the body of Car's constructor, as this would make us call two constructors for the same class.


Previous Section | Contents

Destructors

Destructors are functions that are called whenever the object is de-allocated (i.e. destroyed). Destructors should free resources used by the object.

Destructors are called in the opposite order in which constructors are called:

destructor.C

Special care has to be taken when writing code for base classes that will be called from derived classes:

motivate-virtual-des.C

Note that in the program above, only Vehicle's destructor is called, even though we are deleting an object of type Car. The fix is to use virtual destructors like this:

virtual-des.C


Previous Idiom | Next Idiom | About Idioms
If a class contains virtual functions and needs a destructor, make sure that the destructor is also declared virtual.

When in doubt, use virtual functions


Previous Lecture | Next Lecture | Exercises | Contents
Christian Goetze