Visitor Pattern
Intent
Section titled “Intent”Represent an operation to be performed on the elements of an object structure. Visitor lets you define a new operation without changing the classes of the elements on which it operates.
— Design Patterns: Elements of Reusable Object-Oriented Software
The visitor pattern is well-suited for extending operations but poorly suited for extending types. It follows the Open Closed Principle in regard to operations, but not types.
Styles
Section titled “Styles”Classic Visitor
Section titled “Classic Visitor”The classic style is outdated due to its many disadvantages:
- Two inheritance hierarchies (intrusive)
- Two virtual function calls per operation (performance cost)
- Many pointers (indirections, performance cost)
- Promotes dynamic memory allocation
- Many small manual allocations
- Need to manage lifetime explicitly (e.g. use unique_ptr)
- Danger for lifetime related bugs with pointers
Modern Visitor Style using std::variant (C++17)
Section titled “Modern Visitor Style using std::variant (C++17)”The std::variant visitor style enables value semantics. This makes it much simpler than the classic visitor style.
- No base class, no pointers, no virtual functions, just values.
- Polymorphism without the complexity of an inheritance hierarchy
struct Draw { void operator()(const Circle& c) const { // ... } void operator()(const Square& s) const { // ... }};// ...using Shape = std::variant<Circle, Square>;// ...for (auto const& shape : shapes) { std::visit( Draw{}, shape);}