Language: EN

que-es-el-override-de-metodos-en-programacion

What is and how to use the method override

We have already seen that in object-oriented programming (OOP), one of the most important and fundamental concepts is the ability of Inheritance and Polymorphism among others.

Both concepts rely heavily on method overriding (or override in English) of methods and variables in derived classes.

Method overriding is a feature that allows a derived class to provide a different implementation of a method that is already defined in its base class.

Overriding is used to modify the behavior of inherited methods, allowing subclasses to customize or replace the behavior of methods defined in base classes.

Practical Case

Let’s look at an example to understand how methods are overridden. A classic example is used to explain inheritance in OOP, an example with Puppies and Kittens.

Suppose we have a base class Animal. This class has an instance method called MakeSound() that prints “The animal makes a sound” to the console.

Now we take a derived class Dog, which inherits from Animal, and provide an alternative version of the MakeSound() method.

class Animal
{
    // Method in the base class
    MakeSound()
    {
        Console.Log("The animal makes a sound");
    }
}

class Dog extends Animal
{
    // Overriding the method in the child class
    override MakeSound()
    {
        Console.Log("The dog barks");
    }
}

Some languages will require marking the overridden method with a reserved keyword (like override or new) and others will not (that doesn’t matter to me now, we will see it at the end with examples in specific languages).

Now the important thing is to understand how Inheritance and Polymorphism work with this overridden method.

Calling Overridden Methods

Let’s look at the two simplest cases:

  • Instance of Animal stored in variable Animal
  • Instance of Dog stored in variable Dog
Animal myAnimal = new Animal();
myAnimal.MakeSound(); // Output: The animal makes a sound

Dog myDog = new Dog();
myDog.MakeSound(); // Output: The dog barks

As we can see, when invoking MakeSound(), each instance calls its own definition of MakeSound(). Logical and expected.

Here we see that the derived class Dog has indeed overridden the method of its base class Animal, and when we call it, it invokes its method (not the one from its base class).

Now, the interesting case is what happens when we store an instance of Dog in a variable of type Animal. That is, the interesting case is this 👇

Animal animalDog = new Dog();
animalDog.MakeSound(); // Output: The dog barks

In general, in most languages (each with its details), the normal behavior is that the derived class’s method is invoked. That is, the variable type doesn’t matter; what matters is the instance we hold in it.

As the instance has the MakeSound() method overridden, the method that will be called is the one that exists in the Dog class. Here we have the functioning of method overriding and Polymorphism.

Some languages may have their peculiarities, such as requiring marking the overridden method with a reserved keyword (like override or new). But, in principle, the “normal” functioning of method overriding in OOP is what we have just seen.

Keyword base

In some cases, it may be useful to invoke the method of the base class from the derived class using the base keyword.

Dog extends Animal
{
    MakeSound()
    {
        // Call to the base class method
        base.MakeSound();
        Console.Log("The dog barks");
        // Output: The animal makes a sound 
        //         The dog barks
    }
}

In the previous example, MakeSound in the Dog class first calls the implementation of the method in the base class Animal before adding its own additional behavior.

In this case, it would display both messages:

  • “The animal makes a sound”, when invoking the method base.MakeSound()
  • “The dog barks”, when invoking its own code

Variable Override

Variable overriding, also known as variable hiding, allows a derived class to declare a variable with the same name as a variable in its base class (that’s why we say it “hides” the variable of the parent class in the child class).

This means that the variable in the child class hides the variable in the parent class and can have a different value.

class Parent
{
    string Message = "Hello from the Parent class";
}

class Child extends Parent
{
    new string Message = "Hello from the Child class";
}

In this example,

  • The Child class declares a variable Message
  • This hides the Message variable from the Parent class
  • When accessing the Message variable from an instance of the Child class
  • Therefore, it shows the value Hello from the Child class

It is not as common as method overriding. In fact, it is not particularly useful. But if you find a language that allows it, well, there it is.

Examples in Different Languages

Now let’s look at an example of how method overriding is done in different programming languages.

In C#, method overriding is done using the keyword override in the derived class to override the behavior of the function defined in the base class.

public class Animal
{
    public virtual void MakeSound()
    {
        Console.WriteLine("The animal makes a sound");
    }
}

public class Dog : Animal
{
    public override void MakeSound()
    {
        Console.WriteLine("Woof");
    }
}

public class Cat : Animal
{
    public override void MakeSound()
    {
        Console.WriteLine("Meow");
    }
}

// Usage
Animal dog = new Dog();
Animal cat = new Cat();

dog.MakeSound(); // Output: Woof
cat.MakeSound(); // Output: Meow

In C++, method overriding is done using the keyword override in the derived class to indicate that a virtual function from the base class is being overridden.

#include <iostream>

class Animal {
public:
    virtual void MakeSound() const {
        std::cout << "The animal makes a sound" << std::endl;
    }
};

class Dog : public Animal {
public:
    void MakeSound() const override {
        std::cout << "Woof" << std::endl;
    }
};

class Cat : public Animal {
public:
    void MakeSound() const override {
        std::cout << "Meow" << std::endl;
    }
};

// Usage
int main() {
    Animal* dog = new Dog();
    Animal* cat = new Cat();

    dog->MakeSound(); // Output: Woof
    cat->MakeSound(); // Output: Meow

    delete dog;
    delete cat;

    return 0;
}

In JavaScript, we can redefine base class methods by declaring the same method in the derived class.

class Animal {
    makeSound() {
        console.log("The animal makes a sound");
    }
}

class Dog extends Animal {
    makeSound() {
        console.log("Woof");
    }
}

class Cat extends Animal {
    makeSound() {
        console.log("Meow");
    }
}

// Usage
let animal1 = new Dog();
let animal2 = new Cat();

animal1.makeSound(); // Output: Woof
animal2.makeSound(); // Output: Meow

In TypeScript, the concept of classes and inheritance is similar to that of JavaScript but with the advantage of static typing.

class Animal {
    makeSound(): void {
        console.log("The animal makes a sound");
    }
}

class Dog extends Animal {
    makeSound(): void {
        console.log("Woof");
    }
}

class Cat extends Animal {
    makeSound(): void {
        console.log("Meow");
    }
}

// Usage
const dog: Animal = new Dog();
const cat: Animal = new Cat();

dog.makeSound(); // Output: Woof
cat.makeSound(); // Output: Meow

In Python, method overriding is simply done by redefining the method in the derived class.

class Animal:
    def make_sound(self):
        print("The animal makes a sound")

class Dog(Animal):
    def make_sound(self):
        print("Woof")

class Cat(Animal):
    def make_sound(self):
        print("Meow")

# Usage
dog = Dog()
cat = Cat()

dog.make_sound() # Output: Woof
cat.make_sound() # Output: Meow