Start learning free

LESSON 182 OF 343 · OBJECT-ORIENTED PROGRAMMING

Method Overriding in C++: virtual and override

Lesson Read the full explanation

TL ; DR:

When a child class defines a method with the same name as the parent's, the child's version overrides the parent's. Different objects can give the same method name different behavior.


class Dog {
public:
    virtual void bark() { cout << "Woof!" << endl; }
};
class Puppy : public Dog {
public:
    void bark() override { cout << "Yip!" << endl; }
};


Full lesson:

You've seen that a child class inherits the parent's methods. Overriding is what happens when the child wants to change one of those inherited methods.

Why override?

Subclasses are usually special cases of the parent. A Puppy is a Dog, but it sounds different — "Yip!" instead of "Woof!". Instead of inventing a new method name, you redefine bark() on the Puppy. Callers don't need to know which subclass they're holding — they just call bark() and the right version runs.

How it works in each language

  • C# — the parent method must be marked virtual, the child marks its replacement override. The compiler enforces this pairing.
  • Java — every non-final method is virtual by default; the @Override annotation is optional but tells the compiler to verify the signature matches.
  • Python — defining a method with the same name in the child class replaces the parent's. No keyword required.
  • JavaScript — same as Python: define the method again on the child class and it wins.
  • C++ — the parent method must be virtual; override on the child is optional but compiler-checked.

Your task

The Dog class already defines bark. Inside the Puppy subclass, override bark so it prints "Yip! I am " followed by the puppy's name. The harness creates a Puppy named "Buddy" and calls bark() on it.

Expected output:

Yip! I am Buddy
STEP 1 OF 2
    Ctrl + Enter to check

    C++ · OBJECT-ORIENTED PROGRAMMING

    Method Overriding in C++, explained

    Changing an inherited function

    A derived class inherits its base class's member functions, but sometimes an inherited function isn't quite right. A Puppy is a Dog, yet it should say "Yip!" instead of "Woof!". Instead of inventing a new function name, the child defines bark() again. That is overriding: the child supplies its own version of a function the parent already has.

    The payoff is that callers don't need to know which kind of dog they hold. They call bark(), and the right version runs.

    virtual and override

    In C++, overriding takes two keywords, one in each class:

    class Dog {
    public:
        virtual void bark() { cout << "Woof!" << endl; }
    };
    
    class Puppy : public Dog {
    public:
        void bark() override { cout << "Yip!" << endl; }
    };
    
    • virtual in the base class marks the function as one that derived classes may replace. Without it, the child's function doesn't override anything; it only hides the parent's.
    • override in the derived class is optional, but it asks the compiler to check that a virtual function with exactly this signature exists in a base class. If you misspell the name or change a parameter, the compiler stops you instead of quietly creating a new function.

    Once a function is virtual, it stays virtual in every class derived from it, so override alone is enough in the child. The signature must match: the name, the parameter types and the const qualification.

    Here is what override catches. In this code the parameter list differs:

    class Puppy : public Dog {
    public:
        void bark(int times) override { cout << "Yip!" << endl; }
    };
    

    GCC rejects it with marked 'override', but does not override. Without the keyword, it would compile and bark(int) would be an unrelated new function, while a call to bark() through a Dog pointer still printed "Woof!".

    What happens without virtual

    If the base function is not virtual, the child's version hides it, and the call depends on the declared type of the variable, not on the real object:

    class Base {
    public:
        void who() { cout << "Base" << endl; }
        virtual void v() { cout << "Base v" << endl; }
    };
    
    class Der : public Base {
    public:
        void who() { cout << "Der" << endl; }
        void v() override { cout << "Der v" << endl; }
    };
    
    Der x;
    Base* b = &x;
    b->who();   // Base
    b->v();     // Der v
    x.who();    // Der
    

    Through the Base*, the non-virtual who() runs the base version, while the virtual v() runs the derived one. This is the most surprising rule for people coming from Java or Python, where every method behaves like a virtual one. In C++ you opt in with virtual. The next lesson, on polymorphism, relies on it.

    Calling the parent's version

    An override often wants to extend the parent's behaviour, not replace it. Name the base class and use the scope operator to call it directly:

    void bark() override {
        Dog::bark();                  // run the parent's version first
        cout << "Yip!" << endl;
    }
    

    The lesson's exercise

    The base class's bark() is already virtual and prints Woof! I am and the name. Puppy has a constructor that forwards the name to Dog. The task is to override bark in Puppy so that the program prints:

    Yip! I am Buddy
    1. Inside Puppy, under public: and below the constructor, declare void bark() override { }. The return type and the empty parameter list must match the base version exactly.
    2. In the body, print "Yip! I am " followed by name and endl. name is a public member inherited from Dog, so it can be used directly.

    The solution in C++

    class Dog {
    public:
        string name;
        Dog(string name) { this->name = name; }
        virtual void bark() {
            cout << "Woof! I am " << name << endl;
        }
    };
    
    class Puppy : public Dog {
    public:
        Puppy(string name) : Dog(name) {}
        void bark() override {
            cout << "Yip! I am " << name << endl;
        }
    };
    
    class Solution {
    public:
        void mainFunction() {
            Puppy buddy("Buddy");
            buddy.bark();
        }
    };
    

    The variable buddy is a Puppy, so even a non-virtual function would run the child's version here, because the compiler knows the exact type. The virtual keyword starts to matter when the call goes through a pointer or reference to Dog, as in the next lessons. Writing it correctly now is the habit to build.

    Common mistakes

    • Forgetting virtual in the base class. The code compiles with a plain base function, but calls through Dog* or Dog& run the parent's version. If you then add override, the compiler reports an error, which is a good reason to use it.
    • A signature that differs slightly. A different parameter type, or a missing const on one side, makes a new function instead of an override. Use override to catch it.
    • Putting override on the base class. It belongs on the function that replaces a virtual one.
    • Copying a Puppy into a Dog variable. The copy is a plain Dog, so bark() runs the parent's version. Use a pointer or reference to keep the real type.

    Key takeaways

    • Mark the base function virtual and the child's replacement override.
    • The signature must match exactly; override makes the compiler check it.
    • Without virtual, a function is hidden, not overridden, and calls through base pointers use the base version.
    • Call the parent's version with Dog::bark() when you want to extend it.
    Keep going with C++About 340 step-by-step lessons, from your first line of code to coding interviews. Free to start.
    Start learning free