Item 35: Consider alternatives to virtual functions
Concept
Virtual functions are not the only way to achieve polymorphic behavior. The Non-Virtual Interface (NVI) idiom uses a non-virtual public function that calls a private virtual function, giving the base class control over before/after logic. The Strategy pattern (via function pointers or std::function) decouples the algorithm from the class hierarchy entirely. These alternatives provide greater flexibility in controlling when and how customization occurs, and allow runtime swapping of behavior.
Code Example
#include <functional>
// NVI idiom: non-virtual interface wraps virtual implementation
class GameCharacter {
public:
int healthValue() const {
// "before" logic
int result = doHealthValue();
// "after" logic
return result;
}
virtual ~GameCharacter() = default;
private:
virtual int doHealthValue() const { return 10; }
};
// Strategy via std::function — runtime-swappable behavior
class FlexibleCharacter {
public:
using HealthCalcFunc = std::function<int(const FlexibleCharacter&)>;
explicit FlexibleCharacter(HealthCalcFunc hcf)
: healthFunc_(std::move(hcf)) {}
int healthValue() const { return healthFunc_(*this); }
private:
HealthCalcFunc healthFunc_;
};
Full source code (classic strategy)
Full source code (std::function strategy)
Things to Remember
- Alternatives to virtual functions include the NVI idiom and various forms of the Strategy design pattern. The NVI idiom is itself a form of the Template Method design pattern.
- A disadvantage of moving functionality from a member function to a function outside the class is that the non-member function lacks access to the class's non-public members.
std::functionobjects act like generalized function pointers. Such objects support all callable entities compatible with a given target signature.