V
V
VerNika2016-01-04 15:25:08
Programming
VerNika, 2016-01-04 15:25:08

Qt. How to serialize objects containing collections?

In general, there are the following classes:

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

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

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

It is necessary to serialize a collection of objects of the Institution class (although I'm not sure whether it is appropriate to call this serialization), namely, save this collection to a binary and then "take" it from there.
Saving (no problem here, i.e. sizeof works as it should):
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();

Reading (here, of course, sizeof does not work, because the size of nested collections cannot be determined in advance):
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();

Now the question is, how can you still write and read this collection to / from the binary without changing the class structure (!)?
Or maybe there is something similar like in 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();

Answer the question

In order to leave comments, you need to log in

1 answer(s)
V
Vitaly, 2016-01-04
@VerNika

Qt has a special QDataStream class for serialization. The classes that you want to serialize need to implement two operators (for reading and for writing):

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
}

But you have pointers in your collections, incl. The addresses will be serealised, not the objects themselves. This problem needs to be solved somehow, i.e. if you have QList<Institution> lst, then you can just write s << lstfor serialization, and if the pointer, then no, it is possible to write the appropriate operator for the pointer - this is the solution.
And it might also be worth looking at JSON (since the fifth version, support has been included in the Qt standard library) if you need to save it to files, then read it and be able to fix it by hand.
PS I wrote the code just from memory, so it may not compile :) But something like this is the case.
PPS and better use some smart pointers like QSharedPointer, boost::shared_ptr or std::shared_ptr (since C++11)... Naked pointers are bad manners.

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question