Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате |
Форум программистов > C/C++: Для новичков > Массив разных объектов-наследников (pointers?) |
Автор: KasMP 16.7.2009, 16:34 | ||||
Доброе время суток снова, мои замечательные винградовцы ![]() Предполагается уже знакомая многим структура базовых и производных классов (указываю только защищенные члены, содержащие данные - в функциях ничего интересного нет; есть чисто виртуальные функции; color - выше определенная структура: struct color (r,g,b;)):
В файле удобным для нас (и соответствующим иерархии классов) образом заданы фигуры типов Point, Line, Ellipse, Rectangle (но сам порядок перечисления фигур мы менять не можем, мы можем выбрать только способ задания конкретной фигуры); можно указать и общее количество фигур. Например, как-то так:
Как несложно увидеть, мы знаем только общее количество фигур и не знаем заранее ни тип следующей фигуры, ни общее число фигур какого-то типа. Собственно, в чем проблема... Надо "просто" создать их этих объектов-фигур какую-то ... массивообразную структуру (т.е. так, чтобы с помощь индекса от 0 до n-1 мы могли обратиться к любому объекту, прочитать содержимое его членов, изменить его, поменять местами с каким-то другим элементом с известным номером). Понятно, что все это связано с указателями на базовый класс - это основы динамического полиморфизма. Можно было бы разбить файл на 4 условных части (сначала кол-во Point и их описания, потом кол-во Line и их описания, потом ... ) и создать 4 массива... Но это уже слишком упрощает задачу программиста и резко ограничивает свободу пользователя в выборе z-order-а фигур (предполагается, что изначально фигуры накладываются друг на друга в том порядке, в котором читаются; порядок сохраняется в бинарное дерево (как именно, я пока не думала) и потом может изменяться). Я думала создать массив из указателей на Figure (должно получиться - размер одного указателя известен, а знать размер наследника Figure (или самого Figure) нам не нужно) узнать тип следующей фигуры взять временную переменную такого типа, прочитать в нее данные из файла скопировать данные этой переменной туда, куда показывает указатель текущего цикла Но, естественно, ничего не получилось: указатель-то на Figure и копируются только те члены, которые есть в Figure, а специальные уточняющие члены (точки для Point и Line, цвет кисти и прямоугольник для FilledFigure) не появляются и просто опускаются... Как можно на лету узнать тип (с этим мы справимся - в файле написано) и создать именно такой элемент массива? Не могу догадаться... |
Автор: Леопольд 16.7.2009, 19:00 | ||||||
Я добавил бы виртуальный деструктор в Base, на случай, если будущие наследники освобождают память в деструкторе. Особенно если учесть отказ от "умных" указателей.
Мне кажется, что Factory желательно оформить как singleton. |
Автор: azesmcar 16.7.2009, 19:14 | ||
Это всего лишь пример написаный на скорую руку, думаю что использование виртуального деструктора здесь очевидно. А умные указатели убрал чтобы топикстартеру было легче понять код и чтобы потом не мучалась с хранением auto_ptr -а (именно он был использован как default smart pointer в параметре шаблона) в контейнере. С чего это? А если потом две фабрики понадобиться весь код менять? Нафиг надо. |
Автор: Леопольд 16.7.2009, 19:33 | ||
Если это будут две разные фабрики patterns::Factory<Base> factoryB; patterns::Factory<AnotherBase> factoryA; То это не проблема. А зачем две одинаковых? Проблема может быть из-за того что это не чистая фабрика, она ещё и память чистит. Я бы вынес это из фабрики. И пользовался бы shared_ptr<Base> в качестве возвращаемого значения Create. |
Автор: mes 16.7.2009, 19:42 |
т.с. будет сильно рада. Вопрос в разделе новичков и сразу шаблонами по голове. ![]() KasMP, В общем для реализации обычной фабрики, о которой шла речь выше, надо несколько Create-функций (одинаковой сигнатуры), поместить в (ассоциативный) массив и потом по названию/индексу вызывать подходящую функцию. Create-функцию зачастую удобно оформлять как статическую в классе, объект которого она создает. Добавлено @ 19:44 синглетоны следует применять только тогда, когда они необходимы..(т.е. нет другого варианта или он проблематичен). Одним словом не стоит ими сильно увлекаться ![]() |
Автор: azesmcar 16.7.2009, 19:44 | ||
Может понадобиться. Например в многопоточном приложении.
Эти фабрики...они такие ![]() |
Автор: Леопольд 16.7.2009, 19:51 | ||||||
Если она только "плодит" объекты, то вроде нет проблем... Добавлено через 1 минуту и 3 секунды
Мне кажется что shared_ptr тоже достаточно прост. ![]() |
Автор: Леопольд 16.7.2009, 20:17 | ||
Показалось что она ещё и удаляет все созданные ей объекты. Был неправ, каюсь... ![]() |
Автор: mes 16.7.2009, 20:46 |
с таким подходом у новичков можно вызвать страх и отвращение к паттернам. Хотя на самом деле большинство и них элементарны по сути. ![]() |
Автор: azesmcar 16.7.2009, 21:42 | ||
Проблема есть. Поищи в гугле std::map thread safety issues.
А надо скрывать что это патерны ![]() |
Автор: KasMP 17.7.2009, 07:49 | ||||||||||||
Ух ты, сколько тут всего написали ![]() ![]() ![]() ![]()
Вообще говоря, с шаблонами у меня все не так плохо и страшно, как можно подумать ![]() ![]()
Как всегда, мне понятно каждое слово и вообще понятно. Благодарю ![]()
Я вчера увидела у Герберта Шилдта главу 22 с гордым названием "динамическая идентификация типа и операторы приведения" (удивительно, что заметить ее раньше я не смогла ![]() ![]()
Да, понятно ![]()
Спасибо ![]() Правда, можно было бы не убирать совсем, а оставить 2 варианта ![]() Леопольд, странно, что репутация у тебя такая отрицательная (а репа даже в "-1" уже настораживает форумчан). Спасибо за все твои старания ![]() |
Автор: jonie 17.7.2009, 08:02 |
еще есть boost::serialization - готовый к использованию сериализатор\десериализатор с различными форматтерами (простой для использования) раз пошла такая пьянка ....может стоит взглянуть на него. |
Автор: Леопольд 17.7.2009, 08:19 | ||
Мне надо "общаться" только в трезвом состоянии. А то бываю черезчур резок, если спровоцирвать... ![]() |
Автор: azesmcar 17.7.2009, 08:53 | ||||||
Добавил комментарии (в первом посте). Надеюсь поможет (с английским хорошо?), если что - спрашивайте, не стесняйтесь.
Ну, о шаблонах в книгах для новичков практически ничего не написано.
Тут была тема про совмещение умных указателей и фабрики. http://forum.vingrad.ru/forum/topic-250892/hl/factory/0.html чтобы глаза не мозолить лишними страницами кода ![]() |
Автор: Andrew121 17.7.2009, 09:01 |
Прошу прощения за оффтоп. В этом: http://forum.vingrad.ru/index.php?showtopic=266893&view=findpost&p=1923072 посте я насчитал 13 смайликов. Значит довольна. Не зря старались ![]() |
Автор: Леопольд 17.7.2009, 09:21 | ||||
Проблема в том что map можно менять, при этом, например, все итераторы, которые уже на что-то указывают, становятся невалидными. Можно доработать эту фабрику так, что-бы она работала безопасно с точки зрения многопоточности, не меняя внешнего интерфейса. Но здесь это точно ни к чему, как и singleton. Я упомянул о нём, для того что бы показать что может быть некоторое количество проектных решений одной и той же задачи. После освоения С++ классов, стоит уделить внимание ООП. Сам С++ только предоставляет свои средства для этого. Я в своё время не придавал этому особого значения, а зря, потому что понимая ООП, перестаешь просто пользоваться классами, полиморфизмом и т.п. а начинаешь использовать возможности языка целенаправленно, заранее спроектировав систему. Насколько я вижу, KasMP сначала кодирует, а потом уже пытается сложить все части вместе. Наоборот, сложнее, но гораздо эффективнее. Книжка GoF невелика и читается легко (как мне показалось). Я прочёл её за две недели, а она перевернула мое представление о том как надо создавать программы. Касательно многопоточности: Насколько я понимаю, проблема может быть только с разделяемыми сущностями, которые реагируют изменением состояния на действия пользователя. Т.е. можно получить совсем не то что ожидалось, потому что состояние сущности было изменено другим потоком. С другой стороны, этим можно воспользоваться в своих целях - мьютексы, семафоры, локеры... А если объект не меняет своего состояния за время жизни, то он безопасен. Добавлено @ 09:26
По шаблонам, и их возможностям на сегодняшний день, есть книжка "Шаблоны С++. Справочник разработчика" 538 стр. А5 Как раз её я сейчас прочёл наполовину ![]() |
Автор: azesmcar 17.7.2009, 09:38 | ||||
зачем? если можно просто не делать ее синглтоном ![]()
потоко-безопасен. Ответ: скорее всего - да, (в общем случае - нет). Речь идет о контейнерах STL, а thread safety guarantee STL контейнеры не дают. Надо смотреть доки конкретной реализации STL. Гарантию на потоко-безопасное чтение дает реализация STL от SGI. В общем случае - такой гарантии нет. |
Автор: Леопольд 17.7.2009, 09:49 | ||||
5000 потоков могу использовать одну, разделяемую, фабрику. Кстати, можно ли её вынести в динамически подключаемую либу? Я с этим не разбирался, и не знаю, как шарится память между разными программами. |
Автор: azesmcar 17.7.2009, 09:53 | ||
нет, нельзя, шаблонные классы в динамическую библиотеку не помещаются. чего? |
Автор: Леопольд 17.7.2009, 09:59 | ||
А если она будет не шаблонная? |
Автор: azesmcar 17.7.2009, 10:00 |
можно |
Автор: Леопольд 17.7.2009, 10:00 | ||
Цифра, конечно, нереальная, для обычных ситуаций ![]() Например, нам надо порождать ISUP сообщения, а каждое соединение обрабатывается в отдельном потоке. Я работаю, в основном, с MSC (Mobile Switching Center) ![]() |
Автор: Леопольд 17.7.2009, 16:10 | ||||
Что они творят! Вот пример, из книги, немножко переделан, для наглядности:
|
Автор: azesmcar 17.7.2009, 16:12 | ||
ну и что они творят? |
Автор: Леопольд 17.7.2009, 16:25 | ||||||
Можно задавать параметры шаблона в любом порядке, при этом остальные останутся по умолчанию. Я был впечатлён. Настолько, что решил поделиться ![]()
|
Автор: KasMP 18.7.2009, 22:57 | ||||||||||||||||||||
Спасибо, учтем на будущее ![]()
![]()
![]() ![]() Вопросов пока нет - я пыталась сделать все это более простым способом ![]()
Ну, в ней есть главы и про шаблоны, и про STL... Хотя не исключено, что для вас это будет "практически ничего" ![]() Посмотрим ![]() ![]() ![]()
![]() ![]() ![]() ______________________________________________ Пусть есть полиморфный класс Base и производные от него Der, Der1 и Der2. Я хочу уметь приводить переменные типа Base* к типу Der*, Der1* или Der2*. "Более простой" способ имеет 2 основные составляющие:
Но у меня все совсем по-другому: На строках типа
![]() ![]() ![]() |
Автор: azesmcar 19.7.2009, 10:40 | ||||||
Скорее всего результат приватного наследования.
надо заменить на
|
Автор: GrishinUS 19.7.2009, 15:08 |
а можно попросить пример с boost::serialization? в моей программе как раз буст нужно использовать. И.... как подключить boost к MSVC ? |
Автор: azesmcar 19.7.2009, 15:29 |
http://www.boost.org/doc/libs/1_38_0/libs/serialization/example/demo.cpp |
Автор: GrishinUS 19.7.2009, 16:37 | ||||
спасибо, посмотрел. Вопросы : 1) Зачем создается класс bus_stop, от него потом наследуются классы bus_stop_corner и bus_stop_destination. Что это дает? 2) смущает комментарий :
почему не работает как ожидалось? Это баг? Если да, то где: в boost или stdlib? 3) создается все-таки фиксированное число экземпляров:
а мне нужно создать заранее неопределенное кол-во экземпляров (в моем случае, объектов может быть максимум 25), как это лучше оформить? 4) вопрос, который меня больше всего интересует, где лучше сделать создание и наполнение экземпляров данными из исходного файла? У меня была идея вынести процедуры загрузки исходных данных вообще в отдельный объект, правда в таком случае не понятно каким образом передавать созданные экземпляры в main. |
Автор: KasMP 27.8.2009, 17:05 |
Телепат ![]() ![]() ![]() Спасибо за прекрасную приятную помощь ![]() ![]() GrishinUS, я не знаю ответы на твои вопросы, к сожалению ![]() ![]() |