design patterns · advanced
Visitor Pattern
Visitor is a behavioral GoF pattern that represents an operation to perform on the elements of an object structure, letting you define a new operation without changing the element classes. Instead of editing every Shape class each time you add area, render, or export, you gather one operation across all node types into a Visitor class — so adding an operation means adding a class and the element hierarchy is never reopened. It works by double dispatch, where the executed method depends on two runtime types (the element's and the visitor's): since C++ virtual calls dispatch on only one object, each element implements accept(Visitor&) which calls v.visit(*this) — inside accept, *this has the element's concrete static type so it selects the correct visit() overload, and v is virtual so it lands in the right visitor, giving two virtual hops. Pros: operations are added freely without touching nodes, and a visitor can accumulate state across an entire traversal (summing areas, building an export buffer). The central trade-off and main con: adding a new NODE type is expensive because you must add a visit() to the Visitor interface and update every existing visitor — so Visitor is Open/Closed for operations but closed for elements, the inverse of a normal hierarchy. It also requires an intrusive accept() on every node and can break encapsulation. Use it when the element set is stable but operations keep growing (compiler AST passes, fixed shape kinds); the modern C++ alternative for a closed node set is std::variant with std::visit.
Visitor (behavioral): add NEW operations to a class hierarchy WITHOUT editing it, by writing a visitor class with one visit() per node type. Uses DOUBLE DISPATCH — element.accept(v) calls v.visit(*this), so the method chosen depends on both the element's concrete type and the visitor's. Open/Closed for operations (new op = new class) but costly for new nodes (touch every visitor). Use when the node set is stable and operations keep growing (AST passes); std::variant+std::visit is the closed-set modern alternative.
The code
// Visitor — add NEW operations to a class hierarchy without editing it,// using DOUBLE DISPATCH (the type of the node AND the type of the op).struct Circle;struct Square;struct Visitor { // one method per concrete node virtual void visit(Circle&) = 0; virtual void visit(Square&) = 0; virtual ~Visitor() = default;};
struct Shape { virtual void accept(Visitor& v) = 0; // the dispatch hook virtual ~Shape() = default;};struct Circle : Shape { void accept(Visitor& v) override { v.visit(*this); }};struct Square : Shape { void accept(Visitor& v) override { v.visit(*this); }};
// A NEW operation = a NEW visitor class. Shapes are untouched.struct AreaVisitor : Visitor { double total = 0; void visit(Circle& c) override { total += /* π r² */ 0; } void visit(Square& s) override { total += /* a² */ 0; }};// for (auto& s : shapes) s->accept(area); // visits the right overloadWhat this lesson walks through
- 01Intent — add operations without editing the classes
- 02Mechanism — double dispatch via accept()
- 03New operation = new visitor, zero element edits
- 04Gotcha — easy new ops, HARD new elements
Visitor lets you add new operations to a class hierarchy WITHOUT modifying those classes. Instead of scattering area(), export(), render() across every shape, each operation becomes a Visitor that visits the shapes.
See it animated — step by step, at your own pace
Unlock the full interactive walkthrough of Visitor Pattern and 100+ animated C++ interview lessons.