为基础和派生实现 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];
}
我有两个 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];
}