![]() |
|||||||||
6.4 Replacing Inherited Methods |
|||||||||
|
A derived class is capable of redefining, by overriding, an inherited method, replacing the inherited method with one that is specifically designed for the derived class. Because they are suited to its behavior, the derived class may want to inherit many of the base class's methods. What is considered in this section is how to selectively replace an inappropriate base class method with one appropriate to the derived class. The invocation of a method that has been replaced will result in the replacing method being invoked rather than the replaced method. The replacement is transparent to the code performing the invocation because the replacing method has the same signature (the same name and same arguments) as the method it replaces . The substitution achieved by replacement is often referred to as the receiving object "doing the right thing". The receiving object is aware of its internal structure and, in response to an invocation, selects an appropriate method for execution. The invoker of the method is, and is best, unaware of how the receiving object determines which of its methods to execute. Of course, the receiving object is restricted to executing a method that matches the signature (name and ordered list of argument types) of the invocation. An ExampleThe RestartCounter class is an example of a class in which method replacement is needed. A RestartCounter object is just like a Number object, except that the Reset method always sets the internal value back to an initial value that is given when the RestartCounter is constructed. The RestartCounter does not use the TextBox to obtain the value to which it is reset. Below is the inheritance diagram for the RestartCounter class. This diagram implies that a RestartCounter object has the following methods:
The Reset method defined in DisplayableNumber has been overridden
by the Reset method defined in RestartCounter.
Notice the difference between overloading and overriding. Overloaded methods have the same name but different argument lists (signatures). Overridden methods have the same name and the same arguments (signatures). In the JumpCounter class the Next method is overloaded because the two methods JumpCounter::Next(int) and Number::Next() have different signatures. Thus, a JumpCounter object has both of the Next methods. However, a RestartCounter object has only one Reset method - the one defined in the RestartCounter class (RestartCounter::Reset()). The definition of the RestartCounter class and its code is
class RestartCounter : public Number {
private:
int original;
public:
RestartCounter(int init=0);
void Reset(); // overrides inherited method
~RestartCounter(();
};
RestartCounter::RestartCounter(int init) : Number(init) {
original = init; }
void RestartCounter::Reset() { value = original; }
RestartCounter::~RestartCounter() {}
To emphasize again the role of inheritance, the following code illustrates that a RestartCounter object includes all of the (non-overridden) methods of its ancestors (Number and DisplayableNumber):
TextBox display(Location(100,100), Shape(50,50));
RestartCounter restart(7);
restart.Next(); // from Number
restart.ShowIn(display); // from DisplayableNumber
restart.Show(); // from DisplayableNumber
restart.Reset(); // from RestartCounter (overrides
// DisplayableNumber::Reset()
Method LookupWhen an invocation is received by an object with a layered structure (i.e., an object whose structure is defined through inheritance) a method lookup occurs to determine which method in the layered object to execute in response to the invocation. This method lookup is performed by the receiving object transparently to the invoker. The method lookup described below should be viewed only as a conceptual aid, for in C++ such a lookup does not actually take place at run-time. However, the method lookup described is conceptually correct and gives an intuitive way to understand the notion of overriding. Method lookup is a bottom-up search; it always begins in the level corresponding to the most-derived class. For a JumpCounter object, the method lookup begins in the JumpCounter layer; for a Number object, the method lookup begins in the Number layer. If a method matching the invocation is found, it is selected for execution and the method lookup is complete. If a matching method is not found, the method lookup continues the search by moving to the layer immediately above the current layer. The layered structure for a RestartCounter object illustrates overriding and method lookup. As shown below, a RestartCounter object has three layers: RestartCounter, Number, and DisplayableNumber. The figure shows the invocation of the methods Next(), Restart(), and Show().
Finally, the method lookup for the invocation Show() is:
Thus, the invocation of Show on a RestartCounter object is bound to DisplayableNumber::Show.
|
|||||||||
|
|||||||||