![]() |
Модераторы: 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 ) ![]() -------------------- ἀπὸ μηχανῆς θεός |
||||
|
|||||
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 |
1 Пользователей читают эту тему (1 Гостей и 0 Скрытых Пользователей) | |
0 Пользователей: | |
« Предыдущая тема | C/C++: Общие вопросы | Следующая тема » |
|
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности Powered by Invision Power Board(R) 1.3 © 2003 IPS, Inc. |