Function Overriding in C++

A function is a collection of code blocks with instructions inside, which is used for specific tasks. It is meant to be reused as per requirement, making the division of complex problems into smaller and manageable pieces.

What is Function Overriding in C++?

Function overriding is a concept of object-oriented programming which allows a derived class to redefine a function that is already defined in the base class.

Here the method’s name and parameters remain the same, but the derived class changes its behavior to suit their specific needs.

Example

Let’s consider these 2 functions; one is base class (a) and another is derived class (b), and the function (c) is the main(), where we are implementing overriding −

Function (a)

classbase{public:voidnotice()
   cout <<"This is my Base Class";}

Function (b)

classderived:public base{public:voidnotice()
      cout <<"This is my Derived Class";}

Function (c)

voidmain(){// creating an object for base class and calling it
   base b;
   b.notice();// creating an object for derived class and calling it 
   derived d ;
   d.notice();}

Overriding Explanation

  • Here, we have created an object of base and derived class of ‘function (a) and function(b)’ respectively and called them inside function (c) as shown, “b.notice() and d.notice()” respectively.
  • In this case, for derived class d.notice() will be executed first because it represents the most up-to-date or updated version of the function
  • However, if we create an object of the base class as shown in function(c) “b.msg()” and call it, it will use the original version from the base class.

In short, function overriding occurs when the functionality of the base class is redefined in the derived class. When an object of the derived class is created, it will call the updated function from the derived class, meaning that the base class function (a) is overridden by the derived class function (b).

Function overriding is an essential concept in object-oriented programming, enabling polymorphism and dynamic binding.

Example of Function Overriding

Below is a simple example illustrating how overriding works

#include <iostream>usingnamespace std;// Base classclassShape{public:// Virtual method to be overriddenvirtualvoiddraw()const{
         cout <<"Drawing a shape"<< endl;}};// Derived class CircleclassCircle:public Shape{public:// Overriding the base class methodvoiddraw()constoverride{
         cout <<"Drawing a circle"<< endl;}};// Derived class SquareclassSquare:public Shape{public:// Overriding the base class methodvoiddraw()constoverride{
         cout <<"Drawing a square"<< endl;}};// Main functionintmain(){
   Shape* shapePtr;
   Circle circle;
   Square square;// Point to Circle and call draw()
   shapePtr =&circle;
   shapePtr->draw();// Outputs: Drawing a circle// Point to Square and call draw()
   shapePtr = □
   shapePtr->draw();// Outputs: Drawing a squarereturn0;}

Output

Drawing a circle
Drawing a square

Function Overriding Vs. Function Overloading

Although Function Overriding and Function Overloading are essential key-concepts of Object-oriented programming in C++, they both do serve different purposes.

Function overriding allows derived class to get new implementation of method to its previously defined base class, as having different scopes(base class and derived class) where it resolved at runtime polymorphism(dynamic binding), it only take place in presence of inheritance and can overridden just once, where execution speed relatively slower.

Whereas, function overloading enables you to create multiple functions with the same name but different parameter lists within the same scope. It is resolved at compile time polymorphism (static binding), where presence of inheritance is not important, These functions can be overloaded multiple times and execution speed tends to be faster comparatively.

Advanced Overriding Concepts

Here’s a list of additional sub topics covering advanced overriding concepts −

1. Virtual Destructor

A virtual destructor makes sure that the destructor of the derived class will be executed when an object is removed through a base class pointer. Function overriding with virtual destructors avoids resource leaks and unpredictable behavior by ensuring proper deletion of objects through base class pointers.

Example

Open Compiler

#include <iostream>usingnamespace std;classBaseClass{public:virtual~BaseClass(){// Virtual destructor
         cout <<"BaseClass destructor"<< endl;}};classDerivedClass:public BaseClass{public:~DerivedClass()override{// Overriding destructor
         cout <<"DerivedClass destructor"<< endl;}};intmain(){
   BaseClass* a =newDerivedClass();// Calls DerivedClass's destructor followed// by BaseClass's destructordelete a;return0;}

Output

DerivedClass destructor
BaseClass destructor

2. Covariant Return Value Types

Covariant return types allow derived classes to override a method and return a more specific type than the base class method. This means that a derived class can return a pointer or reference to a more derived type, rather than just the base type. Function overriding improves flexibility and precision in object-oriented programming.

Note

In the derived class, the return type must be a pointer or reference to a type that is derived from the return type of the base class.

Example

Open Compiler

#include <iostream>usingnamespace std;classVehicle{public:// Final methodvirtualvoidhonk()final{
         cout <<"Vehicle honk: Beep beep!"<< endl;}};classSportsCar:public Vehicle{// Cannot override honk() here};intmain(){
   Vehicle* v =newSportsCar();
   v->honk();// Calls Vehicle's honk() methoddelete v;return0;}

Output

Vehicle honk: Beep beep!

3. Overriding and final Keyword alternate word

The `final` keyword stops any further subclassing of a class or overriding of a method.

Function overriding with the `final` keyword is important because it guarantees that a class or method cannot be further changed or extended.

Example

Open Compiler

#include <iostream>usingnamespace std;classSubject{public:// Final methodvirtualvoidexamType()final{
         cout <<"This subject has a written exam."<< endl;}};classMath:public Subject{// Cannot override examType() here};intmain(){
   Subject* s =newMath();
   s->examType();// Calls Subject's examType() methoddelete s;return0;}

Output

This subject has a written exam.

4. Virtual Inheritance

Virtual inheritance in C++ tackles problems which arise with multiple inheritance, particularly the diamond problem. It ensures that when a class inherits from several base classes which have a common ancestor, only a single instance of that common base class is created.

Virtual inheritance makes sure that only one copy of a base class is used when multiple derived classes share that base class in a hierarchy.

Example

Open Compiler

#include <iostream>usingnamespace std;classBase{public:voidpresent(){ cout <<"Display from Base class"<< endl;}};classA:virtual public Base{};classB:virtual public Base{};classFinal:public A, public B{public:voidget(){ cout <<"Display from Final class"<< endl;}};intmain(){
   Final obj;// Displays: Display from Base class
   obj.present();// Displays: Display from Final class
   obj.get();return0;}

Output

Display from Base class
Display from Final class

Advantages of Function Overriding

1. Polymorphism

Overriding enables polymorphism by letting objects of different derived classes be treated as instances of a base class. This allows dynamic method binding at runtime, where the correct method implementation is chosen based on the object type, thus enhancing flexibility and adaptability, making it a fundamental component of polymorphism.

2. Code Reusability

Developers can utilize existing code by inheriting methods from a base class and customizing them in derived classes. This approach fosters a more streamlined and organized code structure.

3. Maintainability

Overriding promotes a modular design by encapsulating various functionalities within distinct classes. This approach simplifies understanding, maintaining, updating and extending the code.

4. Design Patterns

Overriding plays a key role in the Template Method pattern by defining the overall structure of an algorithm in a base class, while permitting subclasses to override specific steps.

The Strategy pattern leverages overriding to encapsulate various algorithms and enable their interchange at runtime.

5. Memory Management

When using inheritance and dynamic memory allocation, virtual destructors are vital for proper memory management. Overriding the destructor in derived classes ensures that resources allocated by the base and derived classes are correctly deallocated, which prevents memory leaks and ensures clean resource release.


Comments

Leave a Reply

Your email address will not be published. Required fields are marked *