Menu
Coddy logo textTech

Method Overriding

Part of the Object Oriented Programming section of Coddy's C++ journey — lesson 51 of 104.

Method overriding occurs when a derived class provides its own implementation of a method that already exists in the base class. This allows derived classes to customize inherited behavior while keeping the same method signature.

To override a method, simply define a method in the derived class with the exact same name, return type, and parameters:

class Animal {
public:
    void speak() {
        std::cout << "Some sound" << std::endl;
    }
};

class Dog : public Animal {
public:
    void speak() {
        std::cout << "Woof!" << std::endl;
    }
};

Dog d;
d.speak();  // Output: Woof!

The derived class version hides the base class version. However, you can still access the base class method using the scope resolution operator:

class Dog : public Animal {
public:
    void speak() {
        Animal::speak();  // Call base class version
        std::cout << "Woof!" << std::endl;
    }
};

There's an important limitation with this basic form of overriding. When you access a derived object through a base class pointer or reference, the base class version is called instead:

Dog d;
Animal* ptr = &d;
ptr->speak();  // Output: Some sound (not Woof!)

This happens because the compiler determines which method to call based on the pointer type, not the actual object type. To achieve true runtime polymorphism where the correct method is called based on the actual object, you'll need virtual functions, which we'll cover in the next lesson.

challenge icon

Challenge

Easy

Let's build a notification system that demonstrates method overriding in action. You'll create a base Notifier class and two specialized notifiers that customize how messages are delivered.

You'll organize your code across three files:

  • Notifier.h: Define a base Notifier class with:
    • A protected std::string recipient member
    • A constructor that takes a recipient name and stores it
    • A public send(const std::string& message) method that prints: Sending to <recipient>: <message>
  • EmailNotifier.h: Define an EmailNotifier class that publicly inherits from Notifier:
    • A constructor that takes a recipient and passes it to the base class
    • Override the send() method to first call the base class version using Notifier::send(), then print: [Email sent successfully]
  • main.cpp: Read two inputs (each on a separate line):
    1. Recipient name (string)
    2. Message content (string)

    Define an SMSNotifier class directly in main.cpp that publicly inherits from Notifier:

    • A constructor that takes a recipient and passes it to the base class
    • Override the send() method to print: SMS to <recipient>: <message> (completely replacing the base behavior without calling it)

    Create one object of each notifier type (base Notifier, EmailNotifier, and SMSNotifier) using the same recipient. Call send() on each with the input message, printing a separator line between each:

    --- Base Notifier ---
    <output>
    --- Email Notifier ---
    <output>
    --- SMS Notifier ---
    <output>

For example, with inputs Alice and Hello there!:

--- Base Notifier ---
Sending to Alice: Hello there!
--- Email Notifier ---
Sending to Alice: Hello there!
[Email sent successfully]
--- SMS Notifier ---
SMS to Alice: Hello there!

Notice how EmailNotifier extends the base behavior by calling the parent method first, while SMSNotifier completely replaces it with its own implementation. Don't forget header guards and to include the appropriate headers in each file.

Cheat sheet

Method overriding allows a derived class to provide its own implementation of a method from the base class, keeping the same method signature (name, return type, and parameters).

Basic override syntax:

class Animal {
public:
    void speak() {
        std::cout << "Some sound" << std::endl;
    }
};

class Dog : public Animal {
public:
    void speak() {
        std::cout << "Woof!" << std::endl;
    }
};

Dog d;
d.speak();  // Output: Woof!

The derived class method hides the base class version. To call the base class method from the derived class, use the scope resolution operator:

class Dog : public Animal {
public:
    void speak() {
        Animal::speak();  // Call base class version
        std::cout << "Woof!" << std::endl;
    }
};

Important limitation: When accessing a derived object through a base class pointer or reference, the base class version is called:

Dog d;
Animal* ptr = &d;
ptr->speak();  // Output: Some sound (not Woof!)

This is because the compiler determines which method to call based on the pointer type, not the actual object type. For true runtime polymorphism, use virtual functions.

Try it yourself

#include <iostream>
#include <string>
#include "Notifier.h"
#include "EmailNotifier.h"

using namespace std;

// TODO: Define SMSNotifier class here that publicly inherits from Notifier
// - Constructor that passes recipient to base class
// - Override send() to print: SMS to <recipient>: <message>
//   (completely replace base behavior, don't call parent send())

int main() {
    string recipient;
    string message;
    
    getline(cin, recipient);
    getline(cin, message);
    
    // TODO: Create Notifier object with recipient
    // Print "--- Base Notifier ---"
    // Call send() with message
    
    // TODO: Create EmailNotifier object with recipient
    // Print "--- Email Notifier ---"
    // Call send() with message
    
    // TODO: Create SMSNotifier object with recipient
    // Print "--- SMS Notifier ---"
    // Call send() with message
    
    return 0;
}
quiz iconTest yourself

This lesson includes a short quiz. Start the lesson to answer it and track your progress.

All lessons in Object Oriented Programming