Реализация MFC Serialazation для базовых и производных классов - PullRequest
1 голос
/ 01 октября 2019

У меня есть два класса: продукт и производный сок. Мне нужно реализовать MFC Serialazation для этих классов.

class Product : CObject
{
protected:
    DECLARE_SERIAL(Product) //IMPLEMENT_SERIAL(Product, CObject, 0) in .cpp

    CString name;
    int expiring;
    double price;
public:
    Product();
    ~Product();

    virtual void input_data();
    virtual void print_data();

    virtual void Serialize(CArchive& archive)
    {
        CObject::Serialize(archive);

        if (archive.IsStoring())
            archive << name << expiring << price;
        else
            archive >> name >> expiring >> price;
    };

};
class Juice :
    public Product
{

private:
    double volume; 
    CString taste;
public:
    Juice();
    ~Juice();

    void input_data() override;
    void print_data() override;

    void Serialize(CArchive& archive) override
    {
        Product::Serialize(archive);
        if (archive.IsStoring())
            archive << volume << taste;
        else
            archive >> volume >> taste;
    }

};

Для хранения объектов классов у меня есть класс Stock, в котором есть контейнер указателей класса Product.

class Stock
{
private:
    vector<shared_ptr<Product>> stock;
public:
    Stock();
    ~Stock();

    void Add(shared_ptr<Product> p); 
    void Print(); 

    bool Save(string fname);
    bool Load(string fname);

    void Clear();
};

В методах сохранения и загрузки я пытаюсь реализовать сериализацию (согласно обсуждению в этой теме C ++ MFC Serialization ).

bool Stock::Save(string fname)
{
    CFile out;
    if (!out.Open(fname.c_str(), CFile::modeWrite | CFile::modeCreate))
        return false;

    CArchive ar(&out, CArchive::store);
    ar.WriteCount(stock.size());
    for (auto it = stock.begin(); it != stock.end(); ++it)
    {
        (*it)->Serialize(ar);
    }
    ar.Close();
    out.Close();
    return true;
}

bool Stock::Load(string fname)
{
    CFile in;
    if (!in.Open(fname.c_str(), CFile::modeRead))
        return false;

    CArchive ar(&in, CArchive::load);
    int cnt = ar.ReadCount();
    for (int i = 0; i < cnt; i++)
    {
        auto p = make_shared<Product>();
        p->Serialize(ar);
        stock.push_back(p);
    }
    ar.Close();
    in.Close();
    return true;
}

Теперь явозникла проблема.

При чтении объектов из файла объекты Juice читаются как Product (без полей volume ant вкуса ). Чтение объекта после Juice начинается с остальной информации о Juice, поэтому я получил CArchiveException в методе Serialaize Product.

exception

Если я использую только объекты Product для добавления в Stock, все работает отлично. В чем мои ошибки и что я должен сделать для правильной реализации сериализации MFC?

1 Ответ

2 голосов
/ 01 октября 2019

Stock :: Save необходимо изменить на:

for (auto it = stock.begin(); it != stock.end(); ++it)
{
    ar << (*it).get();
}

И Stock :: Load необходимо изменить на:

for (int i = 0; i < cnt; i++)
{
    Product* obj = nullptr;
    ar >> obj;

    stock.emplace_back(obj);
}

Когда вы используете ar << obj, он сохраняетвведите информацию вместе с объектом, чтобы ее можно было правильно найти при загрузке. Непосредственный вызов Serialize не сохранит данные типа. </p>

Для справки, вот как выглядит код сериализации MFC внутри CObArray (в основном то, что вы будете использовать вместо вектора, если будете использовать только MFC)

if (ar.IsStoring())
{
    ar.WriteCount(m_nSize);
    for (INT_PTR i = 0; i < m_nSize; i++)
        ar << m_pData[i];
}
else
{
    DWORD_PTR nOldSize = ar.ReadCount();
    SetSize(nOldSize);
    for (INT_PTR i = 0; i < m_nSize; i++)
        ar >> m_pData[i];
}
...