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

Войти
 
  Начало Форум WIKI (Вики)FAQ Помощь Поиск Войти Регистрация  
  Просмотр сообщений
Страниц: 1 ... 51 52 [53] 54 55 ... 58
781  Программирование / С/C++ / Re: Изменить ссылку (?) : Февраль 09, 2013, 21:30
Я могу создать A пока с каким-то фуфлом а потом (когда образовался data) присвоить, но это коряво.
Что бы вы ни делали, после создания объекта A ваша ссылка mData всегда будет эквивалентом этого "фуфла". Можно, конечно, этому "фуфлу" присвоить полученное значение data, но вы ведь не этого добиваетесь?
Если цитировать Страуструпа, ссылка является альтернативным именем объекта, ее всегда надо инициализировать, значение ссылки никогда не меняется после инициализации. Т.е. ссылка появляется либо одновременно с объектом, на который она ссылается, либо позже.
782  Программирование / С/C++ / Re: Сериализация (как сделать поудобнее) : Февраль 08, 2013, 15:50
Идею понял, спасибо. Однако что делать для структур переменной длины, напр контейнеров? Их может быть великое множество, напр vectot<int>, vectot<float>  и еще 100 таких. Да и самих типов контейнеров не так уж мало. Создавать для каждого Boa элемент - явно нереально
Библиотека заточена под БД, поэтому основные структурные единицы - запись, таблица, blob. Для работы с контейнерами можно использовать параметризуемый тип BoaTable, который основан на стандартном векторе, например:
Код:
// запись
class TestRecord : public BoaInterface
{
public:
    bool         boolField;
    char         charField;
    short        shortField;
    int          intField;
    TestRecord();
};

// таблица
typedef BoaTable<TestRecord> TestTable;
// или для элементарных данных int
typedef BoaTable<Bint> TestTable;

Т.е., если надо передать контейнер, его сначала надо его перегнать в таблицу, которая уже все умеет.
783  Программирование / С/C++ / Re: Сериализация (как сделать поудобнее) : Февраль 07, 2013, 21:22
sergek, спасибо за предложение тестового примера, но тут "эффект большого" - на простом hello world вероятно любая схема успешно отработает. Если нетрудно покажите (или расскажите) что делает метод push. Из Вашего кода я не понял как же (используя что) разруливается I/O. Спасибо

Метод push сохраняет информацию о каждом члене класса (указатель, тип, размер). Разумеется, метод параметризуемый:

Код:
template<class C> void BoaInterface::push(C& ptr,const std::string& fldName,int size){
    bool hasName=!fldName.empty();
    BoaElement* elem;
    // Определяем тип преременной. Обрабатываем только известные типы
    if(typeid(ptr)==typeid(bool))                  elem=new BoolBoaElement(&ptr,hasName);
    else if(typeid(ptr)==typeid(char))             elem=new CharBoaElement(&ptr,hasName);
    else if(typeid(ptr)==typeid(short))            elem=new ShortBoaElement(&ptr,hasName);
    else if(typeid(ptr)==typeid(unsigned short))   elem=new ShortBoaElement(&ptr,hasName);
    else if(typeid(ptr)==typeid(int))              elem=new IntBoaElement(&ptr,hasName);
    else if(typeid(ptr)==typeid(long))             elem=new IntBoaElement(&ptr,hasName);
    else if(typeid(ptr)==typeid(unsigned))         elem=new IntBoaElement(&ptr,hasName);
    else if(typeid(ptr)==typeid(unsigned long))    elem=new IntBoaElement(&ptr,hasName);
    else if(typeid(ptr)==typeid(bigint))           elem=new BigIntBoaElement(&ptr,hasName);
    else if(typeid(ptr)==typeid(float))            elem=new FloatBoaElement(&ptr,hasName);
    else if(typeid(ptr)==typeid(double))           elem=new DoubleBoaElement(&ptr,hasName);
    else if(typeid(ptr)==typeid(std::string))      elem=new StringBoaElement(&ptr,hasName,size);
    else if(typeid(ptr)==typeid(BoaDataSet))       elem=new DataSetBoaElement(&ptr,hasName);
    else if(typeid(ptr)==typeid(BoaBinObject))     elem=new BinaryBoaElement(&ptr,hasName);
    else if(typeid(ptr)==typeid(BoaDateTime))      elem=new DateTimeBoaElement(&ptr,hasName,size);
    else if(typeid(ptr)==typeid(BoaBlob))          elem=new BlobBoaElement(&ptr,hasName);
    else if(strstr(typeid(ptr).name(),"BoaTable")) elem=new TableBoaElement(&ptr,hasName);
    else elem=new UnknownBoaElement(&ptr,hasName);
    data.push_back(elem);
}
Информация эта сохраняется в векторе data:
Код:
    std::vector<BoaElement*> data;      // список элементов данных
