Click here to Skip to main content
16,008,075 members
Please Sign up or sign in to vote.
1.00/5 (1 vote)
See more:
Hello
i am learning c++, and the other day i had some difficulties with saving collections of object to file and reading them back. Could you please give me a hint with this question?
Question is followind:i have one base class, and one derived class. I have also ArrayList of objects of derived class, and i have to write this ArrayList to file on disk, and then read it.

Thank you.
Posted
Comments
[no name] 11-Jul-12 15:17pm    
You will get a lot better response if you post the code that you have tried along with what it is doing wrong and what it is that you want to do.
Sergey Alexandrovich Kryukov 11-Jul-12 17:33pm    
Class collection, or a collection of instances of those classes?
--SA
Sergey Alexandrovich Kryukov 11-Jul-12 17:34pm    
Are you sure this is not .NET? Managed, C++/CLI? ArrayList is a .NET class (which you should not use).
--SA
pasztorpisti 12-Jul-12 6:07am    
In managed environment it would be easier to write serialization for this. What is your intention with serialization? Or just practicing/learning c++?
v.chjen 12-Jul-12 8:46am    
It is practising to learn c++

 
Share this answer
 
v2
Comments
CPallini 16-Oct-12 15:38pm    
5.
Sergey Alexandrovich Kryukov 16-Oct-12 15:41pm    
Thank you, Carlo.
--SA
pasztorpisti 16-Oct-12 17:05pm    
+5, Agree.
Sergey Alexandrovich Kryukov 16-Oct-12 17:06pm    
Thank you.
--SA
Unfortunately you will have to write the whole serialization code for yourself in C++. If all you have to do is saving out only an array of objects and then loading it you will get away with quite a simple solution. If you need a much more general serialization support then you will have to use a library that aims your problem or write your own framework but even using such a solution is a bit messy.

Lets assume all you want to save is an array of object pointers to the base class.
Saving:
first you serialize the size of the array, and then the objects one-by-one. You can do the object serialization by introducing a virtual Serialize(Serializer& ser) method to your base class and you call this serialize method on each object while you are iterating over the array. Each object must save a unique identifier that identifies the given type/class and then the data that is needed to restore the inner state. The identifier must be a unique id among the serialzable types/classes, this can be for example the name of the class for the sake of simplicity.

Loading:
First you load the size of the array and set the size of your actual array instance. Then you iterate over the array and for each item in the array you call a magic function that reads creates an object by reading it from the stream. This magic function must somehow know every identifier that can occur in your Serialize() function calls when saving. The magic function reads the type identifier, checks which class must be instantiated, instatiates the class and calls its virtual Deserialize(Deserializer& dser) method that reads the rest of the data from the stream. This magic function check the identifier with an if-else construct or gets the creator function from a registry in which you can register new types dynamically.

EDIT: Iam in good mood so I created you a snippet that demonstrates what I described above:
C++
class CSerializer
{
public:
    // Write method for every primitive type you support
    void Write(const char&);
    void Write(const int&);
    void Write(const size_t&);
    void Write(const bool&);
    void Write(const float&);
    void Write(const char*);
    void Write(const std::string&);
};

class CDeserializer
{
public:
    // Read method for every primitive type you support
    void Read(char&);
    void Read(int&);
    void Read(size_t&);
    void Read(bool&);
    void Read(float&);
    void Read(std::string&);
};

class CBaseClass
{
public:
    virtual ~CBaseClass() {}
    virtual void Serialize(CSerializer& ser) = 0;
    virtual void Deserialize(CDeserializer& dser) = 0;
};

class CDerivedClass : public CBaseClass
{
public:
    virtual void Serialize(CSerializer& ser)
    {
        ser.Write("CDerivedClass");
        ser.Write(m_DerviedClassState);

    }
    virtual void Deserialize(CDeserializer& dser)
    {
        dser.Read(m_DerviedClassState);
    }
private:
    int m_DerviedClassState;
};

class CDerivedClass2 : public CBaseClass
{
public:
    virtual void Serialize(CSerializer& ser)
    {
        ser.Write("CDerivedClass2");
        ser.Write(m_DerviedClassState);
        ser.Write(m_DerviedClassState2);

    }
    virtual void Deserialize(CDeserializer& dser)
    {
        dser.Read(m_DerviedClassState);
        dser.Read(m_DerviedClassState2);
    }
private:
    std::string m_DerviedClassState;
    bool m_DerviedClassState2;
};


std::vector<CBaseClass*> my_array;


void Serialize(CSerializer& ser)
{
    size_t size = my_array.size();
    ser.Write(size);
    for (size_t i=0; i<size; ++i)
        my_array[i]->Serialize(ser);
}

CBaseClass* DeserializeObject(CDeserializer& dser)
{
    std::string class_id;
    dser.Read(class_id);
    CBaseClass* obj = NULL;
    if (class_id == "CDerivedClass")
        obj = new CDerivedClass;
    else if (class_id == "CDerivedClass2")
        obj = new CDerivedClass2;

    // if obj is NULL its a fatal error but for now I dont do error handling
    obj->Deserialize(dser);
    return obj;
}

void Deserialize(CDeserializer& dser)
{
    size_t size;
    dser.Read(size);
    my_array.resize(size);
    for (size_t i=0; i<size; ++i)
        my_array[i] = DeserializeObject(dser);
}
 
Share this answer
 
v3
Comments
v.chjen 12-Jul-12 8:45am    
Thank you very much for very spending time to writting it
For save/load functions, is it possible to use tinibind/tinyxml libraries?
pasztorpisti 12-Jul-12 9:43am    
As you see I haven't provided the implementation of CSerializer/CDeserializer. You can implement it as you want. It can save to a memory stream, into a binary file, into a text file or xml. If you want to save xml then you can use your favorite library (I also like tinyxml). xml is hierarchic data so you might want to save each object and its properties to sub elements. To support this you should introduce a BeginGroup() and EndGroup() method to CSerializer/CDeserializer and call these before and after every object serialization/deserialization if the for loop in the global Serialize()/Deserialize() functions. This way you can introduce some kind of hierarchy and it looks better in general.

If you want to use many different serialization methods in the same program (for example to binary data in memory to send over network plus to xml file), then change the methods of CSerialzer and CDeserializer to pure virtual and then you can provide and pass in different implementations when you do the actual serialzation/deserialization. (CXmlFileSerializer, CBinaryFileSerializer, ...)
v.chjen 12-Jul-12 16:37pm    
if it is possible, could you please write a simple example of implementation of xml serialization?sorry, i am really new in c+
pasztorpisti 12-Jul-12 18:52pm    
Serialization in c++ is not an easy task because of the lack of reflection, wouldn't even consider it as a beginner task. But writing an xml or any other type of serializer is easy so we will let you think about it. You learn nothing if we solve everything for you.
Sergey Alexandrovich Kryukov 16-Oct-12 15:06pm    
Exactly. I voted 5 for the answer, because you gave the basic idea very clearly.

When it comes to C++ and serialization, I advise to look into boost --- please see my answer.
--SA

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900