C/C++ Arena

Step 2 of 9

virtual and override

Inheritance becomes powerful when code works with the base type but each object behaves according to its real type. A function that takes const Animal& should make a Dog bark and a Cat meow. That's polymorphism ("many forms").

By default, C++ doesn't do this: through a base reference, the base version of a function runs. Marking the function virtual changes that: the call is decided at run time, by the actual object.

#include <iostream>
#include <string>

class Notifier {
public:
    virtual std::string send(const std::string& msg) const { return "log: " + msg; }
    std::string channel() const { return "base"; }          // not virtual
    virtual ~Notifier() = default;
};

class Email : public Notifier {
public:
    std::string send(const std::string& msg) const override { return "email: " + msg; }
    std::string channel() const { return "smtp"; }          // hides, doesn't override
};

class Sms : public Notifier {
public:
    std::string send(const std::string& msg) const override { return "sms: " + msg.substr(0, 5); }
};

void alert(const Notifier& n) {
    std::cout << n.send("server down") << " via " << n.channel() << "\n";
}

int main() {
    alert(Notifier{});
    alert(Email{});
    alert(Sms{});
}
log: server down via base
email: server down via base
sms: serve via base

Reading the output

override

Write override after every function that's meant to replace a virtual one. The compiler then checks that a matching virtual function exists in the base. Without it, a typo or a missing const silently creates a brand new function, and the base version keeps running. With it, that's a compile error.

virtual ~Base() = default

A class meant to be used through base references or pointers needs a virtual destructor. You'll see exactly why in step 5; for now, always include it.

Your turn: make Knife and Grenade override attack, returning "slash" and "boom".

Previous: Inheritance Next: Abstract classes