c++serializationmfcclist

MFC serialization


i have to serialize a CList of base and derived classes. How can i do that.

typedef CList<Student*, Student*> StVec;

class Student : public CObject
{
public:
    DECLARE_SERIAL(Student);

    Student();
    Student(Student& s);
    Student(CString _name, CString _last, int _age);
    virtual ~Student(void);

    virtual void cin();
    virtual void cout();

    virtual void Serialize(CArchive& ar);

    static Student* FromInput();

    inline const CString GetName(){return name;}
    inline const CString GetLastName(){return last_name;}
    inline const int GetAge(){return age;}

    virtual inline Student& operator=( const Student &s ) 
    { 
        name = s.name; 
        last_name = s.last_name;
        age = s.age;
        return *this; 
    }

protected:
    CString name;
    CString last_name;
    int age;
};

class Warden : public Student
{
protected:
    virtual void Serialize(CArchive& ar);
    UINT salary;
};

class Group : public CObject
{
public: 
    DECLARE_SERIAL(Group);

    enum FindType { First = 0, Last, All};
    typedef bool (*StudentsFindCallback) (Student* student, void* condition);

    Group(){ name = _T("Default Group"); }
    Group(CString _name);
    Group(Group& s);

    ~Group();

    void CreateUser();
    void ShowUsers();
    //StVecOfIt FindUser(StudentsFindCallback f, void* condition, FindType ft);
    inline Student* getStudent(POSITION pos) {return students->GetNext(pos); }
    inline void DeleteUser(POSITION it){ students->RemoveAt(it); }
    virtual void Serialize(CArchive& ar);
    void Clean();

    /*static bool FindbyName(Student* student, void* condition);
    static bool FindbyLastName(Student* student, void* condition);
    static bool FindbyAge(Student* student, void* condition);*/

    virtual inline Group& operator=( const Group &s ) 
    { 
        name = s.name; 
        students = s.students;
        return *this; 
    }

protected:
    CString name;
    StVec* students;
};

void Student::Serialize(CArchive& ar)
{
    CObject::Serialize( ar );

    if (ar.IsStoring())
    {   
        ar.SerializeClass(Student::GetRuntimeClass());      
        ar << name << last_name << age;
    }
    else 
    {
        ar.SerializeClass(Student::GetRuntimeClass());
        ar >> name >> last_name >> age;
    }   
}
void Group::Serialize(CArchive& ar)
{
    ar.SerializeClass(RUNTIME_CLASS(Group));

    if (ar.IsStoring())
    {
        ar << (int)students->GetCount();

        POSITION pos = students->GetHeadPosition();
        while(pos != NULL)
        {
            Student* student = students->GetNext(pos);

            student->Serialize(ar);
        }
    }
    else 
    {       
        Clean();
        int count = 0;
        ar >> count;

        for(INT_PTR i = 0; i < count; ++i)
        {
            Student* st = new Student();
            st->Serialize(ar);
            students->AddTail(st);
        }
    }
}

I found an article at the codeproject but i'cant understend it at all.

Ofcourse i can add a flag which indicate the type of class. Also i can serialize to derived class and if the derived properties are empty use static_cast to derive it to base class. Or i'am thinking of using CArchive::ReadObject or CArchive::ReadClass to load classes, but is there another way to do it?


Solution

  • My MFC is rusty but I believe this should work (not tested!).

    Also, your Serialize() method should never call SerializeClass for its own class. It's up to the caller to decide to call it. For instance, the << and >> operators do it to identify the class of the object that comes next in the archive.

    void Student::Serialize( CArchive& ar ) 
    { 
        CObject::Serialize( ar ); 
    
        if (ar.IsStoring()) 
        {    // No need for SerializeClass here.
            ar << name << last_name << age; 
        } 
        else  
        {    // No need for SerializeClass here.
            ar >> name >> last_name >> age; 
        }    
    } 
    void Group::Serialize(CArchive& ar) 
    { 
        if (ar.IsStoring()) 
        { 
            ar << (int)students->GetCount(); 
    
            POSITION pos = students->GetHeadPosition(); 
            while(pos != NULL) 
            { 
                Student* student = students->GetNext(pos); 
               ar << student; // << includes class info about the serialized object
            } 
        } 
        else  
        {        
            Clean(); 
            int count = 0; 
            ar >> count; 
    
            for(INT_PTR i = 0; i < count; ++i) 
            { 
                CObject *p;
                ar >> p; // Deserialize whatever kind of object comes next
                students->AddTail(p); 
            } 
        } 
    }