First | Next | Previous | Last | Glossary | About |
We are close to the end of the chalk and talk about classes and need to look at some topics which can be quite puzzling, they certainly puzzled me. After studying these topics it will be time to put in some hard practice.
Somewhere in ages past I wrote that:
Polymorphism is a very useful feature of classes by which a base class enables subclasses to each carry out an apparently similar method in different ways.
Now it's time to explain that in a more practical sense. I'll start with a recap of the building project which we've been using as a way of learning about inheritance.
Figure 1 shows us the relationship between the classes in the building project. You can see that both the commercial class and the domestic class are derived from the base class building.
The figure also reminds us that each of the three classes has a member function called inspect(). When you used these member functions there was no confusion because you declared an instance of the particular class:
domestic home(PITCHED, CLAYBRICK, 1, 8, 3, 1); home.inspect();
Since home is an instance of domestic then calling the inspect() function specifically referred to the domestic.inspect() function. There was no confusion about whether the inherited inspect() (from building) should be called or domestic's own inspect.
What does this have to do with polymorphism?
A polymorph is an entity that can take many shapes. You might have heard the term used in popular science-fiction shows, it's also a characteristic found in many, but not all, polyticians.
commercial skyscraper(FLAT, CONCRETE, 120, OFFICE); domestic home(PITCHED, CLAYBRICK, 1, 8, 3, 1); building * b; home.inspect(); skyscraper.inspect(); b = &home; b->inspect(); b = &skyscraper; b->inspect();
The use of polymorphism in computer programming leads to some very powerful constructions. We can declare a pointer to a base class then assign the address of any of it's derived classes to that pointer. You can see that in the example shown here.
b is a pointer to the base type building. We can assign the addresses of the objects home and skyscraper to b and then use the member dereference operator -> to call a member function. But there is a problem.
class building { public: building(); building(rooftype, constructiontype, int); void inspect(); protected: ... };
If we do this with our original building class we will strike a problem because the inspect() function will be the inspect() function of the base class.
In this case we won't get the full inspection details. For instance even though we are using the address of the home object we are actually executing the member function building.inspect(), not the domestic.inspect(). We definitely don't want this.
class building { public: building(); building(rooftype, constructiontype, int); virtual void inspect(); protected: ... };
The solution is to use a virtual function. We declare the base member function to be virtual and this takes care of the problem of finding the appropriate member function. In a way virtual forces the function call to examine the address of the actual object and find the correct member function.
All that is required is to add the keyword virtual to the base member function declaration.
A major advantage of virtual functions is that we can make use of "late-binding". In a programming sense binding refers to the process of associating, for example, functions with programs. If we link a library with a program at compile time then the functions the program uses are bound early. This early-binding or static-binding is probably the most common but you are no doubt familiar with late-binding even though you may not be aware of it. Programs that use DLL's (Dynamic Link Libraries) use late-binding. The functions and data elements in the DLL are not bound to the program until run-time. I think Linux' shared libraries are the same thing but I'm not 100% certain. I'll find out in due course, in the fullness of time, when the moment is ripe, at the appropriate juncture etc.
1.1 The building project is available here as a ZIP file. It contains the source files and a Makefile. Download it and build it to make sure it runs.
commercial skyscraper(FLAT, CONCRETE, 120, OFFICE); domestic home(PITCHED, CLAYBRICK, 1, 8, 3, 1); building * b; home.inspect(); skyscraper.inspect(); b = &home; b->inspect(); b = &skyscraper; b->inspect();
1.2 Now make the changes as shown here and confirm that we do strike a problem.
1.3 Now make base inspect() a virtual function and confirm that the problem has been solved.
1.4 Think of some other property that all buildings share. Add this property to the base class and write member function that get and set the property. In which section of the class should you store the property?
First | Next | Previous | Last | Glossary | About |
Copyright © 1999 - 2001
David Beech