|How I Learned to Stop Worrying and Make Everything virtual|
There is one small twist to overriding methods in C++ and it has to do with the keyword virtual.
Only methods that are declared as virtual in the superclass can be overridden properly by
subclasses. The keyword goes at the beginning of a method declaration as shown in the modifi ed
version of Super that follows:
virtual void someMethod();
The virtual keyword has a few subtleties and is often cited as a poorly designed part of the
language. A good rule of thumb is to just make all of your methods virtual. That way, you won’t
have to worry about whether or not overriding the method will work. The only drawback is a very
tiny performance hit. The subtleties of the virtual keyword are covered toward the end of this
chapter, and performance is discussed further in Chapter 24.
Even though it is unlikely that the Sub class will be extended, it is a good idea to make its methods
virtual as well, just in case.
class Sub : public Super
virtual void someOtherMethod();
|Even with the preceding measures and the best design principles, the C++ language is fundamentally|
unfriendly to the principle of abstraction. The syntax requires you to combine your public interfaces and private (or protected) data members and methods together in one class definition,
thereby exposing some of the internal implementation details of the class to its clients. The
downside of this is that if you have to add new non-public methods or data members to your class,
all the clients of the class have to be recompiled. This can become a burden in bigger projects.
The good news is that you can make your interfaces a lot cleaner and hide all implementation details,
resulting in stable interfaces. The bad news is that it takes a bit of hacking. The basic principle is to
define two classes for every class you want to write: the interface class and the implementation class.
The implementation class is identical to the class you would have written if you were not taking
this approach. The interface class presents public methods identical to those of the implementation
class, but it only has one data member: a pointer to an implementation class object. The interface
class method implementations simply call the equivalent methods on the implementation class object.
The result of this is that no matter how the implementation changes, it has no impact on the public
interface class. This reduces the need for recompilation. None of the clients that use the interface
class need to be recompiled if the implementation (and only the implementation) changes.
To use this approach with the Spreadsheet class, simply rename the old Spreadsheet class
to SpreadsheetImpl. Here is the new SpreadsheetImpl class (which is identical to the old
Spreadsheet class, but with a different name):