который представляет список объектов полиморфных типов (стольких, сколько поддерживаемых типов данных), каждый из которых знает, как себя сохранить в буфер, и как себя восстановить из буфера:
Код:
class BoaElement
{
public:
...
    // скопировать данные объекта в буфер по адресу ptr
    virtual int objToBuf(char* ptr) = 0;
    // скопировать данные из буфера по адресу ptr в объект
    virtual int bufToObj(char* ptr) = 0;
};
Например, для int:

Код:
int IntBoaElement::objToBuf(char* ptr){
    int dataLen=sizeof(int);
    if(ptr) memcpy(ptr,val,dataLen);
    return dataLen;
}
int IntBoaElement::bufToObj(char* ptr){
    int dataLen=sizeof(int);
    memcpy(val,ptr,dataLen);
    return dataLen;
}

Собственно, и все. Когда в конструкторе класса мы пишем
Код:
    push(boolField);
    push(charField);
    push(shortField);
этим самым мы сохраняем информацию о "сериализуемых" данных, а всю технику прячем в методы базового (интерфейсного) класса. Когда надо передать (сериализовать) объект, вызывается интерфейсный метод send(), в котором последовательно перебирается список объектов упомянутых выше полиморфных типов, и для каждого вызывается метод objToBuf(). При восстановлении (приеме) вызывается метод receive(), выполняющий обратную задачу.
Поэтому для того, чтобы сохранить (или передать) объект, а потом его восстановить не надо определять какие-то дополнительные методы. Достаточно:
1) сериализуемый тип породить от интерфейсного класса;
2) написать конструктор, в котором тупо перечислить все его члены-данные вызовом push().
Все остальное (много чего) прозрачно для разработчика и не требует кодирования под каждую задачу.
784  Программирование / С/C++ / Re: Сериализация (как сделать поудобнее) : Февраль 07, 2013, 08:57
Ну, наверное, можно придумать пример, который не впишется в мою схему. Но хотелось бы конкретики, желательно, из жизни. А вдруг, решаемо...
Есть любой std::map. Как его сериализовать таблицей, а главное как потом десериализовать?

