Member Function Pointers vs Virtual Functions
Why would we use member function pointers instead of virtual functions when we want to change behavior at runtime?
Member function pointers and virtual functions serve different purposes when it comes to runtime behavior modification. Here's why you might choose one over the other:
Virtual Functions
Virtual functions are best when you have a fixed set of behaviors that vary based on the type of object:
class Character {
public:
virtual void Attack() {
std::cout << "Basic attack\n";
}
};
class Warrior : public Character {
public:
void Attack() override {
std::cout << "Sword attack\n";
}
};
Member Function Pointers
Member function pointers are more flexible when you need to:
- Change behavior without inheritance
- Swap behaviors at runtime
- Store multiple behaviors per object
- Configure behavior through data rather than code
Here's an example:
#include <iostream>
class Character {
public:
using AttackFunc = void (Character::*)();
void SetAttack(AttackFunc NewAttack) {
CurrentAttack = NewAttack;
}
void ExecuteAttack() {
(this->*CurrentAttack)();
}
void SlashAttack() {
std::cout << "Slash attack!\n";
}
void FireballAttack() {
std::cout << "Fireball attack!\n";
}
private:
AttackFunc CurrentAttack{
&Character::SlashAttack};
};
int main() {
Character player;
player.ExecuteAttack();
player.SetAttack(&Character::FireballAttack);
player.ExecuteAttack();
}
Slash attack!
Fireball attack!
The key differences are:
- Virtual functions are resolved through the vtable at runtime based on the actual type
- Member function pointers can be changed dynamically for any instance
- Virtual functions require inheritance hierarchy
- Member function pointers work with any compatible function signature
Choose virtual functions when behavior is tied to type hierarchy, and member function pointers when you need more dynamic behavior switching or configuration-based behavior selection.
Pointers to Members
Learn how to create pointers to class functions and data members, and how to use them