Вы можете использовать заводскую функцию.В сочетании с глобальными статическими объектами для регистрации типов.Примерно так:
// in some main file...
typedef CMonster*(*create_ptr)();
std::map<std::string, create_ptr> &get_map() {
// so we can make sure this exists...
// NOTE: we return a reference to this static object
static std::map<std::string, create_ptr> map;
return map;
}
мы добавили немного кода для регистрации функции создания ...
// in each type of monster class (ex: CMonsterA)
CMonster *create_monster_a() {
return new CMonsterA;
}
static struct monsterA_Registrar {
monsterA_Registrar() {
get_map().insert(std::make_pair("MonsterA", create_monster_a));
}
} register_monsterA;
наконец, вернувшись в основной файл, вы можете создать монстримя его типа ...
std::map<std::string, create_ptr>::iterator it = get_map().find("MonsterA");
if(it != get_map().end()) {
return (it->second)();
}
throw "invalid monster type requested";
Вот что происходит:
Когда программа запускается до main, она запускает все конструкторы глобальных объектовв данном случае register_monsterA
является одним из них.
Конструктор этого объекта получит get_map()
(это не может быть просто глобальный static
, потому что у нас нет способа узнать, в каком порядке объекты инициализируютсяесли мы это сделаем, значит, это функция).
Затем он добавит к ней элемент, который является «функцией создания», в основном функцией, способной создать новый CMonster
.
Наконец, чтобы сделать монстра, мы просто смотрим на ту же карту, получаем функцию создания и запускаем ее (если она была).
РЕДАКТИРОВАТЬ: Вот полный рабочий пример ... (с некоторой макро-магией, чтобы сделать его чище)
CMonster.h
class CMonster {
public:
virtual ~CMonster() {
}
virtual void roar() = 0;
};
typedef CMonster*(*create_ptr)();
std::map<std::string, create_ptr> &get_map();
#define MONSTER_REGISTRAR(name) \
CMonster *create_monster_##name() { \
return new C##name; \
}\
\
static struct monster##name##_Registrar {\
monster##name##_Registrar() { \
get_map().insert(std::make_pair(#name, create_monster_##name));\
} \
} register_monster##name;
CMonster.cc
std::map<std::string, create_ptr> &get_map() {
// so we can make sure this exists...
// NOTE: we return a reference to this static object
static std::map<std::string, create_ptr> map;
return map;
}
CMonsterA.cc
#include "CMonster.h"
class CMonsterA : public CMonster {
public:
CMonsterA() {
std::cout << "HERE - A" << std::endl;
}
virtual void roar() {
std::cout << "A" << std::endl;
}
};
MONSTER_REGISTRAR(MonsterA)
CMonsterB.cc
#include "CMonster.h"
class CMonsterB : public CMonster {
public:
CMonsterB() {
std::cout << "HERE - B" << std::endl;
}
virtual void roar() {
std::cout << "B" << std::endl;
}
};
MONSTER_REGISTRAR(MonsterB)
main.cc
#include "CMonster.h"
CMonster *get_monster(const std::string &name) {
std::map<std::string, create_ptr>::iterator it = get_map().find(name);
if(it != get_map().end()) {
return (it->second)();
}
throw "invalid monster type requested";
}
int main() {
CMonster *monster = get_monster("MonsterB");
monster->roar();
delete monster;
}