在C++中使用重载构造函数反序列化对象是一种很好的做法,还是最好创建一个成员函数反序列化(std::istream&file(?
我建议创建一个单独的deserializer函数,因为它分离了责任(即构造函数不需要担心如何获取信息(。
例如
class Foo
{
Foo(int x)
...
}
Foo FooDeserialiser(Data data)
{
// get data to pass to constructor
return Foo(someInt);
}
您可以创建一个成员函数,但我个人更喜欢将其与类分离(尽管我经常将其放在同一个文件中(,因为对我来说,这会破坏封装。
是的。您可以避免两步初始化以及由此引发的所有问题。有些opject"未初始化"的存在是没有意义的。因此,至少在这种情况下,您应该将序列化代码放入构造函数中。这种设计的优点是,您可以使用相同的构造函数进行读写。并且不能违反初始化基类或成员类的顺序。唯一的缺点是,在编写时,您会临时创建要写入的对象的副本。如果这是一个问题,您仍然可以将构造函数代码复制到某个编写方法中。当然,你应该是本世纪的一部分,在阅读和写作时对错误使用异常处理。你真的想让CReadWrite类可以从一些抽象的CRead和CWrite中构造出来,这样你就可以从"某处"读写,包括文件、管道、套接字、内存缓冲区,谁知道你的客户后天会出现什么。
struct CReadWrite;
struct A:B
{ std::string m_sName;
A(const A *const pWrite, CReadWrite *const pFile)
:B(pWrite ? static_cast<B*>(pWrite) : 0, pFile),
m_sName(pFile->readWrite(pWrite ? &pWrite->m_sName : 0))
{
}
};
读取:
CReadWrite sFile("test.dat", "r");
A sA(0, &sFile);
写入:
CReadWrite sFile("test.dat", "w");
A sA;
A(&sA, &sFile);
在构造函数中进行反序列化可能会限制您处理失败情况(例如,损坏的输入数据(的灵活性。专门的成员功能更灵活。例如,它允许return
一个状态值,而构造函数不能返回一个表示失败的值。您是否需要以失去RAII为代价的这种灵活性取决于您。