为基础和派生实现 MFC 序列化 类

Implementing MFC Serialazation for base and derived classes

我有两个 classes:Product 和 derived Juice。我需要为这些 classes 实现 MFC 序列化。

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;
    }

};

为了存储 classes 的 object,我有库存 class,其中包含产品 class 指针的容器。

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();
};

在 Save 和 Load 方法中,我试图实现序列化(根据本主题 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;
}

现在我遇到了问题。

从文件中读取 objects 时 Juice objects 被读取为产品(没有 volume ant taste 字段)。 Juice 之后的 object 的读取是从 Juice 的其余信息开始的,所以我在 Product 的 Serialaize 方法中得到了 CArchiveException

如果我只使用 Product objects 添加到 Stock 一切正常。我的错误是什么,我应该怎么做才能正确实现MFC序列化?

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不会保存类型数据

作为参考,这是 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];
}