zeus

Unnamed repository; edit this file 'description' to name the repository.
git clone Unknown
Log | Files | Refs

commit 338aa1a5e93c6eeb615db830455e69979ee8e335
parent e58770b0d523f37a4afaa41bf760c97091079686
author Dimitrije Dobrota < mail@dimitrijedobrota.com >
date Sat, 17 May 2025 21:14:07 +0200

Basic visitor example

Diffstat:
A visitor_basic.cpp | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

1 files changed, 144 insertions(+), 0 deletions(-)


diff --git a/ visitor_basic.cpp b/ visitor_basic.cpp

@@ -0,0 +1,144 @@

#include <cassert>
#include <iostream>
#include <memory>
#include <string>
#include <string_view>
#include <vector>

class Pet;
class Cat;
class Dog;

class PetVisitor {
public:
virtual ~PetVisitor() = default;

virtual void visit(Cat *c, Pet *p) = 0;
virtual void visit(Dog *d, Pet *p) = 0;
};

class Pet {
std::string m_color;
std::vector<Pet *> m_children;

public:
Pet(std::string_view color) : m_color(color) {}
virtual ~Pet() = default;

virtual void accept(PetVisitor &v, Pet *p = nullptr) = 0;

void add_child(Pet *p) { m_children.emplace_back(p); }

const std::string &color() const { return m_color; }
const auto &children() const { return m_children; }
};

class Cat : public Pet {
public:
using Pet::Pet;

void accept(PetVisitor &v, Pet *p = nullptr) override { v.visit(this, p); }
};

class Dog : public Pet {
public:
using Pet::Pet;

void accept(PetVisitor &v, Pet *p = nullptr) override { v.visit(this, p); }
};

class FeedingVisitor : public PetVisitor {
public:
void visit(Cat *c, Pet *p) override {
(void)p;
std::cout << "Feed tuna to the " << c->color() << " cat\n";
}

void visit(Dog *c, Pet *p) override {
(void)p;
std::cout << "Feed streak to the " << c->color() << " dog\n";
}
};

class PlayingVisitor : public PetVisitor {
public:
void visit(Cat *c, Pet *p) override {
(void)p;
std::cout << "Play with a feather with the " << c->color() << " cat\n";
}

void visit(Dog *c, Pet *p) override {
(void)p;
std::cout << "Play fetch with the " << c->color() << " dog\n";
}
};

class BirthVisitor : public PetVisitor {
public:
void visit(Cat *c, Pet *p) override {
assert(dynamic_cast<Cat *>(p));
c->add_child(p);
}

void visit(Dog *c, Pet *p) override {
assert(dynamic_cast<Dog *>(p));
c->add_child(p);
}
};

class FamilyTreeVisitor : public PetVisitor {
std::size_t m_child_count = 0;

template <typename T> void visit_impl(T *t, const char *s) {
std::cout << s << ": ";
for (const auto p : t->children()) {
std::cout << p->color() << " ";
++m_child_count;
}
std::cout << std::endl;
}

public:
void reset() { m_child_count = 0; }
auto child_count() const { return m_child_count; }

void visit(Cat *c, Pet *p) override {
(void)p;
visit_impl(c, "Kittens");
}

void visit(Dog *c, Pet *p) override {
(void)p;
visit_impl(c, "Puppies");
}
};

class Shelter {
std::vector<std::unique_ptr<Pet>> m_pets;

public:
void add(Pet *p) { m_pets.emplace_back(p); }

void accept(PetVisitor &v) {
for (auto &p : m_pets) {
p->accept(v);
}
}
};

int main() {
std::unique_ptr<Pet> p(new Cat("orange"));

std::unique_ptr<PetVisitor> v(new FeedingVisitor);
p->accept(*v);

std::unique_ptr<Pet> child(new Cat("yellow"));

std::unique_ptr<PetVisitor> b(new BirthVisitor);
p->accept(*b, child.get());

std::unique_ptr<PetVisitor> f(new FamilyTreeVisitor);
p->accept(*f);

return 0;
}