Модераторы: Daevaorn

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Динамическое создание объекта, причем класс определяется при выполнении 
:(
    Опции темы
dAnIK SeNT
Дата 4.6.2003, 23:23 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 9
Регистрация: 8.2.2003
Где: Казань

Репутация: нет
Всего: нет



Дано:
класс base_class.
производные от него классы
child_xxxxxx
где xxxxx - чего-нибудь. например
child_first
child_second
child_third

функция типа
base_class *create_object(char *obj_type) {
}

obj_type - это как раз содержимое ххх, т.е. напрмер вызываем:

base_class *bc = create_object("first");

такой вызов должен создать объект типа child_first и вернуть указатель на него.

это вообще реально?
PM MAIL WWW   Вверх
acp
Дата 4.6.2003, 23:33 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 389
Регистрация: 4.2.2003
Где: Владимир

Репутация: нет
Всего: 2




Как следует из понимания ООП, то родителю можно присваивать потомка. Но в вышенаписанном тобой случае, по всей видимости, тебе функция всё время будет возвращать родителя, а никак не потомка.
Тут возможны два решения
1. или перегрузка функций
2. или void* (вроде так)

PM WWW ICQ   Вверх
RAN
Дата 5.6.2003, 08:39 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Экс. модератор
Сообщений: 709
Регистрация: 14.3.2003
Где: Щёлково Моск.обл.

Репутация: 5
Всего: 6



acp, а где ты функцию увидел, человек только её определение привёл. Не известно что это функция делает.

dAnIK SeNT, поищи какое-нибудь другое решение. Так как-то странно получается. Но это возможно за одним "но". Нельзя получив char* добавить вначале "child_" и создать такой класс, можно лишь написать код, в котором сам будешь по char* определять какой класс создать:

base_class *create_object(char* obj_type)
{
if(strcmp(obj_type, "first")) return new child_first;
return NULL;
}

Однако лучше это делать через константы. Определи в .h define'ы для каждого класса и тогда используй switch

#define CHILD_FIRST 1
#define CHILD_SECOND 2

base_class *create_object(int obj_type)
{

switch(obj_type) {
case CHILD_FIRST:
return new child_first;
case CHILD_SECOND:
return new child_second;
default:
return NULL;
}

}

И ещё раз ты возвращаешь base_class*, то будешь "видеть" в child_first только виртуальные функции.

Это сообщение отредактировал(а) RAN - 5.6.2003, 08:40
PM MAIL ICQ   Вверх
acp
Дата 5.6.2003, 08:44 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 389
Регистрация: 4.2.2003
Где: Владимир

Репутация: нет
Всего: 2



Цитата
acp, а где ты функцию увидел, человек только её определение привёл. Не известно что это функция делает.



Зато видно, что эта функция возвращает. Разве этого не достаточно?

PM WWW ICQ   Вверх
vickr
Дата 5.6.2003, 08:59 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 183
Регистрация: 13.5.2003
Где: Санкт-Петербург

Репутация: нет
Всего: нет



С acp не совсем согласен. Указателю на родителя можно присваивать указатель на потомка (в свое время при мзучении модели СОМ и множественного наследования интерфейсов для меня это тоже было откровением smile.gif), но нужно делать преобразование типа.
RAN Привел вполне подходящее решение. Разумеется, для фиксированного набора дочерних классов. Строки или константы - это уже дело вкуса, в принципе, константы разумнее, согласен.
В качестве альтернативы можно предложить использовать шаблон ф-и, типа
Код

template<class TChild>
base_class *create_object()
{
       return static_cast<base_class*>(new TChild);
}

Сразу оговорюсь - это первое, что пришло в голову и поэтому привожу код как информацию к размышлению. Писалось прямо здесь.
Экспериментируйте, уважаемые smile.gif
--------------------
Каждую секунду, тыкая в клавиши, мы давим насмерть не менее 1000 микробов =:)
PM MAIL   Вверх
Unregistered
Дата 5.6.2003, 13:09 (ссылка)    |    (голосов: 0) Загрузка ... Загрузка ... Быстрая цитата Цитата


Unregistered











Нужно использовать патерн "Фабрика классов"
Будет это выглядеть примерно так. Под рукой хелпов и компиляторов нет, поэтому наверняка будут ошибки(особенно в по отношению stl)

Код

//нижеследующий код менять при появлении нового класса не требуется
class TBaseClass;
typedef  TBaseClass* (*TCreateFunction)(void);
typedef   map<string, TCreateFunction>  TFunctionMap;
class TBaseClass
{
public:
  TBaseClass(){}
  static string ClassName( ) {return string("BaseClass");}
  static  TBaseClass* Create(void) { return new TBaseClass; }
};