Если в простом случае, когда ключ и значение сводится к классам с членами-данными стандартных типов (map<T1,T2>), то легко - две таблицы, одна передает T1, вторая T2. На приемной стороне ассоциативный массив "слепляется" из двух половинок.
В общем случае, нужна декомпозиция данных, приведение к стандартным типам и в цикле передача составных частей. На приемной стороне - обратное восстановление. Но в этом случае изменение структуры данных, параметризующих map, приведет к изменению и клиентской и серверной функции.
Я поэтому и говорил о конкретном примере, чтобы можно было оценить ограничение метода.
785  Программирование / С/C++ / Re: Сериализация (как сделать поудобнее) : Февраль 06, 2013, 22:17
Я не прошу реализовывать, вопрос: как пушатся сложные объекты, например, коллекция объектов?
Для этого есть параметризованный класс, аналог реляционной таблицы. Например, передача таблицы User_inf описывается так:
Код:
// запись для просмотра списка пользователей
class Ruser_inf : public BoaInterface
{
public:
    Ruser_inf();
    int id_user;
    char user_type;
    bool deny;
    string user_name;
    string firstname;
    string lastname;
    string patronymic;
    string organization;
};
typedef BoaTable<Ruser_inf> User_inf;
BoaDataSet* selUser_info(Bint* sortOrder);
А пушатся члены-данные записи. Вообще, библиотека заточена под реляционную БД, т.е прямоугольные однородные таблицы.
Ну, наверное, можно придумать пример, который не впишется в мою схему. Но хотелось бы конкретики, желательно, из жизни. А вдруг, решаемо...
786  Программирование / С/C++ / Re: Сериализация (как сделать поудобнее) : Февраль 06, 2013, 21:47
Давайте так - поставьте конкретную задачу, типа hello, wold (можно сложнее). А я сделаю проект под qt для клиент/серверного приложения. Там и оцените затраты и размер писанного кода. Только не сегодня (результат), а то завтра вставать рано...
787  Программирование / С/C++ / Re: Сериализация (как сделать поудобнее) : Февраль 06, 2013, 21:33
Код:
TestRecord::TestRecord(){
    push(boolField,"boolField");
    push(charField,"charField");
    push(shortField,"shortField");
    push(intField,"intField");
    push(longField,"longField");
    push(bigintField,"bigintField");
    push(floatField,"floatField");
    push(doubleField,"doubleField");
    push(stringField,"stringField");
    push(dateField,"dateField",BoaDateTime::DateTime);
 }
Здесь каждое поле идентифицируется строкой - дороговато выходит. Также неясно - ну а что дальше что, после того как хапихнули в контейнер (мапу?)
Да, неудачный пример я привел... Мап тут ни при чем, там шаблоны. И каждая строка (push) передает указатель на член класса, а шаблон уже сам определяет тип и длину данных, передаваемых через сокет. Поэтому накладные расходы - один push на один член, извините, данное класса. Примерно так.
Думаю, альтернатива этому - только препроцессор, а это тема отдельного разговора...
788  Программирование / С/C++ / Re: Сериализация (как сделать поудобнее) : Февраль 06, 2013, 21:26
to sergek:

Ваш способ и есть тот камень преткновения. При изменении структуры, придётся переписывать функции send и receive.

Или я не уловил вашу систему и у вас сериализуются типы по их текстовому названию и вызывается соответствующий сериализатор?
Не уловили Подмигивающий При изменении структуры переписывается только конструктор, в котором все сериализуемые поля "сохраняются" методом push. Имена не обязательны, они могут использоваться для доступа к полям путем разыменования (полезно при работе с таблицами БД). А так можно написать:
Код:
    push(boolField);
    push(charField);
    push(shortField);
...
И доступ к полям - обычным образом, и на клиенте и на сервере:
Код:
TestRecord rec;
char ch = rec.charField;
rec.shortField = 123;
Т.е. это обычные классы, только порождены от BoaInterface, в котором все и скрыто (и сериализация, и десериализация, и шифрование и много чего..). Кстати, на основе шаблонов, так не любимых вами Подмигивающий
Главное, чтобы объявления класса и реализация конструктора на клиенте и сервере были одинаковы. Поэтому в моих проектах правило: объявления классов, функций и реализации классов - это общая часть серверной и клиентской части.
Реализации функций - разные.
789  Программирование / С/C++ / Re: Сериализация (как сделать поудобнее) : Февраль 06, 2013, 20:53
Кстати, по указанному адресу есть и скомпилированные примеры, можно запустить и попробовать.
790  Программирование / С/C++ / Re: Сериализация (как сделать поудобнее) : Февраль 06, 2013, 20:41
Конечно это безусловно верно. Но вот полей может быть много. Да, придется все записать, но хотелось бы сделать это 1 раз в не 2.
skip
Как бы это дело обобщить?
Рискну предложить свое решение – интерфейс удаленных вызовов, API. Объектное решение, работает уже лет 12 в одной биллинговой системе.
Общий подход следующий:
- архитектура клиент/сервер. Сервер запущен и слушает заданный порт, клиент соединяется с этим портом;
- обмен между клиентом и сервером осуществляется путем вызова особых функций на клиенте и получения результатов исполнения этих функций на сервере;
- аргументами функции и возвращаемым результатом служат указатели на объекты классов, порожденные от одного интерфейсного BoaInterface;
- объявления для классов и функций общие для клиента и сервера;
- реализации функций – свои для клиента и сервера:
  а) клиент выполняет передачу аргументов на сервер и прием результатов,
  б) сервер выполняет прием аргументов от клиента, выполнение бизнес-логики и передачу результатов клиенту.

