Method overriding

Last updated
Illustration Method overriding in subclass.svg
Illustration

Method overriding, in object-oriented programming, is a language feature that allows a subclass or child class to provide a specific implementation of a method that is already provided by one of its superclasses or parent classes. In addition to providing data-driven algorithm-determined parameters across virtual network interfaces, [1] it also allows for a specific type of polymorphism (subtyping). The implementation in the subclass overrides (replaces) the implementation in the superclass by providing a method that has same name, same parameters or signature, and same return type as the method in the parent class. [2] The version of a method that is executed will be determined by the object that is used to invoke it. If an object of a parent class is used to invoke the method, then the version in the parent class will be executed, but if an object of the subclass is used to invoke the method, then the version in the child class will be executed. [3] This helps in preventing problems associated with differential relay analytics which would otherwise rely on a framework in which method overriding might be obviated. [4] [5] Some languages allow a programmer to prevent a method from being overridden.

Contents

Language-specific examples

Ada

Ada provides method overriding by default. To favor early error detection (e.g. a misspelling), it is possible to specify when a method is expected to be actually overriding, or not. That will be checked by the compiler.

typeTisnewControlledwith......;procedureOp(Obj: inoutT;Data: inInteger);typeNTisnewTwithnull record;overriding-- overriding indicatorprocedureOp(Obj: inoutNT;Data: inInteger);overriding-- overriding indicatorprocedureOp(Obj: inoutNT;Data: inString);-- ^ compiler issues an error: subprogram "Op" is not overriding

C#

C# does support method overriding, but only if explicitly requested using the modifiers override and virtual or abstract.

Csharp method overriding.svg

