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
sendisvirtual, soalertcalls the real object's version: log, email and sms.channelis not virtual, so through aNotifier&it's always the base version, even for anEmail. That's almost never what you want in a class hierarchy.
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 task
Make Knife and Grenade override attack, returning "slash" and "boom".
Challenge 2
Player::status() is not virtual, but it calls the virtual max_hp(), so each class's own version is used. Make Heavy report a max of 200 and Scout a max of 75 by overriding max_hp.
Challenge 3
Write Rifle and Sniper, both deriving from Weapon and overriding damage(int distance). A rifle does 30 minus 1 for every full 10 units of distance, but never less than 10. A sniper always does 115. Mark Sniper as final so nothing can derive from it.