180 likes | 331 Views
Overriding. CMPS 2143. Overriding. Recall, a method in a child class overrides a method in the parent class, if it has the same name and type signature. Also known as inclusion polymorphism important when combined with substitution. Parent. void method (int, float. Child.
E N D
Overriding CMPS 2143
Overriding • Recall, a method in a child class overrides a method in the parent class, if it has the same name and type signature. • Also known as inclusion polymorphism • important when combined with substitution Parent void method (int, float Child AnotherChild void method (int, float …
Overriding • In this chapter we will investigate some of the issues that arise from the use of overriding. • Difference from Overloading • Notations • Replacement and Refinement • Shadowing
Overriding vs Overloading Overloading Overriding • same method name • two or more method bodies • classes that methods appear in do NOT have to be in parent/child relationship • signatures MUST NOT match • methods are SEPARATE • resolved at COMPILE-TIME • same method name • two or more method bodies • classes that methods appear in MUST be in parent/child relationship • signatures MUST match • methods SOMETIMES COMBINED • resolved at RUN-TIME
Notations for Overriding • Java, Smalltalk, Objective-C : override with no special keywords, only similarity of type signatures • C++ : notation is in parent class • virtualmethod in parent class indicates method MAY be overridden • Object Pascal: notation is in child class • C# and Delphi Pascal – keyword required in BOTH parent and child • C# use virtual method in parent class and override method in child class
Replacement vs Refinement • There are actually two different ways that overriding can be handled: • A replacement totally and completely replaces the code in the parent class the code in the child class. • A refinement executes the code in the parent class, and adds to it the code in the child class. • Most languages use both types of semantics in different situations. • Constructors, for example, almost always use refinement.
Replacement vs Refinement • Both forms useful and both OFTEN found in the same programming language • Almost all languages use refinement for constructors • void Square::Square (int s) : Rectangle (s,s) {…} • even default child constructor calls default parent constructor • THIS ENSURES the data fields for both the parent and child will be properly set.
Replacement • Two major reasons for using replacement • the method is the parent class is abstract (or pure virtual), it MUST be replaced • the method in the parent class is a default method, not appropriate for all situations • recall Animal speak() method, and Dog speak method() earlier • the child method is more efficient than the parent method • parent class polygon and child class square with methods computeArea();
Downside of Replacement • No guarantee that child class will have any meaning at all similar to the parent class. • For example, a child class could redefine sqrt to compute the cube root of its argument. • This goes back to the difference between subclasses and subtypes. • Refinement makes this more difficult to do, since whatever the parent does is guaranteed to be part of the child. This is why most languages use refinement semantics for constructors.
Refinement • Code in child class combined with code in parent class and both executed • constructors perform a refinement • in most languages, code from parent class executed first
Refinement • C++ example void Parent:: example(int a) { cout << “in parent code\n”; } void Child::example(int a) { Parent::example(12); //do parent action cout << “in child code\n”; } • Java example class Parent { public void example(int a) {cout<< “in parent code\n”;} } class Child { public void example(int a) { super.example(12); //do parent action cout<< “in child code\n”; }
Refinement • Advocates for languages that use refinement argue mechanism makes it almost impossible to write a subclass that is not a subtype. • It is possible with replacement to have a child class compute a cube root in place of a square root. • Advocates for languages that use replacement argue that those errors are uncommon
Overriding versus Shadowing • It is common in programming languages for one declaration of a variable to shadow a previous variable of the same name • Shadowing is resolved at compile time class Silly { private int x; // an instance variable named x public void example (int x) { // x shadows instance variable int a = x+1; while (a > 3) { int x = 1; //local variable shadows parameter a = a - x; } } }
Shadowing of Instance Variables in Java • Java allows instance variables to be redefined, and uses shadowing. class Parent { public int x = 12; } class Child extend Parent { public int x = 42; // shadows variable from parent class } Parent p = new Parent(); System.out.println(p.x); //12 Child c = new Child(); System.out.println(c.x); //42 p = c; // be careful here! System.out.println(p.x); //12
Shadowing Methods • Many of those languages that require the virtual keyword in the parent class will use shadowing if it is omitted: class Parent { public: // note, no virtual keyword here void example () { cout << "Parent" << endl; } }; class Child : public Parent { public: void example () { cout << "Child" << endl; } }; Parent * p = new Parent(); p->example(); //Parent Child * c = new Child(); c->example(); //Child p = c; // be careful here! p->example(); // Parent
Overriding, Shadowing and Redefinition • Overriding • The type signatures are the same in both parent and child classes, and the method is declared as virtual in the parent class. • Shadowing • The type signatures are the same in both parent and child classes, but the method was not declared as virtual in the parent class. • Redefinition • The type signature in the child class differs from that given in the parent class. • (Example available in Chapter 15)
Chapter Summary • An override occurs when a method in the child classes uses the same name and type signature as a method in the parent class. • Unlike overloading, overriding is resolved at run-time. • There are two possible means for an overriding, replacement and refinement. • A name can shadow another name. Some languages permit both shadowing and overriding. Shadowing is resolved at compile time. • A change in the type signature can be covariant or contravariant, if it moves down or up the type hierarchy. The semantics of both types of change can be subtle.
Study Questions • pg. 332: 1-3, 8, 9, 11 • Quiz next week over • overloading • overriding by replacement and refinement • shadowing • redefinition