Russian Qt Forum
Сентябрь 28, 2024, 16:16 *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

Войти
 
  Начало Форум WIKI (Вики)FAQ Помощь Поиск Войти Регистрация  
  Просмотр сообщений
Страниц: 1 ... 55 56 [57] 58
841  Программирование / С/C++ / Re: Сериализация (как сделать поудобнее) : Февраль 07, 2013, 14:48
Примерно десяток используемых сейчас и сотенки две на подходе. Улыбающийся

Это крупный проект, который почти загнулся от старости и поверх него кладут-кладут-кладут новые и новые кирпичики Улыбающийся

Тут вопрос такой: есть ли наследование в этих структурах, и поля-ссылки на другие структуры, в частности ссылка на базовый тип, когда фактически там может быть и производный объект?
842  Программирование / С/C++ / Re: Сериализация (как сделать поудобнее) : Февраль 07, 2013, 14:43
По поводу охов и ахов насчет буста
Код
C++ (Qt)
ar & g.degrees;
Значит вот это круто. А что бы Вы сказали если бы это написал велосипедист (который наверное ничего не знает)? Да Вы бы его охаяли с ног до головы Улыбающийся "Это что, интуититвный оператор & ? Да откуда я могу догадаться что он делает??". НО.. это великий дуст - и лояльность меняется на 180 градусов. "Ах как лаконично"  Улыбающийся
Не все в восторге от буста, но можно смотреть в таком разрезе, что люди там таки довольно много думали над проблемами и нашли не самые плохие способы их решения. А зачастую и самые лучшие в контексте поставленной задачи. Оператор &, шаблоны и макросы там не от хорошей жизни используют. Кстати, из-за обилия макросов мне этот буст и не нравится. Но Вы, когда будете развивать свой метод по объединению чтения/записи, верите или нет, наверняка придете к тому, что сейчас есть в бусте Улыбающийся. А сейчас там есть определение перечня полей, подлежащих сериализации. И ничего лишнего в самих структурах. Всем остальным занимаются отдельные сериализаторы, с помощью которых хоть в QDataStream, хоть в XML, хоть куда можно сохранять. Т.е. в структуру добавить что-нить типа:
Код
C
friend class boost::serialization::access;
template<class Archive>
void serialize(Archive & ar, const unsigned int version)
{
 ar & degrees;
 ar & minutes;
 ar & seconds;
}
и не надо больше никаких методов по вводу/выводу писать в каждой структуре. Вы же к этому и стремились: один раз описать поля и больше с ними не возиться Улыбающийся.

Это, опять же, не призыв этим способом пользоваться, и не возведение в абсолют буста, но как метод сериализации очень достоин внимания. Вы вполне можете сделать свой велосипед, который будет красивше и понятнее Улыбающийся.
843  Программирование / С/C++ / Re: Сериализация (как сделать поудобнее) : Февраль 07, 2013, 11:30
PS заложите, так сказать, правильный подход к сериализации. А то у меня сериализация мозголомная в проекте, вон я тему создавал - наследие драконов прям Веселый

Так это смотря что сериализовать, как и куда Улыбающийся.

1. Если много простых, несвязанных между собой структур, да большинство из которых нельзя модифицировать, то надо смотреть в сторону способа как в QDataStream.
2. Все структуры ваши и можете делать с ними все, что угодно, то брать буст или сделать аналогично.
3. Как п. 2, структуры разрозненные, но есть возможность добавить им всем общего предка, то сравнить способ буста и способ sergek.
4. Классы хорошо организованы в иерархии, довольно громоздкие, в некоторых случаях требуют индивидуальной обработки полей и есть возможность добавить общего предка, то можно попробовать слепить такого странного монстра XMLContentReader/XMLContentWriter.

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

