@VerNika

Qt. Как сериализовать объекты содержащие коллекции?

В общем имеются вот такие вот классы:
class Institution //Класс "учебное заведение"
{
    ...
private:
    ...
    QList<Pupil *> Pupils; //Коллекция учеников
};

class Pupil //Класс "ученик"
{
    ...
private:
    ...
    QList<Exam *> Lessons; //Коллекция предметов
};

class Exam //Класс "экзамен"
{
    ...
};

Необходимо сериализовать коллекцию объектов класса Institution (хотя я не уверена уместно ли называть это сериализацией), а именно сохранить это коллекцию в бинарник и потом "взять" её от туда.

Сохранение (здесь проблем нет, т. е. sizeof работает как надо):
QList<Institution *> institutions;
...
Institution bf("", 0);
char str[1024];
strcpy(str, filename.toStdString().c_str());
std::ofstream out(str, std::ios::out | std::ios::binary);
for (int i = 0; i < institutions.size(); i++)
{
    bf = *institutions[i];
    int a = sizeof bf;
    out.write((char *) &bf, sizeof bf);
}
out.close();

Считывание (здесь, понятное дело, sizeof не работает, т. к. размер вложенных коллекций заранее не определить):
QList<Institution *> institutions;
...
institutions.clear();
char str[1024];
strcpy(str, filename.toStdString().c_str());
std::ifstream in(str, std::ios::in | std::ios::binary);
while (!in.eof() && in.peek() != EOF)
{
    Institution *bf = new Institution("", 0);
    int a = sizeof bf;
    in.read((char *) bf, sizeof *bf); //!
    institutions.append(bf);
}
in.close();

Теперь и вопрос, как всё-таки можно записать и считать эту коллекцию в/из бинарника, не изменяя структуру классов(!)?

Или может быть есть что-то подобное как в Java?
/*Коллекция*/
ArrayList list = new ArrayList();
/*Запись*/
try
{
FileOutputStream fos = new FileOutputStream(file.toString());
ObjectOutputStream oos = new ObjectOutputStream(fos);
oos.writeObject(list);
oos.close();
fos.close();
}
catch(IOException ioe)
{
}
/*Считывание*/
FileInputStream fis = new FileInputStream(file.toString());
ObjectInputStream ois = new ObjectInputStream(fis);
try
{
list = (ArrayList) ois.readObject();
} 
catch (ClassNotFoundException e)
{
}
ois.close();
fis.close();
  • Вопрос задан
  • 973 просмотра
Решения вопроса 1
vt4a2h
@vt4a2h Куратор тега C++
Senior software engineer (C++/Qt/boost)
Для сереализации в Qt есть специальный класс QDataStream. У классов которые вы хотите сереализовать нужно реализовать два оператора (для чтения и для записи):
QDataStream &operator<< (QDataStream &out, const T &obj);
QDataStream &operator>> (QDataStream &in, T &obj);

QFile f("path");
if (f.open(QIODevice::ReadOnly) { // or WriteOnly, or ReadWrite
   QDataStream s(&f);
   T obj;
   s >> obj; // for write s << obj
}

Но у вас в коллециях указатели, т.ч. сереализоваться будут адреса, а не сами объекты. Эту проблему нужно как-то решить, т.е. если у вас QList<Institution> lst, то можно просто написатьs << lstдля сереализации, а если указатель, то нет, возможно написать соотвествующий оператор для указателя -- это решение.

А еще возможно стоит присмотреться к JSON (с пятой версии поддержка входит в стандартную библиотеку Qt) если нужно именно сохранять в файлы, потом читать и иметь возможность поправить руками.

PS код писал просто по памяти, поэтому может не скомпилироваться :) Но примерно дела обстоят так.
PPS и лучше используйте какие-нибудь умные указатели вроде QSharedPointer, boost::shared_ptr или std::shared_ptr (с C++11)... Голые указатели уже моветон.
Ответ написан
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы