trainings/CreatingReliableSoftwareCpp/Presentation/examples/visitor/visitor4.cpp

113 lines
2.8 KiB
C++

#include <algorithm>
#include <cassert>
#include <functional>
#include <iostream>
#include <memory>
#include <set>
#include <variant>
#include <vector>
class AbstractVisitor;
class Ammunition {
public:
Ammunition(size_t amount)
: _amount(amount) {}
virtual ~Ammunition() = default;
virtual void accept(const AbstractVisitor&) = 0;
size_t amount() const { return _amount; }
private:
size_t _amount = 0;
};
class RoundShot;
class ChainShot;
class GrapeShot;
class AbstractVisitor {
protected:
// Can be only use by derived class
virtual ~AbstractVisitor() = default;
};
template <typename T>
class Visitor {
public:
virtual void visit(const T& shot) const = 0;
protected:
virtual ~Visitor() = default;
};
class DamageVisitor : public AbstractVisitor,
public Visitor<RoundShot>,
public Visitor<ChainShot>,
public Visitor<GrapeShot> {
public:
void visit(const RoundShot& shot) const override {
std::cout << "Round shot make 20 damages\n";
}
void visit(const ChainShot& shot) const override {
std::cout << "Chain shot make 30 damages\n";
}
void visit(const GrapeShot& shot) const override {
std::cout << "Grape shot make 40 damages\n";
}
};
class SoundVisitor : public AbstractVisitor,
public Visitor<RoundShot>,
public Visitor<ChainShot>,
public Visitor<GrapeShot> {
public:
void visit(const RoundShot& shot) const override {
std::cout << "Fiuuuuuuuu Bam!\n";
}
void visit(const ChainShot& shot) const override {
std::cout << "Fiuuuuuuuuuuu Bam bam!\n";
}
void visit(const GrapeShot& shot) const override {
std::cout << "Fiuuuuuuuuuuu Bam bam bam bam bam!\n";
}
};
class RoundShot : public Ammunition {
public:
using Ammunition::Ammunition;
void accept(const AbstractVisitor& visitor) {
if (const auto* v = dynamic_cast<const Visitor<RoundShot>*>(&visitor)) {
v->visit(*this);
}
}
};
class ChainShot : public Ammunition {
public:
using Ammunition::Ammunition;
void accept(const AbstractVisitor& visitor) {
if (const auto* v = dynamic_cast<const Visitor<ChainShot>*>(&visitor)) {
v->visit(*this);
}
}
};
class GrapeShot : public Ammunition {
public:
using Ammunition::Ammunition;
void accept(const AbstractVisitor& visitor) {
if (const auto* v = dynamic_cast<const Visitor<GrapeShot>*>(&visitor)) {
v->visit(*this);
}
}
};
int main() {
std::unique_ptr<Ammunition> grapeShot = std::make_unique<GrapeShot>(100);
SoundVisitor soundVisitor;
DamageVisitor damageVisitor;
grapeShot->accept(soundVisitor);
grapeShot->accept(damageVisitor);
}