在C ++中使用重载构造函数反序列化对象是一个好习惯,或者最好创建一个成员函数deserialize(std :: istream& file)?
答案 0 :(得分:5)
我建议创建一个单独的deserialiser函数,因为它分离了责任(即构造函数不需要担心它如何获取它的信息)。
例如
class Foo
{
Foo(int x)
...
}
Foo FooDeserialiser(Data data)
{
// get data to pass to constructor
return Foo(someInt);
}
你可以创建一个成员函数,但我个人更喜欢将它与该类分开(尽管我经常把它放在同一个文件中),对我而言,这将破坏封装。 / p>
答案 1 :(得分:1)
在构造函数中放入反序列化可能会限制您处理失败案例的灵活性(例如,损坏的输入数据)。专用成员函数更灵活。例如,它允许您return
状态值,而构造函数不能返回值来指示失败。是否需要以牺牲RAII为代价来实现这种灵活性取决于您。
答案 2 :(得分:1)
是的。您可以避免两步初始化以及由此引起的所有问题。一些对象没有意义存在“未初始化”。因此,至少在这种情况下,您应该将序列化代码放入构造函数中。这种设计的优点是,您可以使用相同的构造函数进行读写。而且您无法违反基类或成员类的初始化顺序。唯一的缺点是,对于写入,您临时创建要写入某处的对象的副本。如果这是一个问题,您仍然可以将构造函数代码复制到某个write方法中。当然,您应该成为本世纪的一部分,并在阅读和写作时使用异常处理来处理错误。而且你真的想要从一些抽象的CRead和CWrite构造CReadWrite类,这样你就可以从/到“某处”进行读写,包括文件,管道,套接字,内存缓冲区,以及谁知道你的客户会去哪里后天来了。
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);