References and Runtime Polymorphism
Can I use references with polymorphic classes to achieve runtime polymorphism?
Absolutely! References are a great way to achieve runtime polymorphism in C++. They allow you to work with derived class objects through base class references, enabling you to call virtual functions and get the correct derived class behavior.
Let's look at an example using our Character class from the lesson:
#include <iostream>
#include <string>
class Character {
public:
Character(const std::string& name)
: mName{name} {}
virtual void Attack() const {
std::cout << mName
<< " performs a basic attack!\n";
}
virtual ~Character() = default;
protected:
std::string mName;
};
class Warrior : public Character {
public:
Warrior(const std::string& name)
: Character{name} {}
void Attack() const override {
std::cout << mName
<< " swings a mighty sword!\n";
}
};
class Mage : public Character {
public:
Mage(const std::string& name)
: Character{name} {}
void Attack() const override {
std::cout << mName
<< " casts a powerful spell!\n";
}
};
void PerformAttack(const Character& character) {
character.Attack();
}
int main() {
Character genericChar{"Generic"};
Warrior warrior{"Conan"};
Mage mage{"Gandalf"};
PerformAttack(genericChar);
PerformAttack(warrior);
PerformAttack(mage);
}Generic performs a basic attack!
Conan swings a mighty sword!
Gandalf casts a powerful spell!In this example:
- We define a base
Characterclass with a virtualAttack()method. - We create two derived classes,
WarriorandMage, each overriding theAttack()method. - We define a
PerformAttack()function that takes aconst Character¶meter. - In
main(), we create instances of each class and pass them toPerformAttack().
The key here is the PerformAttack() function. It takes a reference to a Character, but when we call it with a Warrior or Mage, it still calls the correct overridden Attack() method. This is runtime polymorphism in action!
A few important points:
- The
Attack()method must be declaredvirtualin the base class for this to work. - We use
constreferences here as we're not modifying the objects. - It's good practice to declare a virtual destructor in the base class when using polymorphism.
References provide a clean syntax for achieving polymorphism, as you don't need to worry about dereferencing pointers. However, remember that unlike pointers, references can't be null and can't be reassigned after initialization.
References
This lesson introduces references, explaining how they work, their benefits, and their role in performance and data manipulation