zeusUnnamed repository; edit this file 'description' to name the repository. |
git clone Unknown |
Log | Files | Refs |
factory_virtual_ctor.cpp (3108B)
0 #include <cstddef>
1 #include <functional>
2 #include <memory>
3 #include <vector>
5 class Unit {};
6 class Knight : public Unit {};
7 class Mage : public Unit {};
9 // allows the factory function to have one concrete signature
10 struct BuildingSpec {};
12 class Building {
13 // register type_id in runtime
14 static std::size_t type_count;
16 using BuildingFactory = std::function<Building *(const BuildingSpec &)>;
17 static std::vector<BuildingFactory> registry;
19 public:
20 virtual ~Building() = default;
22 static std::size_t Register(BuildingFactory factory) {
23 registry.emplace_back(std::move(factory));
24 return type_count++;
25 }
27 static auto Make(std::size_t type, const BuildingSpec &spec) {
28 return std::unique_ptr<Building>(registry[type](spec));
29 }
31 virtual Unit *MakeUnit() const = 0;
32 virtual std::unique_ptr<Building> Clone() const = 0;
33 };
35 std::vector<Building::BuildingFactory> Building::registry;
36 std::size_t Building::type_count = 0;
38 // CRTP to avoid rudundant Clone methods
39 template <typename Derived> class BuildingCloner : public Building {
40 public:
41 std::unique_ptr<Building> Clone() const override {
42 return std::unique_ptr<Building>(
43 new Derived(*static_cast<const Derived *>(this)));
44 }
45 };
47 // Builder for concrete BuildingSpec
48 struct CastleSpec : BuildingSpec {
49 bool with_pasture = false;
50 int number_of_stalls = 0;
52 CastleSpec() = default;
54 CastleSpec &SetPasture(bool with_pasture) {
55 this->with_pasture = with_pasture;
56 return *this;
57 }
59 CastleSpec &SetStalls(int number_of_stalls) {
60 this->number_of_stalls = number_of_stalls;
61 return *this;
62 }
63 };
65 // Concrete Building that needs a tag and a way to make units
66 class Castle : public BuildingCloner<Castle> {
67 public:
68 static const size_t type_tag;
70 explicit Castle(const CastleSpec &spec) { /* ... */ }
72 Knight *MakeUnit() const override { return new Knight; }
73 };
75 const size_t Castle::type_tag =
76 Building::Register([](const BuildingSpec &spec) -> Building * {
77 return new Castle(static_cast<const CastleSpec &>(spec));
78 });
80 struct TowerSpec : BuildingSpec {
81 bool with_magic = false;
82 int number_of_apprentices = 0;
84 TowerSpec() = default;
86 TowerSpec &SetMagic(bool with_magic) {
87 this->with_magic = with_magic;
88 return *this;
89 }
91 TowerSpec &SetApprentices(int number_of_apprentices) {
92 this->number_of_apprentices = number_of_apprentices;
93 return *this;
94 }
95 };
97 class Tower : public BuildingCloner<Tower> {
98 public:
99 static const size_t type_tag;
101 explicit Tower(const TowerSpec &spec) { /* ... */ }
103 Mage *MakeUnit() const override { return new Mage; }
104 };
106 const size_t Tower::type_tag =
107 Building::Register([](const BuildingSpec &spec) -> Building * {
108 return new Tower(static_cast<const TowerSpec &>(spec));
109 });
111 int main() {
112 const auto castle = Building::Make(
113 Castle::type_tag, CastleSpec{}.SetPasture(true).SetStalls(5));
114 const auto castle2 = castle->Clone();
116 const auto tower = Building::Make(
117 Tower::type_tag, TowerSpec{}.SetMagic(false).SetApprentices(2));
118 const auto tower2 = castle->Clone();
120 return 0;
121 }