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.

Both concepts are based largely on the method override (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 the base classes.

Practical case

Let’s see an example to understand how methods are overridden. We have a classic example 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 to the console “The animal makes a sound”.

Now let’s 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
{
    // Method override in the derived class
    override MakeSound()
    {
        Console.Log("The dog barks");
    }
}

Some languages will require marking the overridden method with a reserved word (like override or new) and others won’t. I don’t care about that now, but we’ll see it in 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 see the two simplest cases:

  • Instance of Animal saved in variable Animal
  • Instance of Dog saved 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 to be expected.

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

Now, the interesting case is what happens when we save 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 detail) it is normal for the method of the derived class to be invoked. That is, the type of variable doesn’t matter, what matters is the instance we save in it.

Since 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 method override and the Polymorphism in operation.

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

base keyword

In some cases, it may be useful to invoke the base class method 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 above example, MakeSound in the Dog class first calls the method implementation in the base class Animal before adding its own additional behavior.

In this case, it would show both messages on the screen

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

Variable override

Variable override, also known as variable hiding, allows a derived class to declare a variable with the same name as a variable in its base class, thus hiding the variable from the parent class in the child class.

This means that the variable in the child class hides the variable from 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 Message variable that hides the Message variable of the Parent class. When accessing the Message variable from an instance of the Child class, the value “Hello from the Child class” will be used.

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

Examples in different languages

Now let’s see an example of how method override is performed in different programming languages.

In C#, function override is done using the override keyword 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++, function override is done using the override keyword in the derived class to indicate that a virtual function of 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 perform function redefinition from the base class through the declaration of 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, function override is done simply by redefining the method in the derived class.

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

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

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

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

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