1

我有两个类:产品和派生果汁。我需要为这些类实现 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();
};

在 Save and 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;
}

现在我遇到了问题。

从文件中读取对象时,Juice 对象的读取方式与 Product 类似(没有体积蚂蚁味觉字段)。Juice 之后对象的读取是从其余的 Juice 信息开始的,所以我在 Product 的 Serialaize 方法中得到了CArchiveException

例外

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

4

1 回答 1

2

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];
}
于 2019-10-01T14:26:12.523 回答