![]() |
|
Модераторы: Daevaorn |
![]()
|
|
| georain |
|
||||||||
![]() Бывалый ![]() Профиль Группа: Участник Сообщений: 193 Регистрация: 28.11.2006 Где: Санкт-Петербург Репутация: нет Всего: нет |
Вот приходят из сети данные блоками, в начале блока есть число - идентификационный номер класса который он содержит. Нужно преобразовать блок в класс с помощью статической функции этого класса.
Пользоваться case не хочу, классов много, хочу чтобы работало быстро Вот мой вариант: У меня дерево классов полиморфное. В каждом классе делаю статическую функцию которая принимает указатель на данные, возвращает указатель на базовый класс указывающий на новый класс (производный с нужным номером) созданный из этих данных. Это удобно потому что методы инкапсулированны внутри классов.
Делаю enum - перечисляю все мои классы, номера для каждого класса беру из протокола
Далее делаю финт ушами
Для создания нужного класса пишу
В итоге вместо множественного case получаю быстрый вызов нужной функции. Реализация мне нравится, но может есть что получше? Потому что во-первых велосипед наверняка, а во вторых надо не забыть каждый класс в таблицу записать и в enum ещё. Это сообщение отредактировал(а) georain - 15.2.2008, 15:23 |
||||||||
|
|||||||||
| marcusmae |
|
|||
![]() stravaganza ![]() ![]() Профиль Группа: Участник Сообщений: 874 Регистрация: 26.3.2006 Репутация: 5 Всего: 39 |
georain, действительно, велосипед солидный. Задача, как я понял, из потока распознать и десериализовать объекты. Если у вас дерево классов полиморфное, то почему нельзя эту иерархию как-то удобнее закодировать, чем прямой нумерацией? От этого в итоге будет зависеть, на сколько быстро их будет распознать.
-------------------- ἀπὸ μηχανῆς θεός |
|||
|
||||
| Alek86 |
|
|||
|
Эксперт ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 1299 Регистрация: 30.1.2007 Где: Киев Репутация: 21 Всего: 25 |
удалил
Это сообщение отредактировал(а) Alek86 - 15.2.2008, 15:56 |
|||
|
||||
| georain |
|
|||
![]() Бывалый ![]() Профиль Группа: Участник Сообщений: 193 Регистрация: 28.11.2006 Где: Санкт-Петербург Репутация: нет Всего: нет |
Ну так я и прошу совета, подскажите какой есть способ лучше. На счёт нумерации классов, а как можно удобнее закодировать, чем это будет лучше и чем плохо прямой нумерацией? |
|||
|
||||
| Alek86 |
|
|||
|
Эксперт ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 1299 Регистрация: 30.1.2007 Где: Киев Репутация: 21 Всего: 25 |
думаю, тут можно так извратиться
раскоментируй все строки и, вникая, увидишь, что при отсутсвии или номера или связи между номером и типом будет бабах (причем, в общем, читабельный) Добавлено @ 16:49 а способа лучше я не смог придумать (применимо к передаче кода класса вначале). Это сообщение отредактировал(а) Alek86 - 15.2.2008, 16:50 |
|||
|
||||
| Lazin |
|
|||
![]() Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 3820 Регистрация: 11.12.2006 Где: paranoid oil empi re Репутация: 41 Всего: 154 |
Думаю наиболее стандартным решением будет использование указателей на производящие ф-ии
потом когда приходит пакет можно очень быстро найти нужную ф-ю, скорость конечно ниже чем у switch, зато эта реализация масштабируется |
|||
|
||||
| Mayk |
|
||||
![]() ^аВаТаР^ сообщение>> ![]() ![]() ![]() ![]() Профиль Группа: Участник Сообщений: 2616 Регистрация: 22.5.2005 Где: за границей разум а Репутация: 45 Всего: 134 |
В принципе вместо map'а можно использовать hash_map или даже vector. Ну а фабрику можно инициализировать статически
-------------------- Здесь был кролик. Но его убили. Человеки < кроликов, йа считаю. |
||||
|
|||||
| marcusmae |
|
|||
![]() stravaganza ![]() ![]() Профиль Группа: Участник Сообщений: 874 Регистрация: 26.3.2006 Репутация: 5 Всего: 39 |
georain, я бы посмотрел, например, следующее : пусть есть всем базовый класс А, его наследники A1, A2, у каждого их которых по паре своих - A11, A12 и A21, A22 соотвественно. Кодировать - цепочку наследования, скажем, для A22 : просто "A-A2-A22" или, нумируя наследников, "00-01-01" - битами, байтами, символами - как-угодно. Ещё пример для A12 : "00-00-01" и т.п. Что за цепочки получились? = Это - пути в дереве наследования. Таким образом, проблема поиска типа сведена к задаче поиска в дереве. Оно, конечно, имеет свои ньюансы, скажем, в отличие от case по прямой нумерации, по ходу поиска отсекается большое число вариантов.
georain, можно много-чего посоветовать, способов много, тк проблема весьма абстрактная. А принятие ответственности за выбор способа решения для Вашего конкретного бизнеса - одна из составляющих работы -------------------- ἀπὸ μηχανῆς θεός |
|||
|
||||
| Lazin |
|
|||
![]() Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 3820 Регистрация: 11.12.2006 Где: paranoid oil empi re Репутация: 41 Всего: 154 |
а так более кошерно))
Это сообщение отредактировал(а) Lazin - 16.2.2008, 13:28 |
|||
|
||||
| Alek86 |
|
|||
|
Эксперт ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 1299 Регистрация: 30.1.2007 Где: Киев Репутация: 21 Всего: 25 |
marcusmae, раз говоришь, что есть много способов создания классов по данным из потока, то не мог бы ты сказать, как это сделать лучше для N классов, не связанных родственными узами? ну, или ссылку, как обычно
потому как мне задачка понравилась, но ничего лучше представленного в пером посте (ну, + некоторые мета-уловки, которые, возможно, упростят жизнь при добавлении новых классов) не придумал |
|||
|
||||
| marcusmae |
|
|||
![]() stravaganza ![]() ![]() Профиль Группа: Участник Сообщений: 874 Регистрация: 26.3.2006 Репутация: 5 Всего: 39 |
хорошо сказал вообще-то с самого начала речь шла о полиморфном дереве классов, ну а если нет, то его всегда можно искусственно создать, определив, к примеру, базовый абстрактный класс :
Уже после того, как вчера появились последние посты, я подумал, а как вообще нужно докатиться (в негативном смысле) до ситуации, когда в потоке непонятно-какие объекты, типы которых подлежат определению? Вижу две возможности : 1) на машине в сети работает программа с функцией main(), в которой наинициализирована и сериализована целая армия экземпляров разных типов. Но вообще-то так в кучу обычно не сваливают, а создают большой класс-контейнер Main или, как в .NET, Program, для которого уже можно определить функцию сериализации (которая в т.ч. будет вызывать сериализацию составных компонентов) и отправлять в поток уже как целостный объект. 2) экземпляр класса не может сериализовать сам себя. Если он сериализовался, то что-то извне этого потребовало : явный вызов или исключение. Это можно было бы обыграть, чтобы как-то дополнительно облегчить работу серверу. -------------------- ἀπὸ μηχανῆς θεός |
|||
|
||||
| Alek86 |
|
|||
|
Эксперт ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 1299 Регистрация: 30.1.2007 Где: Киев Репутация: 21 Всего: 25 |
ну "вот так вот получилось"
причем я легко могу представить, чтобы мне пришел некий отсериализированный контейнер разнородных данных. да пусть и однородных. Как их в этом случае рассовывать по классам? я вижу только вариант с ID |
|||
|
||||
| marcusmae |
|
|||
![]() stravaganza ![]() ![]() Профиль Группа: Участник Сообщений: 874 Регистрация: 26.3.2006 Репутация: 5 Всего: 39 |
Alek86, получиться может много-чего, просто улучшаемость заведомо плохих решений весьма ограничена. Ты сказал ключевое слово контейнер. Раз он есть, значит 1) его тип известен - можно сразу вызывать его десериализатор 2) "рассовывать" - забота контейнера, он должен уметь своим методом Deserialize прочитать, что в нём лежит. Этот вариант я описал в (1). А не нравится мне вариант, когда контейнера нет. То есть, просто ткнули заголовок и указатель на байты и длину - то, о чём шла речь вначале. Вот мне интересно : зачем тот, кто это сделал, так сделал? Это сообщение отредактировал(а) marcusmae - 16.2.2008, 17:18 -------------------- ἀπὸ μηχανῆς θεός |
|||
|
||||
| tol05 |
|
||||||||||
![]() Эксперт ![]() ![]() ![]() Профиль Группа: Участник Клуба Сообщений: 1632 Регистрация: 21.12.2006 Где: Харьков Репутация: 1 Всего: 170 |
Привет всем.
Я давно забыл плюсы и поэтому не буду писать здесь код. Я не очень четко понял задачу в части Непонятно почему выбрана такая реализация: и в базовом, и в дочернем класса будут статические ф-ции, и какая связь между статическими ф-циями базового и дочернего классов? Но меня попросили посмотреть тему и высказаться, поэтому напишу свое видение вопроса концептуально Десерилизация - это процесс создания и инициализации объекта, аналогичный созданию и инициализации объекта через конструктор. С тем только отличием, что вместо инициализирующих параметров в конструктор передается поток, содержащий полный набор данных объекта. Вместо конструктора marcusmae предлагает использовать вторую виртуальную ф-цию... Ну что ж, можно и так, просто это будет лишний вызов - в любом случае сначала нужно вызвать конструктор десерилизуемого объекта, а потом для него эту виртуальную ф-цию... Но повторяю, пусть пока будет как у marcusmae Соответственно, для того, чтобы определить, в каком порядке этот поток содержит даннные нашего класса, необходимо построить и зафиксировать граф серилизации. Граф создается при серилизации объекта, при десерилизации данные считываются в соответствии с ним. Для сложного (композитного) объекта подразумевается, что не только он, но и все его поля поддерживают серилизацию, т.е. каждое поле само должно восстановить себя из потока (ну и записать себя в поток при серилизации, конечно). При этом ... Например класс Base содержит в себе поля int, Class1, string. Класс Derived (наследник от Base добавляет bool, Class2, float). Все классы (Base, Derived, Class1 и Class2) наследуют базовый класс
При серилизации вызывается метод Serialize класса Derived, с такой псевдо-реализацией:
где метод Serialize класса Base, с такой псевдо-реализацией:
при десерилизации вызывается конструктор класса Derived, потом метод Deserialize с такой псевдо-реализацией:
метод Deserialize класса Base:
как видно, за позицию курсора потока беспокоиться не нужно - если все классы серилизуют и десерилизуют себя в одном и том же порядке (граф серилизации, определенный в Derived.Serialize используется в Derived.Deserialize), то каждый поток будет его смещать на величину именно своих данных и все будет хоккей.. Закон простой - в каком порядке записывались данные, в таком и читать. Классы сами себя "рассуют" куда нужно (потому что разработчик классов сам определяет что, как и когда писать и читать. Один раз и навсегда, для каждого класса) Здесь явно виден недостаток: постоянные вызовы конструкторов и ф-ций Deserialize... А вот если через конструктор базового класса (с параметром потоком) делать... то его бы не было и никаких индексов... они просто не имеют смысда в последовательном и единственном потоке. Ну вот и все. Не знаю, понятна ли мысль... Но это ясная и четкая структура, полиморфная и весьма юзабельная. Спасибо за внимание Это сообщение отредактировал(а) tol05 - 16.2.2008, 19:36 -------------------- На хорошей работе и сны хорошие снятся. |
||||||||||
|
|||||||||||
| marcusmae |
|
|||
![]() stravaganza ![]() ![]() Профиль Группа: Участник Сообщений: 874 Регистрация: 26.3.2006 Репутация: 5 Всего: 39 |
tol05, спасибо за ответ!
Согласен, что присутствие спецконструктора полезно в любом случае. А фишка наличия виртуальной функции в том, что с помощью шаблона она возвращает точный тип, а не интерфейс : (плюсифицирую код tol05
Здесь внутри был нужный нам конкретный Class1, но при возврате он разобщился до ISerializable, который потом придётся обратно приводить к Class1, правильно? -------------------- ἀπὸ μηχανῆς θεός |
|||
|
||||
| Alek86 |
|
|||
|
Эксперт ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 1299 Регистрация: 30.1.2007 Где: Киев Репутация: 21 Всего: 25 |
а терь для совсем тупых
есть у меня вектор Base'ов. В нем находятся потомки в последовательности: Derived1, Derived2, Derived1, Derived1, Derived2 засериализировать вектор легко КАК его снова получить из потока? как узнать, что для 0-го элемента требуется вызвать Deserialize у Derived1б для 1-го - у Derived2 и т.д.? |
|||
|
||||
| Lazin |
|
|||
![]() Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 3820 Регистрация: 11.12.2006 Где: paranoid oil empi re Репутация: 41 Всего: 154 |
Сохраняй числовые идентификаторы, по ним определяй что создавать и читать...
|
|||
|
||||
| Alek86 |
|
|||
|
Эксперт ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 1299 Регистрация: 30.1.2007 Где: Киев Репутация: 21 Всего: 25 |
и как сюда приткнуть красивейшую полиморфическую схему, предложенную ранее (имхо, очевидную, ибо вся трудность в этой связке) |
|||
|
||||
| xvr |
|
||||
|
Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Комодератор Сообщений: 7046 Регистрация: 28.8.2007 Где: Дублин, Ирландия Репутация: 60 Всего: 223 |
Насколько быстро надо? Если умеренно быстро, то можно в качестве ID взять не просто число а пару - строку, с именем типа класса и хэш от этой строки. Если хэш будет достаточно хороший (в идеале без колизий вообще), то определение типа класса сведется просто к индексации массива с хэшами. Реализация: 1) Для получения имен типов используется RTTI 2) Все типы классов должны наследоваться от базового, содержащего примитивы для сериализации 3) Для регистрации классов используется специальный темплэйтный класс - фабрика.
При записи сначала пишется ID класса (хэш(typeid(Item).name()) и typeid(Item).name()), затем сам класс (методом serialize). Опционально можно проверить, что данный ID был зарегистрированн какой либо фабрикой классов (Fabric<xxx>) При чтении читается ID, ищется среди зарегистрированных фабрик (в идеале просто индексируется массив), создается класс, заполняется из потока Это сообщение отредактировал(а) xvr - 18.2.2008, 12:45 |
||||
|
|||||
| marcusmae |
|
||||
![]() stravaganza ![]() ![]() Профиль Группа: Участник Сообщений: 874 Регистрация: 26.3.2006 Репутация: 5 Всего: 39 |
Хорошо, перефразирую. Тип Вы восстановите, я не сомневаюсь (Леонардо да Винчи плакаль бы от приведённых здесь неистовых механизмов осуществления этого). Мне непонятно, что Вы будете делать в случае неоднозначности соответствия сериализованного экземпляра и "места", в которое его нужно десериализовать. Так что, в этой постановке,
ответ : НИКАК. Ещё вопросы? Это сообщение отредактировал(а) marcusmae - 18.2.2008, 13:10 -------------------- ἀπὸ μηχανῆς θεός |
||||
|
|||||
| georain |
|
||||||
![]() Бывалый ![]() Профиль Группа: Участник Сообщений: 193 Регистрация: 28.11.2006 Где: Санкт-Петербург Репутация: нет Всего: нет |
В общем ничего лучше чем в первом после я не услышал, замечания tol05 относятся к методам сериализации/десериализации, т.е. как упаковать/распаковать класс, это совсем другая проблема. На счёт создания в конструкторе: новый класс можно создавать с параметрами конструктора взятые из потока в той-же функции create().
Надо не забывать что доступ к коду и клиента и сервера одновременно не всегда возможен. Иногда есть только протокол. И третий момент, что не всегда нужно передавать по сети весь класс целиком, часто нужны только некоторые его члены. Была приведена функция
, хорошо, допусти мы работаем по этой методике, как эту функцию Serialize вызвать для нужного класса? tol05 я очень благодарен что хочешь помочь, но мысль совсем не понятна. Ну как тогда без индексов классифицировать классы и вообще отделять один класс от другого в потоке? А изначальная проблема для этой задачи кстати звучит очень просто: есть дерево под сотню классов, набор экземпляров этих классов надо максимально эффективно отправлять по сети, причем последовательность типов экземпляров и их количество заранее не известно. В общем вопрос открытый. P.S. Alek86, кстати строчка
проверят существует ли переменная nNameClass, если ее в enume нет, то ошибку выведет. Поэтому проверка enum'а нужна только на отравляющей стороне (а там проверка находится в функции "сериализации" при вставке константы из enum'а в поток). Добавлено через 13 минут и 29 секунд marcusmae, ну это же может быть вектор указателей на Base) Это сообщение отредактировал(а) georain - 18.2.2008, 13:23 |
||||||
|
|||||||
| tol05 |
|
|||
![]() Эксперт ![]() ![]() ![]() Профиль Группа: Участник Клуба Сообщений: 1632 Регистрация: 21.12.2006 Где: Харьков Репутация: 1 Всего: 170 |
Да действительно, если мы имеем сложный класс MyClass, серилизуем в один и тот же поток 10 его экземпляров, а десерилизовать нужно будет (к примеру) только 2-й и 8-й....
В таком случае, в ф-ции Serealize класса MyClass перед началом записи в поток информации необходимо добавлять метки. Или индексы, как будет угодно Здесь нужно написать базовую функциональность серилизации, а как ее применять - уже зависит от конкретного случая использования... Вот как, например, сказать глупой машине, чтобы среди много-много байтов она нашла только те, которые относятся только к тому классу, у которого 23-й член равен 17? Я описывал только паттерн (композитор ИМХО), реализованный в .Net, в частности. -------------------- На хорошей работе и сны хорошие снятся. |
|||
|
||||
| Alek86 |
|
|||
|
Эксперт ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 1299 Регистрация: 30.1.2007 Где: Киев Репутация: 21 Всего: 25 |
ты не веришь, что десериализация возможна? ) да, похоже... перемудрил я ) тогда порекомендую вместо массива указателей на функции пользовать map и вызов с помощью cdr.getNumber() в try-блок обернуть... Добавлено через 2 минуты и 46 секунд помойму, tol05, ты не совсем понимаешь, в чем вопрос. Вопрос, как отличать разных наследников в списке. Если на это есть "паттерн" - с удовольствием выслушаю (говорю без стеба) |
|||
|
||||
| georain |
|
|||
![]() Бывалый ![]() Профиль Группа: Участник Сообщений: 193 Регистрация: 28.11.2006 Где: Санкт-Петербург Репутация: нет Всего: нет |
||||
|
||||
| Alek86 |
|
|||
|
Эксперт ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 1299 Регистрация: 30.1.2007 Где: Киев Репутация: 21 Всего: 25 |
чтобы исключения кидать, когда айди несуществующий функция cdr.getNumber() отдаст
в твоем же случае боюсь подумать, что получится. отдастся какое-то число, оно посчитается указателем на функцию и запустится... Добавлено через 1 минуту и 30 секунд а заместо указателей на функции использовать boost::function чтоб и от других ошибок отгородиться |
|||
|
||||
| tol05 |
|
|||
![]() Эксперт ![]() ![]() ![]() Профиль Группа: Участник Клуба Сообщений: 1632 Регистрация: 21.12.2006 Где: Харьков Репутация: 1 Всего: 170 |
Теперь понял. Конечно есть паттерн, как не быть.
каждый объект, серилизуясь, записывает в поток имя своего класса (в качестве своей системной информации, например) Делаем класс - фабрику, куда передаем имя класса и поток. Фабрика создает объект нужного класса. Она ищет в потоке фрагменты данных, соответствующие требуемому классу. Если таких объектов - несколько, перегружаем методы фабрики и добавляем в запросы к фабрике параметры, конкретизирующие поиск. P.S. все, больше мешать не буду. ИМХО решите проблему концептуально сначала. P.S.S указателей не передавайте. Где гарантия уникальности значений? При десерилизации из нескольких потоков? На различных клиентах? Это сообщение отредактировал(а) tol05 - 18.2.2008, 14:27 -------------------- На хорошей работе и сны хорошие снятся. |
|||
|
||||
| Alek86 |
|
|||
|
Эксперт ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 1299 Регистрация: 30.1.2007 Где: Киев Репутация: 21 Всего: 25 |
немного неясная формулировка. короче говоря, нужно делать ту же карту, только между строкой и соответствующей функцией фабрики? тогда это практически то же, что и в первом посте. |
|||
|
||||
| Lazin |
|
|||
![]() Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 3820 Регистрация: 11.12.2006 Где: paranoid oil empi re Репутация: 41 Всего: 154 |
Ну вы тут напридумывали сами себе сложностей
вот приблизительный код, никаких имен классов, boost::function, и прочего. Похожий код использовал в одном проекте, этот в качестве иллюстрации на коленке написал за пару минут))
|
|||
|
||||
| tol05 |
|
|||
![]() Эксперт ![]() ![]() ![]() Профиль Группа: Участник Клуба Сообщений: 1632 Регистрация: 21.12.2006 Где: Харьков Репутация: 1 Всего: 170 |
я бы не сказал, что то же
Похоже конечно, но ведь мы все говорим на одну тему, поэтому и посты как бы об одном и том же... Ты получаешь пакеты данных. Это во-первых. Вначале пакета идет его идентификатор. Замечательно. Получил ты число 12667845 например... Нужно создать какой-то класс. Какой? "с помощью статической функции какого класса"? передаешь принятый пакет (поток) в фабрику. Она считывает из потока блок данных до определенной метки. Это имя класса. Дальше нужно создать экземпляр. Рефлексия в плюсах есть? Позднее связывание? Класс Activator, я имею в виду? marcusmae, здесь точно ответит. я - нет... Но даже если и нет... Простой оператор switch по текстовому значению вызывает ф-цию ISerializable.Deserialize для каждого конкретного класса, а-ля
и т.д. сделайте абстракный класс, как говорилось выше. Если хотите полиморфности. -------------------- На хорошей работе и сны хорошие снятся. |
|||
|
||||
| Alek86 |
|
|||
|
Эксперт ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 1299 Регистрация: 30.1.2007 Где: Киев Репутация: 21 Всего: 25 |
и tol05 и Lazin, фактически, предлагают одно и то же
в С++ нету свича для строк + мап полюбому получше от свича. а у Lazin оно не так автоматизировано, как в пером посте + боюсь представить, что ЭТО такое. какой у этого класса размер?
|
|||
|
||||
| Lazin |
|
|||
![]() Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 3820 Регистрация: 11.12.2006 Где: paranoid oil empi re Репутация: 41 Всего: 154 |
этот класс нужен только для того что-бы сработал его конструктор во время запуска программы Добавлено через 3 минуты и 7 секунд
эту проблему я и решаю этим классом, можно не в enum записывать, а куда угодно, в простой массив, в объект класса автора |
|||
|
||||
| Alek86 |
|
|||
|
Эксперт ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 1299 Регистрация: 30.1.2007 Где: Киев Репутация: 21 Всего: 25 |
||||
|
||||
| marcusmae |
|
||||||
![]() stravaganza ![]() ![]() Профиль Группа: Участник Сообщений: 874 Регистрация: 26.3.2006 Репутация: 5 Всего: 39 |
Нет Нет Нет Если позволите, немного резюмирую всё вышесказанное.
мне не нравится, потому что : а) статическая функция десериализации б) создаёт не ClassA *, а Base *. А массив указателей на функции - это всегда кажется, что "финт ушами", особенно если в первый раз делать... Статичность функции ::create я отношу к недостатком, поскольку она не позволяет "каскадно" или по частям десериализовать объект, опираясь на десериализаторы базовых типов. Топикстартеру придётся в static Base * create(CDR * cdr){ ... } разводить помойку, которая при заявленных аппетитах в сотню классов примет формы опасные для здоровья И тот, и другой способ вполне имеют право на существование. Статический - скорее в случае наличия готовой большой иерархии, к которой сериализацию нужно лишь "временно" прикрутить, чтобы что-то там попробовать. Виртуальный - скорее в случае разработки кОмплексного решения, так, как это обычно делается на современных платформах. В любом случае, странно, что , и вообще вдруг выяснилось, что это всё не нужно, и , а просто
Могу привести пример, когда она, как мне кажется, невозможна. Сериализую массив структур "поштучно" и бросаю в перегруженную сеть, которая поперепутала пакеты (или есть сомнения в том, что сеть может менять очерёдность пакетов..?). Предлагаю их десериализовать и расставить ровно в той последовательности, что были изначально. Это сообщение отредактировал(а) marcusmae - 18.2.2008, 22:26 -------------------- ἀπὸ μηχανῆς θεός |
||||||
|
|||||||
| georain |
|
|||
![]() Бывалый ![]() Профиль Группа: Участник Сообщений: 193 Регистрация: 28.11.2006 Где: Санкт-Петербург Репутация: нет Всего: нет |
Lazin, скажи пожалуйста, зачем делать в базовом классе невиртуальные методы-обёртки для виртуальных методов? Чем это лучше, почему не следует сразу виртуальные методы save_() load_() вызывать?
marcusmae, полность с тобой согласен, единственное только хочу сказать, что естественно внутри static create ,будет вызываться функция - член десериализатор с "каскадной" функциональностью либо поток будет передаваться конструктору, и вот тут пример очень не удачный, потому как есть протокол TCP гарантирующий доставку в нужном порядке. |
|||
|
||||
| georain |
|
|||
![]() Бывалый ![]() Профиль Группа: Участник Сообщений: 193 Регистрация: 28.11.2006 Где: Санкт-Петербург Репутация: нет Всего: нет |
ИМХО в каждом классе есть метод для превращения класса в кусок потока, и наоборот и есть функция которая по этому куску потока вызывает этот метод для необходимого класса - её функция определить нужный класс. По идее должна быть симметричная ей функция которая пишет информацию в поток в зависимости от того какой класс записывается, но только потому что класс сам знает свой тип удобнее не делать отдельную функцию, а делать чтобы класс перед тем как "линеаризироваться" записывал информацию о себе сам. Это две разные задачи и никак не связаны. За вторую задачу может быть ответственен базовый класс, например ISerializable у tol05, первая же задача "каскадно" размазана по методам производных классов. У меня вторая задача тоже размазана по производным классам в статик методах плюс один внешний класс с таблицей которая может быть и внутри базового класса как статический член. Хотя это всё в общем-то довольно удобно, мне кажется что это не очень хорошо. Именно про это и был задан мой вопрос, как лучше (и эффективнее) решить вторую задачу (именно вторую) - нахождение класса из потока, а решение первой задачи довольно тривиальное и тут мало что можно придумать. Ну вы меня сильно не бейте если чё |
|||
|
||||
| marcusmae |
|
|||
![]() stravaganza ![]() ![]() Профиль Группа: Участник Сообщений: 874 Регистрация: 26.3.2006 Репутация: 5 Всего: 39 |
Мне кажется, что всё, что можно придумать на счёт сериализации/десериализации основано на той информации, которую предоставляет поток. Не стоит его содержимое считать фиксированным и очевидным. Все идеи - там. Ахтычорт, TCP, и правда -------------------- ἀπὸ μηχανῆς θεός |
|||
|
||||
| xvr |
|
|||
|
Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Комодератор Сообщений: 7046 Регистрация: 28.8.2007 Где: Дублин, Ирландия Репутация: 60 Всего: 223 |
Чем тебя мое решение не устроило (на 2й странице 3е сверху)? |
|||
|
||||
| Lazin |
|
|||
![]() Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 3820 Регистрация: 11.12.2006 Где: paranoid oil empi re Репутация: 41 Всего: 154 |
в моем примере оверхеда на вызов дополнительной ф-ии не будет, компилятор ее просто выкинет. А преимуществ масса, почитай про паттерн NVI ^_^ |
|||
|
||||
| tol05 |
|
||||
![]() Эксперт ![]() ![]() ![]() Профиль Группа: Участник Клуба Сообщений: 1632 Регистрация: 21.12.2006 Где: Харьков Репутация: 1 Всего: 170 |
не ну я так не играю!.. Что значит размазана? Это расширение функциональности в базовом классе и ее поддержка в производных... Зачем же тогда наследование придумано??? Всвязи с тем, что позднего связывания (в том виде, к которому я уже привык) здесь не имеется, я на своем методе обнаружения классов в потоке не настаиваю... Размазанность - это благо. Каждый класс сам обеспечивает свое жизнеобеспечение. А по поводу статических ф-ций - это ИМХО плохо. Какое преимущество их использования? Из статической ф-ции производного класса нельзя вызвать статическую ф-цию базового класса, как же тогда инициализировать закрытые члены базового класса? В производном классе к ним доступа нет, а в потоке данные о них есть
В статические ф-ции нужно передавать дополнительные параметры, идентифицирующие конкретный объект. Зачем? Раздувается таблица методов класса. Дублируется значительная часть функциональности.... И как статические ф-ции обеспечивают потокозащищенность в плюсах? Я не помню просто Это сообщение отредактировал(а) tol05 - 19.2.2008, 12:21 -------------------- На хорошей работе и сны хорошие снятся. |
||||
|
|||||
| marcusmae |
|
||||
![]() stravaganza ![]() ![]() Профиль Группа: Участник Сообщений: 874 Регистрация: 26.3.2006 Репутация: 5 Всего: 39 |
georain,
tol05, Я тут ночью думал-думал и вот что надумал. Что вообще хорошего в статических функциях (при том, что они ужасно плохие
Сервер получил этот stream, считал размер пакета и имя функции. Имея последнее, сервер лезет в эталонную таблицу и загружает оттуда точку входа функции-десериализатора :
Готово. Копия объекта загружена в LPVOID a. Так что здесь можно обойтись без всяких там enum-ов и навороченных таблиц в коде. Не знаю, правда, насколько это удобно в плане того, что автор собирается дальше делать с клоном, но факт тот, что он получен... Архив с полным решением присоединён. Присоединённый файл ( Кол-во скачиваний: 7 )
Koder.rar 43,99 Kb-------------------- ἀπὸ μηχανῆς θεός |
||||
|
|||||
| Lazin |
|
|||
![]() Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 3820 Регистрация: 11.12.2006 Где: paranoid oil empi re Репутация: 41 Всего: 154 |
это на каком языке? на плюсах можно, если позволяет видимость... а если завтра тебе понадобится добавить десяток новых классов, как быть? |
|||
|
||||
| marcusmae |
|
|||
![]() stravaganza ![]() ![]() Профиль Группа: Участник Сообщений: 874 Регистрация: 26.3.2006 Репутация: 5 Всего: 39 |
ну, понадобится иметь для них десяток функций сериализации - по своей собственной для каждого класса. Ну и декорированные имена через dumpbin посмотреть и забить в константы. Что-то мне подсказывает, что если всё аккуратно сделать, то можно обойтись без имён - одними указателями. По идее, если dll, то у неё фиксированная виртуальная адресация, и адрес функции у клиента и сервера должен быть одинаковый. Можно-можно. Просто, для статических функций само понятие наследования отсутствует. Но их всегда можно вызвать явно. А вот - хороший довод. По-моему, никак. Это сообщение отредактировал(а) marcusmae - 19.2.2008, 14:55 -------------------- ἀπὸ μηχανῆς θεός |
|||
|
||||
| tol05 |
|
|||
![]() Эксперт ![]() ![]() ![]() Профиль Группа: Участник Клуба Сообщений: 1632 Регистрация: 21.12.2006 Где: Харьков Репутация: 1 Всего: 170 |
Это называется "нельзя" Какое же это наследование, если нужно this в параметры передать??? Я так могу любую ф-цию вызвать и передать указатель на мой класс. Так что, эти классы предками/потомками станут? Я имел в виду использование Base... когда и базовый, и производный класс оперируют с одним и тем же указателем на объект. мда, по-моему тоже... ну да ладно... этот пост можно считать оффтопом. -------------------- На хорошей работе и сны хорошие снятся. |
|||
|
||||
| georain |
|
||||||
![]() Бывалый ![]() Профиль Группа: Участник Сообщений: 193 Регистрация: 28.11.2006 Где: Санкт-Петербург Репутация: нет Всего: нет |
xvr
Потому что решение более сложное, а строка
обязывающая для каждого класса писать
остаётся, в чём выгода? tol05 потому что
а сама функция create ни как в наследовании не участвует, нам от неё только адрес нужен, и чтоб в классе была, чтобы всегда знать где такую функцию искать (по моему логично функцию создающую конкретный класс держать поближе к самому классу). marcusmae развеселил, хохот в час ночи. Возможно это даже будет работать, но мне кажется это не очень кроссплатформенно, этож на win-lin-mac-bsd-и.т.д. должно работать, а разный порядок байтов на разных машинах, сомнительное предложение, но прикольно! |
||||||
|
|||||||
| xvr |
|
||||||
|
Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Комодератор Сообщений: 7046 Регистрация: 28.8.2007 Где: Дублин, Ирландия Репутация: 60 Всего: 223 |
В том, что: 1) Не надо добавлять никаких enum'ов, ID и пр. 2) Количество типов классов может быть любым (не ограничено размером числа, задающего тип) 3) Полная проверка на этапе сериализации, что CREATE_FABRIC не забыли указать (увы, может не сработать при раздельных sender'е и reviever'е) 4) Не нужен никакой switch и никакая другая централизованная обработка - потенциальное место где можно забыть что-то добавить. 5) CREATE_FABRIC - это ЕДИНСТВЕННОЕ что добавляется при сериализации нового класса П1-4 следствия П5. |
||||||
|
|||||||
| georain |
|
||||||||
![]() Бывалый ![]() Профиль Группа: Участник Сообщений: 193 Регистрация: 28.11.2006 Где: Санкт-Петербург Репутация: нет Всего: нет |
Ну если на то пошло, то хеш имени может оказаться одинаковым для двух каких-нибудь классов.
Проверять надо на этапе компиляции, а на этапе сериализации это накладно. К тому же классы отправителя и принимателя будут иметь разную реализацию, т.е. либо там либо там можно забыть написать CREATE_FABRIC.
Ну у меня вообще свича нет
Это факт, спору нет. Тут есть и плюсы и минусы, в равной степени, но реализация толще и главная причина, будет тяжело обойти проблему, если имена классов на разных сторонах будут различаться. |
||||||||
|
|||||||||
| marcusmae |
|
|||
![]() stravaganza ![]() ![]() Профиль Группа: Участник Сообщений: 874 Регистрация: 26.3.2006 Репутация: 5 Всего: 39 |
georain, ну что за чушь? Это сообщение отредактировал(а) marcusmae - 20.2.2008, 11:22 -------------------- ἀπὸ μηχανῆς θεός |
|||
|
||||
| xvr |
|
||||||||||||
|
Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Комодератор Сообщений: 7046 Регистрация: 28.8.2007 Где: Дублин, Ирландия Репутация: 60 Всего: 223 |
Да. При приеме проверять, если для данного значения хэша есть более одного имени - проверять имя, если только одно - игнорировать. Хэш можно подобрать (в том числе и run-time), что бы минимизировать количество коллизий. Например, если в качестве хэша использовать CRC16, то можно выбрать один из нескольких порождающих полиномов.
|
||||||||||||
|
|||||||||||||
| Dimonius |
|
|||
|
Шустрый ![]() Профиль Группа: Участник Сообщений: 51 Регистрация: 11.10.2006 Репутация: нет Всего: 1 |
Если все классы, которые приходят по сети наследуются от одного родительского, то здесь следует применить шаблон проектирования Factory Method, который позволит внести в программу желаемую расширяемость и управляемость. Если нужен пример кода, то на досуге напишу.
|
|||
|
||||
![]()
|
| Правила форума "С++:Общие вопросы" | |
|
|
Добро пожаловать!
Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, Earnest Daevaorn |
| 0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей) | |
| 0 Пользователей: | |
| « Предыдущая тема | C/C++: Общие вопросы | Следующая тема » |
|
|
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности Powered by Invision Power Board(R) 1.3 © 2003 IPS, Inc. |