class FabricClass
{
private:
 TFuctionMap m_Map;
public:
 static void Register(string str, TFunctionMap fun)
 {
       m_Map.insert(str, fun);
 }
 static TBaseClass* Create(string str)
 {
    TFunctionMap::iterator i = m_Map.find(str);
     if (i)
     {
        TFunctionMap func = i.second;
        return (*func)();
     }
     return NULL;  
 }
}  
//здесь кончается неизменяемый код

// далее идет только то, что касается  конкретно классов

class TBaseClass1 : public TBaseClass
{
public:
  TBaseClass1():TBaseClass(){}
  static string ClassName( ) {return string("BaseClass1");}
  static  TBaseClass* Create(void) { return new TBaseClass1; }
};

class TBaseClass2 : public TBaseClass
{
public:
  TBaseClass2():TBaseClass(){}
  static string ClassName( ) {return string("BaseClass2");}
  static  TBaseClass* Create(void) { return new TBaseClass2; }
};

//теперь используем
//сначала регистрация классов в фабрике

TFabricClass::Register(TBaseClass::ClassName(); &(TBaseClass::Create));
TFabricClass::Register(TBaseClass1::ClassName(); &(TBaseClass1::Create));
TFabricClass::Register(TBaseClass2::ClassName(); &(TBaseClass2::Create));

TBaseClass* base = TFabricClass::Create(string("BaseClass"));
TBaseCalss* base1 = TFabricClass::Create(string("BaseClass1"));
TBaseCalss* base2 = TFabricClass::Create(string("BaseClass2"));


Думаю, смысл понятен.

  Вверх
Vyacheslav
Дата 5.6.2003, 13:12 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Экс. модератор
Сообщений: 2124
Регистрация: 25.3.2002
Где: Москва

Репутация: 9
Всего: 59



Предыдуший пост о фабрике классов - мой


--------------------
С уважением, Вячеслав Ермолаев
PM MAIL WWW ICQ   Вверх
dAnIK SeNT
Дата 5.6.2003, 13:36 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 9
Регистрация: 8.2.2003
Где: Казань

Репутация: нет
Всего: нет



2All
спасибо за ответы smile.gif. теперь по порядку.

Цитата
base_class *create_object(char* obj_type)
{
if(strcmp(obj_type, "first")) return new child_first;
return NULL;
}

это я понимаю. хотелось бы автоматизировать процесс.

Цитата
Однако лучше это делать через константы. Определи в .h define'ы для каждого класса и тогда используй switch
...

я бы так и сделал smile.gif. но этот пример почти не отличается от предыдущего smile.gif.

Цитата
И ещё раз ты возвращаешь base_class*, то будешь "видеть" в child_first только виртуальные функции.

конечно. интерфейс у всех этих классов одинаковый - описанный в абстрактном базовом классе.

2Vyacheslav
сходу в код не въехал (только начинаю работать с С++ smile.gif). но, похоже, это как раз то что мне надо. спасибо smile.gif
PM MAIL WWW   Вверх
DENNN
Дата 5.6.2003, 14:16 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Участник Клуба
Сообщений: 3878
Регистрация: 27.3.2002
Где: Москва

Репутация: 1
Всего: 43



Можно предложить альтернативу шаблонному описанию класса - макрос
Код

#define FABRIC(cl_type) \
new cl_type;\

void main (void)
{
base_class* pclass[2];
//создаем first
pclass[1]=FABRIC (first)
//создаем second
pclass[1]=FABRIC (second)

}


Это сообщение отредактировал(а) DENNN - 5.6.2003, 14:16
PM ICQ   Вверх
RAN
Дата 6.6.2003, 00:33 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Экс. модератор
Сообщений: 709
Регистрация: 14.3.2003
Где: Щёлково Моск.обл.

Репутация: 5
Всего: 6



Vyacheslav, а от куда от термин "фабрика классов", я хотел бы почитать об этом, чтоб понять где это используют. Вообще мне кажется, что это лишнее, но это моё мнение. Ведь если приглядеться, то это тоже самое сравнение строк, только после сравнения не сразу создаётся класс, а вызывается static функция, которая создаёт класс. А вот идея DENNNа мне понравилась, но скорее всего имя класса dAnIK SeNT хотел создавать динамически.

Acp, ты сам написал, что родителю можно присваисать потомка. Между прочим это активно использовалось в OWL, но это было давно...