Пример использования:
1) объявления классов и функций (общие для клиента и сервера):
Код:
// тестовый класс
class TestRecord : public BoaInterface
{
public:
    bool         boolField;
    char         charField;
    short        shortField;
    int          intField;
    long         longField;
    bigint       bigintField;
    float        floatField;
    double       doubleField;
    string       stringField;
    BoaDateTime  dateField;
 
    TestRecord();
};
// функция получения объекта
TestRecord* selRecord(TestRecord* rec);

2) реализация класса (тоже общая для клиента и сервера):
Код:
// инициализация членов Boa-объекта
TestRecord::TestRecord(){
    push(boolField,"boolField");
    push(charField,"charField");
    push(shortField,"shortField");
    push(intField,"intField");
    push(longField,"longField");
    push(bigintField,"bigintField");
    push(floatField,"floatField");
    push(doubleField,"doubleField");
    push(stringField,"stringField");
    push(dateField,"dateField",BoaDateTime::DateTime);
 }

3) реализация клиентской функции:

Код:
// обработка запроса одной записи
TestRecord* selRecord(TestRecord* rec){
    // создание и отправка командного объекта
    BoaCommand cmd("selRecord");
    if(cmd.send()==BOA_ERROR)
        return 0;

    // получение результата
    int ret=rec->receive();
    // возвращаемое значение
    if(ret==BOA_ERROR)
        return 0;
    else
        return rec;
}

4) реализация серверной функции:

Код:
// обработка запроса одной записи
TestRecord* selRecord(TestRecord* arg){
    // принятая команда
    BoaCommand* cmd=BoaCommandPtr(arg);

    // формирование данных для клиента
    TestRecord record;
    record["boolField"]=true;
    record["charField"]=char('c');
    record["shortField"]=1;
    record["intField"]=10;
    record["longField"]=100;
    record["bigintField"]=1000;
    record["floatField"]=0.1;
    record["doubleField"]=0.01;
    record["stringField"]="Тестовая запись";
    record["dateField"]=BoaDateTime::currentDateTime();

    // отправка результата клиенту
#if defined(__BORLANDC__) || defined(QT_WIN)
    // win-версия
    record.sendTo(cmd->hSocket);
#else
    // *nix-версия
    record.send();
#endif
    return 0;
}

В общем-то, и все. Вся сериализация скрыта в методах базового класса BoaInterface::send() и BoaInterface::receive(), сериализуются все основные типы и некоторые встроенные предопределенные типы.
Остальное одинаково для всех программ – организация соединения со стороны клиента, прослушивание порта со стороны сервера. Есть нюансы для win- и nix-реализации. Один раз пишется и переносится из проекта в проект.
Более того, процесс написания можно автоматизировать. В свое время даже хотел написать визард для генерации кода (stub/sckeleton), но, поскольку, писал все программы сам, для себя поленился. Есть встроенная поддержка BDE и PostgreSQL, правда, древней версии. Возможен callback из серверной функции на клиента.
Если заинтересует, библиотеку можно найти по адресу http://www.freesoft.ru/?id=671951. Полная документация (руководство программиста, справочник), примеры для Borland C++Builder и Qt в Windows и Unix. Правда, давно не компилировал под nix-системами (последний раз проверял под FreeBSD 4.5 и Fedora 10 (или 12?).
Но если кого заинтересует, проверю в ubunta 12.04.01.
791  Qt / Дополнительные компоненты / Re: zip : Январь 20, 2013, 17:59
Коллеги, по использованию QZipReader/Writer хотелось бы уточнить одну деталь.
При использовании модуля GUI, ничего не надо включать в проект - достаточно в каталог проекта положить файл qzipreader_p.h (или qzipwriter_p.h, в зависимости от того, что нужно), а в файле, где используется класс библиотеки, его включить include'ом, и все.

