#include <iostream>
#include <list>
struct InventoryItem {
virtual ~InventoryItem() {}
};
struct Weapon: public InventoryItem {};
struct Missile: public InventoryItem {};
struct Armor: public InventoryItem {};
struct Menu {
void insert (const Weapon* weapon) {std::cout << "Menu::insert weapon called" << std::endl;}
void insert (const Missile* missile) {std::cout << "Menu::insert missile called" << std::endl;}
void insert (const Armor* armor) {std::cout << "Menu::insert armor called" << std::endl;}
} menu, anotherMenu, yetAnotherMenu;
int main() {
std::list<Weapon*> weapons = {new Weapon, new Weapon, new Weapon};
std::list<Armor*> armor = {new Armor, new Armor, new Armor};
std::list<Missile*> missiles = {new Missile, new Missile, new Missile};
/* [Won't compile because of ambiguity]
auto insertInMenus = [&](const InventoryItem* item)->void {
menu.insert(item);
// long code that uses anotherMenu.insert(x), yetAnotherMenu.insert(x), etc...
};
*/
for (const Weapon* x: weapons)
{
menu.insert(x);
// long code that uses anotherMenu.insert(x), yetAnotherMenu.insert(x), etc...
}
for (const Missile* x: missiles)
{
menu.insert(x);
// long code identical to the above (but uses a different overload of Menu::insert because x is Missile*)
}
for (const Armor* x: armor)
{
menu.insert(x);
// long code identical to the above (but uses a different overload of Menu::insert because x is Armor*)
}
std::cin.get();
}
My ideal solution was to use the local function
1 2 3 4
auto insertInMenus = [&](const InventoryItem* item)->void {
menu.insert(item);
// long code that uses anotherMenu.insert(x), yetAnotherMenu.insert(x), etc...
};
in each for-loop. That would have taken care of the repetitions nicely. But it won't compile because of ambiguity.
Note: the three overloads of Menu::insert are much more complex than above.
So I tried using virtual methods, which works. But the amount of repetition is just as much. It is only a tad better because now main() looks more elegant and shorter. Still not content with this though.
struct InventoryItem {
virtual ~InventoryItem() {}
};
struct Weapon: public InventoryItem {};
struct Missile: public InventoryItem {};
struct Armor: public InventoryItem {};
struct Menu {
void insert (const InventoryItem* item) {
if (typeid (*item) == typeid (Weapon)) {std::cout << "Menu::insert weapon called" << std::endl;}
elseif (typeid (*item) == typeid (Missile)) {std::cout << "Menu::insert missile called" << std::endl;}
elseif (typeid (*item) == typeid (Armor)) {std::cout << "Menu::insert armor called" << std::endl;}
}
} menu, anotherMenu, yetAnotherMenu;
int main() {
std::list<Weapon*> weapons = {new Weapon, new Weapon, new Weapon};
std::list<Armor*> armor = {new Armor, new Armor, new Armor};
std::list<Missile*> missiles = {new Missile, new Missile, new Missile};
auto insertInMenus = [&](const InventoryItem* item) {
menu.insert (item);
// And now the long code that was being repeated:
// ...
anotherMenu.insert (item);
// ...
yetAnotherMenu.insert (item);
// ...
};
for (const Weapon* x: weapons)
insertInMenus(x);
for (const Missile* x: missiles)
insertInMenus(x);
for (const Armor* x: armor)
insertInMenus(x);
std::cin.get();
}
It gives the correct output. But I've been told that virtual methods is better than using multiple if-statements (that were prevalent in the 80's before virtual methods came around), and downgrades performance due to the constant multiple checking.