Это сообщение отредактировал(а) RAN - 6.6.2003, 00:59
PM MAIL ICQ   Вверх
Vyacheslav
Дата 6.6.2003, 09:30 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Экс. модератор
Сообщений: 2124
Регистрация: 25.3.2002
Где: Москва

Репутация: 9
Всего: 59



RAN
Основное примущество предложенного мною метода в том, что коды TBaseClass и TFabricClass не требуют модификации при добавлении новых классов, т.е. мы в принципе можем это вынести в ядро нашей системы (например dll) и забыть. Что же касается фабрики классов, действительно простешая фабрика классов предстваляет собой функцию с набором if, типа
Код

TBaseClass* CreateClass(AnsiString str)
{
  if (str == "BaseClass") return new TBaseClass;
  if (str == "BaseClass1") return new TBaseClass1;
  if (str == "BaseClass2") return new TBaseClass2;
  return NULL;
}

Но у нее есть недостаток - при появленнии нового класса эту функцию надо править. Что же касается патеррнов программирования, советую обратить внимание на книгу Приемы объектно-ориентированного проектирования. Паттерны проектирования Э. Гамма, Р. Хелм, Р. Джонсон, Дж. Влиссидес



--------------------
С уважением, Вячеслав Ермолаев
PM MAIL WWW ICQ   Вверх
DENNN
Дата 8.6.2003, 15:36 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Участник Клуба
Сообщений: 3878
Регистрация: 27.3.2002
Где: Москва

Репутация: 1
Всего: 43



Термин "фабрика классов" активно используется в COM-технологии. Там это действительно "фабрика классов", так как клиент абсолютно не участвует в механизме создания запрашиваемых объектов, а лишь использует их и управляет временем жизни. Такая технология очень удобна при создании "распределенных приложений". В твоем примере такой метод построения может обеспечить некоторый "запас прочности кода" при дальнейшем усовершенствовании.
PM ICQ   Вверх
Vyacheslav
Дата 9.6.2003, 09:30 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Экс. модератор
Сообщений: 2124
Регистрация: 25.3.2002
Где: Москва

Репутация: 9
Всего: 59



"Фабрика классов" - это не порождение COM, а лишь одна из многочисленных реализаций известного паттерна. К тому же на мой вгляд, незачем применять технологию COM, если в этом нет особой необходимости.



--------------------
С уважением, Вячеслав Ермолаев
PM MAIL WWW ICQ   Вверх
RAN
Дата 10.6.2003, 07:46 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Экс. модератор
Сообщений: 709
Регистрация: 14.3.2003
Где: Щёлково Моск.обл.

Репутация: 5
Всего: 6



Цитата
К тому же на мой вгляд, незачем применять технологию COM, если в этом нет особой необходимости.

Может ты и прав, но кто нас спрашивает, дядиньки из MicroSoft сказали надо, значит надо. Это теперь стандарт.
PM MAIL ICQ   Вверх
Fantasist
Дата 10.6.2003, 16:51 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Лентяй
***


Профиль
Группа: Участник Клуба
Сообщений: 1517
Регистрация: 24.3.2002

Репутация: 4
Всего: 41



Цитата
Может ты и прав, но кто нас спрашивает, дядиньки из MicroSoft сказали надо, значит надо. Это теперь стандарт


А что, дядиньки из MicroSoft сказали, что надо применять COM даже там, где это не нужно? smile.gif


--------------------
Волны гасят ветер...
PM MAIL   Вверх
Ответ в темуСоздание новой темы Создание опроса
Правила форума "С++:Общие вопросы"
Earnest Daevaorn

Добро пожаловать!

  • Черновик стандарта C++ (за октябрь 2005) можно скачать с этого сайта. Прямая ссылка на файл черновика(4.4мб).
  • Черновик стандарта C (за сентябрь 2005) можно скачать с этого сайта. Прямая ссылка на файл черновика (3.4мб).
  • Прежде чем задать вопрос, прочтите это и/или это!
  • Здесь хранится весь мировой запас ссылок на документы, связанные с C++ :)
  • Не брезгуйте пользоваться тегами [code=cpp][/code].
  • Пожалуйста, не просите написать за вас программы в этом разделе - для этого существует "Центр Помощи".
  • C++ FAQ

Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, Earnest Daevaorn

 
1 Пользователей читают эту тему (1 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | C/C++: Общие вопросы | Следующая тема »


 




[ Время генерации скрипта: 0.0899 ]   [ Использовано запросов: 21 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.