А вот если нужно консольное приложение (запустить гуёвое, например, cron'ом просто так не получится), тут интереснее - нужно включить в проект qzip.cpp, а рядом положить qzipreader_p.h, qzipwriter_p.h, zconf.h, zconf.h.in и zlib.h). Все очень хорошо работает под Linuxом, а в Windows приходится в заголовочных qzip...h заменять Q_GUI_EXPORT на Q_DECL_EXPORT.
Полчаса я потратил на изучение qglobal.h, но так и не понял, почему под виндами работает Q_DECL_IMPORT вместо Q_DECL_EXPORT. Может, нужно какое-нибудь макро определить? Кто подскажет?
792  Qt / Установка, сборка, отладка, тестирование / Re: Распространение на linux - системах без статической сборки : Январь 12, 2013, 12:40
Вот еще рекомендации:
http://habrahabr.ru/post/78094/
793  Qt / Установка, сборка, отладка, тестирование / Re: Распространение на linux - системах без статической сборки : Январь 11, 2013, 09:53
А попробуйте GiftWrap:
http://rus-linux.net/nlib.php?name=/MyLDP/po/giftwrap/create-ubuntu-packages-with-giftwrap.html
https://launchpad.net/giftwrap,
вдруг получится Подмигивающий
Если сработает, отпишите. У самого руки не доходят...
794  Qt / Вопросы новичков / Gui-приложение в консольном режиме : Январь 09, 2013, 12:47
Коллеги, тоже столкнулся с необходимостью запуска приложения с графическим интерфейсом из командной строки. При этом оконный интерфейс не вызывается, и есть необходимость вывода в консоль некоторой информации во время выполнения программы.

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

Столкнулся с тем, что под Windows ничего не смог вывести в stdout. Внимательно изучил все, что попалось по этой теме в форуме. Понял следующее - для gui-приложения вывод в консоль невозможен (ну, или почти невозможен, но эти варианты меня не заинтересовали из-за их неэстетичности;). Можно, конечно, в проект добавить CONFIG +=console, но тогда при работе с оконным интерфейсом лишней оказывается консоль, которая болтается, как черный флаг.

А вопрос в следующем - почему в Linux (Ubuntu 12.04) моя программа при запуске из терминала ведет себя, как я ожидал - как консольная, и выводит в командную строку все, что нужно?
795  Qt / Вопросы новичков / Re: Qt и Qt-Creator в Ubuntu 12.04 LTS : Декабрь 24, 2012, 17:37
Цитировать
Если синаптика нет, то ставишь его через менеджер приложений
Его в 12.04 нет, поэтому sudo apt-get install synaptic

Цитировать
В Synaptic пишешь qt и видишь россыпь пакетов. Какой из них корневой я не помню, возможно qmake или Creator.
Я ставил qt-sdk из репозитория, потом ставил Qt Creator 2.6.1 отсюда http://releases.qt-project.org/qtcreator/2.6.1/qt-creator-linux-x86_64-opensource-2.6.1.bin, в наутилусе ставим галочку "Разрешить исполнение файла как программы" и запускаем. Я ставил в домашний каталог.
Страниц: 1 ... 51 52 [53] 54 55 ... 58

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