abstractclassAnimal{publicstringName{get;set;}// MethodspublicvoidDrink();publicvirtualvoidEat();publicvoidGo();}classCat:Animal{publicnewstringName{get;set;}// MethodspublicvoidDrink();// Warning: hides inherited drink(). Use newpublicoverridevoidEat();// Overrides inherited eat().publicnewvoidGo();// Hides inherited go().}

When overriding one method with another, the signatures of the two methods must be identical (and with same visibility). In C#, class methods, indexers, properties and events can all be overridden.

Non-virtual or static methods cannot be overridden. The overridden base method must be virtual, abstract, or override.

In addition to the modifiers that are used for method overriding, C# allows the hiding of an inherited property or method. This is done using the same signature of a property or method but adding the modifier new in front of it. [6]

In the above example, hiding causes the following:

Catcat=newCat();cat.Name=;// accesses Cat.Namecat.Eat();// calls Cat.Eat()cat.Go();// calls Cat.Go()((Animal)cat).Name=;// accesses Animal.Name!((Animal)cat).Eat();// calls Cat.Eat()!((Animal)cat).Go();// calls Animal.Go()!

C++

C++ does not have the keyword super that a subclass can use in Java to invoke a superclass version of a method that it wants to override. Instead, the name of the parent or base class is used followed by the scope resolution operator. For example, the following code presents two classes, the base class Rectangle, and the derived class Box. Box overrides the Rectangle class's Print method, so as also to print its height. [7]

#include<iostream>//---------------------------------------------------------------------------classRectangle{public:Rectangle(doublel,doublew):length_(l),width_(w){}virtualvoidPrint()const;private:doublelength_;doublewidth_;};//---------------------------------------------------------------------------voidRectangle::Print()const{// Print method of base class.std::cout<<"Length = "<<length_<<"; Width = "<<width_;}//---------------------------------------------------------------------------classBox:publicRectangle{public:Box(doublel,doublew,doubleh):Rectangle(l,w),height_(h){}voidPrint()constoverride;private:doubleheight_;};//---------------------------------------------------------------------------// Print method of derived class.voidBox::Print()const{// Invoke parent Print method.Rectangle::Print();std::cout<<"; Height = "<<height_;}

The method Print in class Box, by invoking the parent version of method Print, is also able to output the private variables length and width of the base class. Otherwise, these variables are inaccessible to Box.

The following statements will instantiate objects of type Rectangle and Box, and call their respective Print methods:

intmain(intargc,char**argv){Rectanglerectangle(5.0,3.0);// Outputs: Length = 5.0; Width = 3.0rectangle.Print();Boxbox(6.0,5.0,4.0);// The pointer to the most overridden method in the vtable in on Box::print,// but this call does not illustrate overriding.box.Print();// This call illustrates overriding.// outputs: Length = 6.0; Width = 5.0; Height= 4.0static_cast<Rectangle&>(box).Print();}

In C++11, similar to Java, a method that is declared final in the super class cannot be overridden; also, a method can be declared override to make the compiler check that it overrides a method in the base class.

Delphi

In Delphi, method overriding is done with the directive override, but only if a method was marked with the dynamic or virtual directives.

The inherited reserved word must be called when you want to call super-class behavior

typeTRectangle=classprivateFLength:Double;FWidth:Double;publicpropertyLengthreadFLengthwriteFLength;propertyWidthreadFWidthwriteFWidth;procedurePrint;virtual;end;TBox=class(TRectangle)publicprocedurePrint;override;end;

Eiffel

In Eiffel, feature redefinition is analogous to method overriding in C++ and Java. Redefinition is one of three forms of feature adaptation classified as redeclaration. Redeclaration also covers effecting, in which an implementation is provided for a feature which was deferred (abstract) in the parent class, and undefinition, in which a feature that was effective (concrete) in the parent becomes deferred again in the heir class. When a feature is redefined, the feature name is kept by the heir class, but properties of the feature such as its signature, contract (respecting restrictions for preconditions and postconditions), and/or implementation will be different in the heir. If the original feature in the parent class, called the heir feature's precursor, is effective, then the redefined feature in the heir will be effective. If the precursor is deferred, the feature in the heir will be deferred. [8]

The intent to redefine a feature, as message in the example below, must be explicitly declared in the inherit clause of the heir class.

classTHOUGHTfeaturemessage-- Display thought messagedoprint("I feel like I am diagonally parked in a parallel universe.%N")endendclassADVICEinheritTHOUGHTredefinemessageendfeaturemessage-- Precursordoprint("Warning: Dates in calendar are closer than they appear.%N")endend

In class ADVICE the feature message is given an implementation that differs from that of its precursor in class THOUGHT.

Consider a class which uses instances for both THOUGHT and ADVICE:

classAPPLICATIONcreatemakefeaturemake-- Run application.do(create{THOUGHT}).message;(create{ADVICE}).messageendend

When instantiated, class APPLICATION produces the following output:

I feel like I am diagonally parked in a parallel universe.Warning: Dates in calendar are closer than they appear.

Within a redefined feature, access to the feature's precursor can be gained by using the language keyword Precursor. Assume the implementation of {ADVICE}.message is altered as follows:

message-- Precursordoprint("Warning: Dates in calendar are closer than they appear.%N")Precursorend

Invocation of the feature now includes the execution of {THOUGHT}.message, and produces the following output:

Warning: Dates in calendar are closer than they appear.I feel like I am diagonally parked in a parallel universe.

Java

In Java, when a subclass contains a method with the same signature (name and parameter types) as a method in its superclass, then the subclass's method overrides that of the superclass. For example:

classThought{publicvoidmessage(){System.out.println("I feel like I am diagonally parked in a parallel universe.");}}publicclassAdviceextendsThought{@Override// @Override annotation in Java 5 is optional but helpful.publicvoidmessage(){System.out.println("Warning: Dates in calendar are closer than they appear.");}}

Class Thought represents the superclass and implements a method call message(). The subclass called Advice inherits every method that could be in the Thought class. Class Advice overrides the method message(), replacing its functionality from Thought.

Thoughtparking=newThought();parking.message();// Prints "I feel like I am diagonally parked in a parallel universe."Thoughtdates=newAdvice();// Polymorphismdates.message();// Prints "Warning: Dates in calendar are closer than they appear."

When a subclass contains a method that overrides a method of the superclass, then that (superclass's) overridden method can be explicitly invoked from within a subclass's method by using the keyword super. [3] (It cannot be explicitly invoked from any method belongings to a class that is unrelated to the superclass.) The super reference can be

publicclassAdviceextendsThought{@Overridepublicvoidmessage(){System.out.println("Warning: Dates in calendar are closer than they appear.");super.message();// Invoke parent's version of method.}

There are methods that a subclass cannot override. For example, in Java, a method that is declared final in the super class cannot be overridden. Methods that are declared private or static cannot be overridden either because they are implicitly final. It is also impossible for a class that is declared final to become a super class. [9]

Kotlin

In Kotlin we can simply override a function like this (note that the function must be open):

funmain(){valp=Parent(5)valc=Child(6)p.myFun()c.myFun()}openclassParent(vala:Int){openfunmyFun()=println(a)}classChild(valb:Int):Parent(b){overridefunmyFun()=println("overrided method")}

Python

In Python, when a subclass contains a method that overrides a method of the superclass, you can also call the superclass method by calling super(Subclass,self).method [10] instead of self.method. Example:

classThought:def__init__(self)->None:print("I'm a new object of type Thought!")defmessage(self)->None:print("I feel like I am diagonally parked in a parallel universe.")classAdvice(Thought):def__init__(self)->None:super(Advice,self).__init__()defmessage(self)->None:print("Warning: Dates in calendar are closer than they appear")super(Advice,self).message()t=Thought()# "I'm a new object of type Thought!"t.message()# "I feel like I am diagonally parked in a parallel universe.a=Advice()# "I'm a new object of type Thought!"a.message()# "Warning: Dates in calendar are closer than they appear"# "I feel like I am diagonally parked in a parallel universe.# ------------------# Introspection:isinstance(t,Thought)# Trueisinstance(a,Advice)# Trueisinstance(a,Thought)# True

Ruby

In Ruby when a subclass contains a method that overrides a method of the superclass, you can also call the superclass method by calling super in that overridden method. You can use alias if you would like to keep the overridden method available outside of the overriding method as shown with 'super_message' below.

Example:

classThoughtdefmessageputs"I feel like I am diagonally parked in a parallel universe."endendclassAdvice<Thoughtalias:super_message:messagedefmessageputs"Warning: Dates in calendar are closer than they appear"superendend

Notes

  1. Zhang, Jie (2015). "A novel P2P overridden API for open data communications in WWW". 2015 IEEE International Conference on Consumer Electronics - Taiwan. pp. 156–157. doi:10.1109/ICCE-TW.2015.7216830. ISBN   978-1-4799-8745-0. S2CID   23295793.
  2. Flanagan 2002, p. 107
  3. 1 2 Lewis & Loftus 2006, p.454
  4. Overbey, J (2011). "Differential precondition checking: A lightweight, reusable analysis for refactoring tools". 2011 26th IEEE/ACM International Conference on Automated Software Engineering (ASE 2011). pp. 303–312. doi:10.1109/ASE.2011.6100067. ISBN   978-1-4577-1639-3. S2CID   5933208.
  5. Li, K (2014). "Residual investigation: Predictive and precise bug detection". ACM Transactions on Software Engineering and Methodology. 24 (2). doi:10.1145/2656201. S2CID   47112802.
  6. Mössenböck, Hanspeter (2002-03-25). "Advanced C#: Overriding of Methods" (PDF). Institut für Systemsoftware, Johannes Kepler Universität Linz, Fachbereich Informatik. pp. 6–8. Retrieved 2011-08-02.
  7. Malik 2006, p. 676
  8. Meyer 2009, page 572-575
  9. Deitel & Deitel 2001, p.474
  10. super().method in Python 3 - see https://docs.python.org/3/library/functions.html#super Archived 2018-10-26 at the Wayback Machine

See also

Related Research Articles

Multiple inheritance is a feature of some object-oriented computer programming languages in which an object or class can inherit features from more than one parent object or parent class. It is distinct from single inheritance, where an object or class may only inherit from one particular object or class.

A visitor pattern is a software design pattern and separates the algorithm from the object structure. Because of this separation new operations can be added to existing object structures without modifying the structures. It is one way to follow the open/closed principle in object-oriented programming and software engineering.

The bridge pattern is a design pattern used in software engineering that is meant to "decouple an abstraction from its implementation so that the two can vary independently", introduced by the Gang of Four. The bridge uses encapsulation, aggregation, and can use inheritance to separate responsibilities into different classes.

In object-oriented programming, the decorator pattern is a design pattern that allows behavior to be added to an individual object, dynamically, without affecting the behavior of other objects from the same class. The decorator pattern is often useful for adhering to the Single Responsibility Principle, as it allows functionality to be divided between classes with unique areas of concern as well as to the Open-Closed Principle, by allowing the functionality of a class to be extended without being modified. Decorator use can be more efficient than subclassing, because an object's behavior can be augmented without defining an entirely new object.

In object-oriented programming, the template method is one of the behavioral design patterns identified by Gamma et al. in the book Design Patterns. The template method is a method in a superclass, usually an abstract superclass, and defines the skeleton of an operation in terms of a number of high-level steps. These steps are themselves implemented by additional helper methods in the same class as the template method.

A method in object-oriented programming (OOP) is a procedure associated with an object, and generally also a message. An object consists of state data and behavior; these compose an interface, which specifies how the object may be utilized by any of its various consumers. A method is a behavior of an object parametrized by a consumer.

The fragile base class problem is a fundamental architectural problem of object-oriented programming systems where base classes (superclasses) are considered "fragile" because seemingly safe modifications to a base class, when inherited by the derived classes, may cause the derived classes to malfunction. The programmer cannot determine whether a base class change is safe simply by examining in isolation the methods of the base class.

In object-oriented programming, in languages such as C++, and Object Pascal, a virtual function or virtual method is an inheritable and overridable function or method for which dynamic dispatch is facilitated. This concept is an important part of the (runtime) polymorphism portion of object-oriented programming (OOP). In short, a virtual function defines a target function to be executed, but the target might not be known at compile time.

In computing, type introspection is the ability of a program to examine the type or properties of an object at runtime. Some programming languages possess this capability.

In object-oriented programming, delegation refers to evaluating a member of one object in the context of another original object. Delegation can be done explicitly, by passing the sending object to the receiving object, which can be done in any object-oriented language; or implicitly, by the member lookup rules of the language, which requires language support for the feature. Implicit delegation is the fundamental method for behavior reuse in prototype-based programming, corresponding to inheritance in class-based programming. The best-known languages that support delegation at the language level are Self, which incorporates the notion of delegation through its notion of mutable parent slots that are used upon method lookup on self calls, and JavaScript; see JavaScript delegation.

<span class="mw-page-title-main">Java syntax</span> Set of rules defining correctly structured program

The syntax of Java is the set of rules defining how a Java program is written and interpreted.

Many programming language type systems support subtyping. For instance, if the type Cat is a subtype of Animal, then an expression of type Cat should be substitutable wherever an expression of type Animal is used.

In object-oriented programming, inheritance is the mechanism of basing an object or class upon another object or class, retaining similar implementation. Also defined as deriving new classes from existing ones such as super class or base class and then forming them into a hierarchy of classes. In most class-based object-oriented languages like C++, an object created through inheritance, a "child object", acquires all the properties and behaviors of the "parent object", with the exception of: constructors, destructors, overloaded operators and friend functions of the base class. Inheritance allows programmers to create classes that are built upon existing classes, to specify a new implementation while maintaining the same behaviors, to reuse code and to independently extend original software via public classes and interfaces. The relationships of objects or classes through inheritance give rise to a directed acyclic graph.

Call super is a code smell or anti-pattern of some object-oriented programming languages. Call super is a design pattern in which a particular class stipulates that in a derived subclass, the user is required to override a method and call back the overridden function itself at a particular point. The overridden method may be intentionally incomplete, and reliant on the overriding method to augment its functionality in a prescribed manner. However, the fact that the language itself may not be able to enforce all conditions prescribed on this call is what makes this an anti-pattern.

this, self, and Me are keywords used in some computer programming languages to refer to the object, class, or other entity of which the currently running code is a part. The entity referred to by these keywords thus depends on the execution context. Different programming languages use these keywords in slightly different ways. In languages where a keyword like "this" is mandatory, the keyword is the only way to access data and methods stored in the current object. Where optional, they can disambiguate variables and functions with the same name.

In the Java computer programming language, an annotation is a form of syntactic metadata that can be added to Java source code. Classes, methods, variables, parameters and Java packages may be annotated. Like Javadoc tags, Java annotations can be read from source files. Unlike Javadoc tags, Java annotations can also be embedded in and read from Java class files generated by the Java compiler. This allows annotations to be retained by the Java virtual machine at run-time and read via reflection. It is possible to create meta-annotations out of the existing ones in Java.

<span class="mw-page-title-main">Covariant return type</span>

In object-oriented programming, a covariant return type of a method is one that can be replaced by a "narrower" type when the method is overridden in a subclass. A notable language in which this is a fairly common paradigm is C++.

clone is a method in the Java programming language for object duplication. In Java, objects are manipulated through reference variables, and there is no operator for copying an object—the assignment operator duplicates the reference, not the object. The clone method provides this missing functionality.

In object-oriented programming, a virtual base class is a nested inner class whose functions and member variables can be overridden and redefined by subclasses of an outer class. Virtual classes are analogous to virtual functions.

In object-oriented programming, forwarding means that using a member of an object results in actually using the corresponding member of a different object: the use is forwarded to another object. Forwarding is used in a number of design patterns, where some members are forwarded to another object, while others are handled by the directly used object. The forwarding object is frequently called a wrapper object, and explicit forwarding members are called wrapper functions.

References