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:
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:
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:
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:
Next Section |
Previous Section |
Contents
More on Constructors
The best way to find out how constructors work is to try them out:
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:
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:
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:
Special care has to be taken when writing code for base classes that will be called from derived classes:
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:
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