2010-01-15 2 views
3

Я ищу способ определения во время выполнения, какой тип объекта должен быть выделен (на основе заданного имени класса, которое имеет тип const char*).Как получить объект неизвестного класса с заданным именем класса

Ну, самый простой способ, конечно, заключается в использовании нагрузок if S/else if с, но это не кажется, это применимо, потому что у меня есть> 100 различных классов (ну по крайней мере, все они происходят из одного базового класса), и у меня есть регулярно добавлять новые классы.

я уже придумал первый проект, но, к сожалению оно не компилировать еще (MinGW & г ++ 4,4)

template<typename TBase, typename TDerived, typename... TArgs> 
Base* get_classobject(const char* classname) 
{ 
    if(strcmp(classname,typeid(TDerived).name())==0) 
     return new TDerived; // 
    else if(sizeof...(TArgs)>0) 
     return get_classobject<TBase,TArgs...>(classname); 
    else 
     return 0; 
} 


int main() 
{ 
    Base* obj = get_classobject<Base,A,Foo,B,C>("Foo"); 
    // ^- Types A B C and Foo are all derived from Base 
    delete obj; //of course we got an virtual dtor ;) 
    return 0; 
} 

но sizeof...(TArgs)>0 не останавливает НКУ от попыток генерации кода для get_classobject<TBase,const char*>(const char*) которая не

Есть ли у вас какие-либо идеи, как это исправить или какая-либо другая идея? Спасибо.

EDIT: я решил это:

template<typename TBase, typename TDerived> 
Base* get_classobject(const char* classname) 
{ 
    if(strcmp(classname,typeid(TDerived).name())==0) 
     return new TDerived; 
    return 0; 
} 

template<typename TBase, typename TDerived, typename TArg, typename... TArgs> 
Base* get_classobject(const char* classname) 
{ 
    if(strcmp(classname,typeid(TDerived).name())==0) 
     return new TDerived; 
    return get_classobject<TBase,TArg,TArgs...>(classname); 
} 

EDIT Для заинтересованных читателей:
Вы должны теперь, что реализация выше НЕ компилятор независимыми вообще. Вывод typeif(sometype).name() является специфическим для компилятора/реализации. Используя переменную или функцию static const char* name во всех Производных классах, исправит это, но добавит кучу работы (конечно, вы можете использовать макрос для этого, но если вы уже используете макросы, вы можете использовать другой метод фабрики объектов)

+0

Пахнет, как вам нужно внедрить заводские методы и методы «клонирования». Используя интерфейс 'clone()', вы можете создавать объекты семейства и не знать их имя класса. –

+0

Я не хочу казаться критическим, но на самом деле ... это плохо пахнет. Прежде всего использование 'typeid' довольно противоречиво, но я также хотел бы указать на неэффективность такого метода> вы выполняете поиск с линейной сложностью, и вы должны точно определить ВСЕ возможные типы, которые могли бы быть созданы. .. и я даже не хочу думать о кошмарной стоимости обслуживания. –

+0

typeid может быть легко заменен функцией static :: name, линейный поиск не является выражением, так как я только вызываю этот метод один раз (кроме того, что любой другой объект, на котором был рассмотрен объект, также имеет линейный поиск или макросы злоупотреблений) – smerlin

ответ

3

Разве вы не можете просто объявить

template<typename TBase, typename TDerived, typename TArg, typename... TArgs> 

?

Тогда вы можете специализироваться на случай

typename TBase, typename TDerived, typename TArg 
+0

не мог бы даже если я это сделаю, выполните один шаг рекурсии? – smerlin

+0

Вы пытаетесь получить параметры шаблона 1+, а не 0+ правильно? Вы можете специализировать шаблон для случая 0. –

+0

работал как шарм, как только я понял тебя. – smerlin

2

Читайте ответы над here, вы, вероятно, нужен завод.

0

Это похоже на то, что вы ищете шаблон фабрики классического объекта. Посмотрите на это stackoverflow question. Лично мне это нравится method

+0

при использовании этого шаблона вам нужно написать код самостоятельно, используя мой способ, который компилятор создает для меня;) – smerlin

+0

@smerlin Если я понимаю * ваш * путь, вам нужно будет цепочки/писать все производные классы каждый раз, когда вам нужно позвонить 'get_classobject()'. Поэтому при добавлении класса или его удалении это административный/ручной процесс. То, как я описываю, немного больше * автоматически *. В основном вам нужно только добавить две строки. METADECL в объявлении класса и METAIMPL в компиляторе (файл .cpp), предпочтительно близком к конструктору. Эта автоматическая функция этого решения - это то, что мне действительно нравится, тогда даже можно добавлять классы во время выполнения, загружая общие объекты (файлы .so/.dll). Выполнено ... – epatel

+0

Мне нужно только один раз вызвать эту функцию, и если бы мне пришлось их называть более одного раза, я бы добавил (встроенную) функцию-оболочку, так что мне нужно было только один раз написать классы – smerlin

1

Как насчет создания специализированного get_classobject() без вариационных temlates? Это остановило бы рекурсию.

У вас тогда будет одно определение с вариационным шаблоном, а другое - только template<typename TBase, typename TDerived>. Другая идея состоит в том, чтобы сделать перегрузку без шаблона, которая принимает только const char *, и возвращает 0.

+0

Уже пробовал, что все еще получил 'error: никакой подходящей функции для вызова в get_classobject (const char * &) '| ' – smerlin

Смежные вопросы