А с шаблонами лучше разобраться, штука очень мощная, может сильно уменьшить объем написания кода. Правда мозги при этом свернутся Веселый.
844  Программирование / С/C++ / Re: Сериализация (как сделать поудобнее) : Февраль 07, 2013, 00:09
Специализации шаблона функции можно просто вставить, где вместо аргумента Mode этот Mode будет типом, и тогда будет использоваться то, что нужно. Но при этом код будет един для клиента и сервера.
Да, можно Mode сделать параметром шаблона, а не функции (тогда шаблоны Igors будут немного по другому выглядеть). При этом Mode должен быть известен в compile-time, что накладывает некоторые ограничения. В частности смотреть, что будет при наследовании, полях-ссылках на другие структуры и т.п.

А вообще вот в бусте отличная идея заложена на это дело. Лаконичнее наверное не придумаешь.
Способ буста хорош, тут не поспоришь. Но это надо буст с собой носить, не всем это нравится. Опять же, должна быть возможность для модификации исходных структур, а если такой возможности нет? Способ QDataStream в этом отношении мне как-то ближе Улыбающийся, но нет доступа к защищенным/приватным членам Веселый. И как тут не разорваться...  Непонимающий.
845  Программирование / С/C++ / Re: Сериализация (как сделать поудобнее) : Февраль 06, 2013, 22:52
В бинарник попадёт только то, что используется.
Насколько я понимаю, в этом случае как раз и используется и попадет, т.к. в одном методе находится, и туда развернется шаблон и на чтение и на запись. Есть и другие особенности: виртуальный метод или экспортируется в библиотеке или еще чего (навскидку не припомню). Так что есть случаи, когда вроде бы неиспользуемое может в бинарник попасть.
846  Программирование / С/C++ / Re: Сериализация (как сделать поудобнее) : Февраль 06, 2013, 22:31
От увлекающихся обобщенным программированием я ожидал чего-то типа такого
Код
C++ (Qt)
template <class Stream, class T>
void ReadWrite( Stream & strm, T * data, int mode )
{
switch (mode)
...
 
void MyStruct::ReadWrite( QDataStream & strm, int mode )
{
   ReadWrite(strm, &intPoleMyStruct, mode);
   ...
 
Для определенных задач, когда клиент и сервер обменивается одинаковыми структурами в обе стороны, такой вариант может облегчить жизнь. Для других задач надо иметь в виду такой момент: если клиент отправляет серверу одну структуру типа request, а сервер в ответ другую типа response (и наоборот не будет), то при таком подходе этот вариант не самый лучший. Да, он в два раза уменьшит исходный код сериализации, но и в два раза увеличит конечный (скомпилированный) Улыбающийся. Потому что клиенту не нужен read(request) и write(response), а серверу не нужен read(response) и write(request). В этом же варианте при любом значении mode скомпилируется код на чтение и на запись сразу, хоть это и не всем нужно.

Вариант sergek, конечно, хорош, но общий предок - это не совсем честно Улыбающийся. С общим предком много чего можно сделать интересного. Можно взять общего предка QObject и практически бед не знать с его metaObject. Правда туда стороннюю произвольную структуру не воткнешь, и вернемся к тому, с чего начали.
847  Программирование / С/C++ / Re: Сериализация (как сделать поудобнее) : Февраль 06, 2013, 19:09
Я бы использовал отдельные файлы для каждого способа сериализаци для каждой структуры. Например:
Цитировать
IO/DataStream/MyStructRead.h
IO/DataStream/MyStructWrite.h
IO/DataStream/YourStructRead.h
IO/DataStream/YourStructWrite.h
IO/XML/MyStructRead.h
IO/XML/MyStructWrite.h
IO/XML/YourStructRead.h
IO/XML/YourStructWrite.h
Тот, кто будет читать/записывать, знает, каким способом он это сделает, подключит необходимые файлы и вызовет нужные функции. Может много хидеров подключить придется, зато ничего лишнего не будет. Можно и сгруппировать операции связанных структур в один файл, а не каждую в отдельный, но в общем смысл такой.
848  Программирование / С/C++ / Re: Сериализация (как сделать поудобнее) : Февраль 06, 2013, 18:12
Код
C++ (Qt)
void MyStruct::ReadWrite( QDataStream & strm, bool modeWrite )

Да, в один метод это лучше не пихать, и по вышеназванной причине тоже. И вообще, лучше не делать это методом структуры, а создавать отдельно. Как, например, и рекомендуется в QDataStream, операторами. Потому что, в общем случае, структуру не должно волновать, кто и куда захочет ее сериализовать. QDataStream - это, конечно, хорошо, но вдруг кому захочется сохранять/загружать/передавать в XML/JSON/YAML/по сети/как-нибудь еще. Или, наоборот, кто-нибудь не будет пользоваться QDataStream, зачем ему эти методы в структуре? Улыбающийся

А написать отдельные методы на чтение и на запись, не самое страшное, что есть в сериализации Улыбающийся.
849  Программирование / С/C++ / Re: Сериализация (как сделать поудобнее) : Февраль 06, 2013, 17:02
Я и спрашиваю как избежать повтора довольно большого куска в операторах >> и << для большой структуры
Ручками, ручками Улыбающийся. А если ручками лень, то написать парсер, который по исходникам сгенерит сериализаторы. Которые потом все равно придется ручками править Веселый.

Если применительно к структурам struct, то, похоже, все печально - к каждому полю придется обращаться отдельно. Махинации с памятью чреваты, как отметил Верес.

Можно попробовать придумать и использовать другие конструкции, похожие на struct, которые лучше поддаются сериализации. Но это если будет позволительно такое в программе использовать. А то, возможно, придется и их в struct конвертировать, что возвращает нас к исходной проблеме.

В boost'е тоже какие-то сериализаторы встречались.
850  Qt / Дополнительные компоненты / Re: Qt Design Patterns Extension : Январь 31, 2013, 17:06
Хорошо, а вот такая проблемка: общее число объектов приличное - напр неск тысяч. В то же время число "нужного" типа может быть с гулькин нос, а то и вообще ни одного. И что, итератор все равно должен промолотить все тысячи?
Тут мы, наверное, по разному понимаем, что в контейнере может находится Улыбающийся. В моем варианте в одном контейнере или много элементов одного типа (хоть несколько тысяч), или достаточно малое количество разных, причем заранее известно, в какой позиции какой тип находится. Можно, конечно, и тысячу разнотипных объектов в один контейнер засунуть, но это архитектурно другая задача будет. Это больше похоже на метод QObject::findChildren, который возвращает список объектов определенного типа, по которому потом можно пройти итератором. Правда пока он этот список создаст, он все тысячи объектов и промолотит Улыбающийся.
851  Qt / Дополнительные компоненты / Re: Qt Design Patterns Extension : Январь 31, 2013, 14:55
Интересно, но въехать и понять о чем речь трудновато Улыбающийся Обычная техника - контейнер указателей базового класса. Да, как правило нужны итераторы "по каждому из типов", ну я напр реализовывал в процедурном стиле (FirstTypedObject, NextTypedObject) и особых трудностей не испытывал.

Да, на первый взгляд выглядит заморочено, но если разобраться, то не все так страшно Улыбающийся. Базовые классы CompositeContainer и CompositeItem довольно простые, все преобразования типов ложатся на плечи CompositeAdapter. Он и доступ к методам контейнера с конкретным типом элемента предоставит, и итератор подходящий создаст. Дополнительная прослойка, конечно, но, возможно, это не самое худшее из зол Улыбающийся.
852  Qt / Дополнительные компоненты / Re: Qt Design Patterns Extension : Январь 31, 2013, 11:59
Есть вариант с CRTP оберткой.
Спасибо за вариант, посмотрю, можно будет ли его где-нибудь применить. Хотя одна вещь уже останавливает: использование шаблонного класса в качестве предка для другого.
Код:
class ConcreateItem : public TheItem<ConcreateContainer, Item>
Многие инструменты не любят шаблоны. Всякие автодополнения в редакторах и генераторы документации, например Doxygen. В этом случае он не сможет построить нормальный граф наследования классов, каким он, по-идее, должен быть. Я такие варианты использования шаблонов пробовал, и теперь, по мере возможности, стараюсь их избегать. Похоже нормально справиться с шаблонами под силу только компилятору  Веселый.

Цитировать
В случае большого количества элементов наследование от QObject для базовых типов может быть нецелесообразно.
Это возможно для некоторого класса задач. Но я писал эту библиотеку специально для использования в Qt, а не общую реализацию для любых классов. Общую реализацию быстрее, красивше и лучше, наверняка, можно сделать с помощью Boost, там вроде достаточно возможностей для этого. Я такой вариант рассматривал, но решил не привязываться к Boost'у, да и стиль классов Qt мне нравится намного больше. А если в Qt не унаследоваться от QObject, то могут закидать камнями, типа: "И как мне теперь сигналы подключать? А metaObject() где?". В общем, я не рискнул Улыбающийся.

Цитировать
Мне практически всегда приходилось отслеживать добавление/удаление элементов из контейнеров, например, элемент меняет контейнер.
Эту функциональность надо будет обдумать, насколько необходима и востребована она будет. С одной стороны вещь, безусловно, полезная, с другой стороны, не хочется загромождать базовые классы. Как-то баланс надо в этом найти.

Цитировать
Для С++ компоновщик менее универсален в сравнении с языками, допускающими полиморфные вызовы из конструкторов/деструкторов.
С этим тоже сталкивался, ощущения не из приятных - заставляет придумывать костыли, чего стараюсь избегать.

Цитировать
Итераторы для компоновщика элегантно реализуются через CRTP. Каждое хранилище (store) имеет свой STL-compatible итератор (нешаблонный). Под ConcreateItem делается CRTP шаблон-обертка TheIterator, которая выполняет даункастинг.
С итераторами я там столько наворотил, что сейчас их лучше не трогать Веселый.

Цитировать
В общем случае компоновщик можно ортогонализовать (выразился то как   но по делу) по различным стратегиям. Стратегия хранения у вас уже имеется. Также напрашиваются стратегии по возвращаемым типам элементов (raw pointer, shared_pointer и т.п.).
Хотел сделать такую возможность, и даже пробовал. Очень тяжко это шло, много проблем возникало, поэтому пока остановился на QPointer в хранилище.

Цитировать
Операции сортировки и фильтрации не стоит реализовывать на уровне компоновщика, тем самым загромождая его. Лучше вынести это в отдельный слой с проксированием, подобно QAbstractItemModel -> QAbstractProxyModel.
С этим согласен, каждый должен заниматься своим делом: контейнер хранить, сортировщик сортировать и т.п.

Цитировать
Если уж используете const propagation, то делайте это везде (я видел const метод findItem, возвращающий non-const pointer).
Тут возможна моя недоработка. По-хорошему, надо провести ревизию кода на предмет этого. Наверняка там много где еще можно const добавить.

Цитировать
Вы используете copy ctor() & operator=() для типов сущностей (identity type), коими являются все QObject'ы (т.е. ваши CompositeItem и т.д.), тем самым нарушая наказ родителя QObject: Q_DISABLE_COPY(). Несмотря на техническую корректность ваших методов, лучше использовать для этих целей методы clone() и assign() соответственно, а copy ctor() & operator=() оставить для value type.
Это все правильно, и надо еще хорошо подумать, как лучше клонирование организовать. Такой способ я ввел на самом раннем этапе, "чтоб был", потому что реальную его работу можно будет проверить на более позднем этапе, когда будет много вариантов деревьев для тестирования. Если честно, клонированием больших деревьев еще не занимался. Вопрос непростой, требует размышлений и тестирования. К особенностям некопирования QObject добавляются особенности компоновщика. Например, в одном контейнере может находиться ссылка на элемент в другом контейнере, и при ее копировании могут возникнуть сложности.

В общем, большое спасибо за полезные замечания Улыбающийся. Очень важен взгляд со стороны.
853  Qt / Model-View (MV) / Re: Создание модели : Январь 30, 2013, 18:01
А если попробовать?
Item->data(Qt::DisplayRole) = 4; - не отображает ничего

Это все неправильно. Если надо отображать таблицу без особых изысков, то лучше наследоваться от QAbstractTableModel и
Цитировать
When subclassing QAbstractTableModel, you must implement rowCount(), columnCount(), and data(). Default implementations of the index() and parent() functions are provided by QAbstractTableModel. Well behaved models will also implement headerData().
Как "implement rowCount(), columnCount(), and data()" смотрите в примерах и внимательнее изучите "Model/View Programming", это в справке Qt есть.

Если коротко, то числа можно вывести как-то так:
Код:
QVariant SomeTableModel::data(const QModelIndex &index, int role) const
{
  if (!index.isValid())
    return QVariant();

  switch (role)
  {
    case Qt::DisplayRole:
      switch (index.column())
      {
        case 0:
          return 4;
          break;
        case 1:
          return 423423.2342342;
          break;
        default:
        break;
      }
    break;
    default:
    break;
  }

  return QVariant();
}
854  Qt / Дополнительные компоненты / Re: Qt Design Patterns Extension : Январь 30, 2013, 12:09
Да, произвольный объект в контейнер вставить нельзя, для создания иерархии своих классов нужен определенный предок. Для листовых элементов это CompositeItem, для контейнеров - CompositeContainer. Например, AbstractSheet <- BookSheet, AbstractSheetCollection <- BookSheetCollection. Помимо общего предка, необходимо добавлять некоторые типы/методы, для контейнера минимум как в HomoCompositeContainer. Хотел уйти это этой копи-пасты, но, похоже, никуда от нее не денешься, можно только постараться свести ее к унифицированному виду.

Кроме последовательной индексации элементов в контейнере можно еще использовать ассоциативную. Так сделано в классах AbstractStringCatalog <- GenreCatalog, чтобы к элементу обращаться, например, таким способом:
Код:
BookShelf *bookShelf = catalog.item("Fantasy");

Выше были описаны гомогенные контейнеры, в которых содержатся элементы одинакового типа. Но иногда возникает потребность хранить в одном контейнере элементы разного типа. В классе магазина BookShop хранятся разные полки: BookShelf, NewspaperShelf и MagazineShelf. Обращаться к ним можно с помощью таких конструкций:
Код:
BookShop::Adapter aShop(bookShop());

BookShelf::Adapter aBookShelf = aShop.item<BookShop::Shelf::Book>()->adapter();
NewspaperShelf *pNewspaperShelf = aShop.item<BookShop::Shelf::Newspaper>();
auto aMagazineShelf = aShop.item<BookShop::Shelf::Magazine>()->adapter();
Может не самый удачный способ, но лучше я пока не придумал Улыбающийся.
855  Qt / Дополнительные компоненты / Re: Qt Design Patterns Extension : Январь 29, 2013, 23:29
Основная цель - чтобы было удобно пользоваться деревом объектов в "повседневном" коде, с минимумом лишних телодвижений. Доступ к объектам и методам через метаобъектную модель я бы все же удобным не назвал, она служит для несколько иных целей. Например, в композитном контейнере CompositeContainer при добавлении элемента проверяется его тип, чтобы нельзя было вставить объект другого типа, который не подходит к конкретному контейнеру. Вряд ли это можно сделать стандартными средствами метаобъектной модели. И много всего подобного.

Кроме того, в базовые классы композитного контейнера добавлены возможности шаблона проектирования Visitor, которые позволяют добавлять "якобы виртуальные" методы к уже существующим классам без их модификации. Пример этого можно увидеть в классах XMLContentWriter, XMLContentReader. Там, кстати, и используются возможности метаобъектной модели. И в то же время, именно из-за нее пример получился не совсем наглядным Улыбающийся. Надо будет его исправить.

Страниц: 1 ... 55 56 [57] 58

Страница сгенерирована за 0.151 секунд. Запросов: 23.