反序列化构造层次 [英] Deserializing constructor hierarchy
问题描述
(这个问题是非常相似的<一href=\"http://stackoverflow.com/questions/35722135/deserializing-construtor-doesnt-read-data-correctly\">this 之一,但是这一次我打电话了父
反序列化中的儿童
初始化列表构造函数)。
在其中儿童
没有增加任何新数据序列化的情况下,父
没有默认构造函数中,我希望能够序列化父
对象直接以及在儿童
,并没有孩子,也没有家长有默认的构造函数,这似乎是我们应该在初始化列表中使用以下模式,那里的孩子反序列化构造函数初始化父(也使用其反序列化的构造函数):
的#include&LT;升压/存档/ text_oarchive.hpp&GT;
#包括LT&;升压/存档/ text_iarchive.hpp&GT;#包括LT&;&的fstream GT;父类
{
上市:
双mParentData; 家长(常量双倍数据):mParentData(数据){} 模板&LT; typename的TArchive&GT;
家长(TArchive&安培;存档)
{
归档&GT;&GT; *这个;
} 模板&LT;类TArchive&GT;
无效连载(TArchive&安培;归档,const的无符号整型版)
{
归档和放大器; mParentData;
}
};儿童类:公共父
{
上市: 儿童(常量双倍数据):父(数据){} 模板&LT; typename的TArchive&GT;
儿童(TArchive&安培;存档):家长(存档)
{
//什么也不做,因为读的唯一数据是在父
} 模板&LT;类TArchive&GT;
无效连载(TArchive&安培;归档,const的无符号整型版)
{
//让家长尽其系列化
归档和放大器;提高::系列化:: base_object&LT;家长和GT;(*此); //闲来无事,作为唯一的数据读/写在家长
}
};诠释的main()
{
孩童(1.2); {
的std ::的ofstream的OutputStream(的test.txt);
提高::档案:: text_oarchive的outputArchive(OutputStream中); outputArchive&LT;&LT;儿童;
outputStream.close();
} {
性病:: ifstream的InputStream的(的test.txt);
提高::档案:: text_iarchive inputArchive(InputStream的);
儿童childRead(inputArchive); 性病::法院LT&;&LT; childRead:&所述;&下;的std :: ENDL
&LT;&LT; childRead.mParentData&LT;&LT;的std :: ENDL; //输出0(预期1.2)
} 返回0;
}
所以调用链应该(和不)如下:
输出:
- 子::连载()
- 父::连载()
输入:
- 子(存档)
- 父(存档)
- 父::连载()
但是, mParentData code>在
childRead $ C $最终为
0
C>,当我希望它是 1.2
。
任何人都可以发现这个错误吗?
----------- -----------编辑
正如@stijn指出,在孩子没有额外的数据序列化的情况下,我们可以简单地删除连载()
从功能孩子
完全,像这样的:
的#include&LT;升压/存档/ text_oarchive.hpp&GT;
#包括LT&;升压/存档/ text_iarchive.hpp&GT;#包括LT&;&的fstream GT;父类
{
上市:
双mParentData; 家长(常量双倍数据):mParentData(数据){} 模板&LT; typename的TArchive&GT;
家长(TArchive&安培;存档)
{
归档&GT;&GT; *这个;
} 模板&LT;类TArchive&GT;
无效连载(TArchive&安培;归档,const的无符号整型版)
{
归档和放大器; mParentData;
}
};儿童类:公共父
{
上市: 儿童(常量双倍数据):父(数据){} 模板&LT; typename的TArchive&GT;
儿童(TArchive&安培;存档):家长(存档)
{
//什么也不做,因为读的唯一数据是在父
}};诠释的main()
{
孩童(1.2); {
的std ::的ofstream的OutputStream(的test.txt);
提高::档案:: text_oarchive的outputArchive(OutputStream中); outputArchive&LT;&LT;儿童;
outputStream.close();
} {
性病:: ifstream的InputStream的(的test.txt);
提高::档案:: text_iarchive inputArchive(InputStream的);
儿童childRead(inputArchive); 性病::法院LT&;&LT; childRead:&所述;&下;的std :: ENDL
&LT;&LT; childRead.mParentData&LT;&LT;的std :: ENDL; //输出0(预期1.2)
} 返回0;
}
不过,在情况下,当这两个孩子和家长有数据序列化,他们都没有一个默认的构造函数,该模式似乎将要成为像以下,但并不完全。在儿童
反序列化的构造函数,我们呼吁双方父
反序列化的构造,也是儿童::连载()
函数,该函数调用父::连载()
的功能,所以有效地父
将试图反序列化的两倍。这种不正确的行为表现出在这里:
的#include&LT;升压/存档/ text_oarchive.hpp&GT;
#包括LT&;升压/存档/ text_iarchive.hpp&GT;#包括LT&;&的fstream GT;父类
{
上市:
双mParentData; 家长(常量双倍数据):mParentData(数据){} 模板&LT; typename的TArchive&GT;
家长(TArchive&安培;存档)
{
归档&GT;&GT; *这个;
} 模板&LT;类TArchive&GT;
无效连载(TArchive&安培;归档,const的无符号整型版)
{
归档和放大器; mParentData;
}
};儿童类:公共父
{
上市: 双mChildData; 儿童(常量双parentData,常量双childData):家长(parentData),mChildData(childData){} 模板&LT; typename的TArchive&GT;
儿童(TArchive&安培;存档):家长(存档)
{
归档&GT;&GT; *这个;
} 模板&LT;类TArchive&GT;
无效连载(TArchive&安培;归档,const的无符号整型版)
{
//让家长尽其系列化
归档和放大器;提高::系列化:: base_object&LT;家长和GT;(*此); //执行的孩子系列化
归档和放大器; mChildData;
}
};诠释的main()
{
孩童(1.2,3.4); {
的std ::的ofstream的OutputStream(的test.txt);
提高::档案:: text_oarchive的outputArchive(OutputStream中); outputArchive&LT;&LT;儿童;
outputStream.close();
} {
性病:: ifstream的InputStream的(的test.txt);
提高::档案:: text_iarchive inputArchive(InputStream的);
儿童childRead(inputArchive); 性病::法院LT&;&LT; childRead:&所述;&下;的std :: ENDL
&LT;&LT; childRead.mParentData&LT;&LT;的std :: // ENDL 0.2输出(预期1.2)
&LT;&LT; childRead.mChildData&LT;&LT;的std :: ENDL; //输出3.4正确
} 返回0;
}
好像在某种程度上我们需要调用不同版本的儿童::连载的()
从儿童
反序列化的构造函数?或者设置一个标志,没有明确的反序列化父
从儿童::连载()
如果从<$称为C $ C>儿童反序列化的构造函数?
如果我们改变了儿童::连载()
来下,我得到一个段错误:
模板&LT;类TArchive&GT;
无效连载(TArchive&安培;归档,const的无符号整型版)
{
//让家长尽其系列化
家长::连载(存档版本); //执行的孩子系列化
归档和放大器; mChildData;
}
我相信,你不需要反序列化转发给家长。
更改code到
的#include&LT;升压/存档/ text_oarchive.hpp&GT;
#包括LT&;升压/存档/ text_iarchive.hpp&GT;#包括LT&;&的fstream GT;父类
{
上市:
双mParentData; 家长(常量双倍数据):mParentData(数据){} 模板&LT; typename的TArchive&GT;
家长(TArchive&安培;归档,布尔反序列化= FALSE)
{
如果(!反序列化)
归档&GT;&GT; *这个;
} 模板&LT;类TArchive&GT;
无效连载(TArchive&安培;归档,const的无符号整型版)
{
归档和放大器; mParentData;
}
};儿童类:公共父
{
上市: 儿童(常量双倍数据):父(数据){} 模板&LT; typename的TArchive&GT;
儿童(TArchive&安培;存档):家长(存档,真)
{
归档&GT;&GT; *这个;
} 模板&LT;类TArchive&GT;
无效连载(TArchive&安培;归档,const的无符号整型版)
{
//让家长尽其系列化
归档和放大器;提高::系列化:: base_object&LT;家长和GT;(*此); //闲来无事,作为唯一的数据读/写在家长
}
};诠释的main()
{
{
孩童(1.2);
的std ::的ofstream的OutputStream(的test.txt);
提高::档案:: text_oarchive的outputArchive(OutputStream中); outputArchive&LT;&LT;儿童;
outputStream.close();
} {
性病:: ifstream的InputStream的(的test.txt);
提高::档案:: text_iarchive inputArchive(InputStream的);
儿童childRead(inputArchive);
性病::法院LT&;&LT; childRead:&所述;&下;的std :: ENDL
&LT;&LT; childRead.mParentData&LT;&LT;的std :: ENDL; //输出0(预期1.2)
} 返回0;
}
我的作品。
(This question is very similar to this one, but this time I am calling the Parent
deserializing constructor in the Child
initialization list).
In a case where a Child
adds no new data to be serialized, the Parent
does not have a default constructor, I want to be able to serialize the Parent
object directly as well as the Child
, and neither the child nor the parent have default constructors, it seems like we should use the following pattern, where the child deserializing constructor initializes the parent (also using its deserializing constructor) in the initialization list:
#include <boost/archive/text_oarchive.hpp>
#include <boost/archive/text_iarchive.hpp>
#include <fstream>
class Parent
{
public:
double mParentData;
Parent(const double data) : mParentData(data) {}
template<typename TArchive>
Parent(TArchive& archive)
{
archive >> *this;
}
template<class TArchive>
void serialize(TArchive& archive, const unsigned int version)
{
archive & mParentData;
}
};
class Child : public Parent
{
public:
Child(const double data) : Parent(data) {}
template<typename TArchive>
Child(TArchive& archive) : Parent(archive)
{
// Do nothing, as the only data to read is in Parent
}
template<class TArchive>
void serialize(TArchive& archive, const unsigned int version)
{
// Let the parent do its serialization
archive & boost::serialization::base_object<Parent>(*this);
// Nothing else to do, as the only data to read/write is in Parent
}
};
int main()
{
Child child(1.2);
{
std::ofstream outputStream("test.txt");
boost::archive::text_oarchive outputArchive(outputStream);
outputArchive << child;
outputStream.close();
}
{
std::ifstream inputStream("test.txt");
boost::archive::text_iarchive inputArchive(inputStream);
Child childRead(inputArchive);
std::cout << "childRead:" << std::endl
<< childRead.mParentData << std::endl; // Outputs 0 (expected 1.2)
}
return 0;
}
So the call chain should (and does) look like:
Output:
- Child::serialize()
- Parent::serialize()
Input:
- Child(archive)
- Parent(archive)
- Parent::serialize()
However, the mParentData
ends up as 0
in childRead
, when I would expect it to be 1.2
.
Can anyone spot the error?
----------- EDIT -----------
As pointed out by @stijn , in the case where the child has no additional data to serialize, we can simply remove the serialize()
function from Child
entirely, like this:
#include <boost/archive/text_oarchive.hpp>
#include <boost/archive/text_iarchive.hpp>
#include <fstream>
class Parent
{
public:
double mParentData;
Parent(const double data) : mParentData(data) {}
template<typename TArchive>
Parent(TArchive& archive)
{
archive >> *this;
}
template<class TArchive>
void serialize(TArchive& archive, const unsigned int version)
{
archive & mParentData;
}
};
class Child : public Parent
{
public:
Child(const double data) : Parent(data) {}
template<typename TArchive>
Child(TArchive& archive) : Parent(archive)
{
// Do nothing, as the only data to read is in Parent
}
};
int main()
{
Child child(1.2);
{
std::ofstream outputStream("test.txt");
boost::archive::text_oarchive outputArchive(outputStream);
outputArchive << child;
outputStream.close();
}
{
std::ifstream inputStream("test.txt");
boost::archive::text_iarchive inputArchive(inputStream);
Child childRead(inputArchive);
std::cout << "childRead:" << std::endl
<< childRead.mParentData << std::endl; // Outputs 0 (expected 1.2)
}
return 0;
}
However, in the case when both the child and parent have data to serialize, and they both do not have a default constructor, the pattern seems like it would need to be something like the following, but not quite. In the Child
deserializing constructor, we are calling both the Parent
deserializing constructor, but also the Child::serialize()
function, which calls the Parent::serialize()
function, so effectively the Parent
would try to deserialize twice. This incorrect behavior is demonstrated here:
#include <boost/archive/text_oarchive.hpp>
#include <boost/archive/text_iarchive.hpp>
#include <fstream>
class Parent
{
public:
double mParentData;
Parent(const double data) : mParentData(data) {}
template<typename TArchive>
Parent(TArchive& archive)
{
archive >> *this;
}
template<class TArchive>
void serialize(TArchive& archive, const unsigned int version)
{
archive & mParentData;
}
};
class Child : public Parent
{
public:
double mChildData;
Child(const double parentData, const double childData) : Parent(parentData), mChildData(childData) {}
template<typename TArchive>
Child(TArchive& archive) : Parent(archive)
{
archive >> *this;
}
template<class TArchive>
void serialize(TArchive& archive, const unsigned int version)
{
// Let the parent do its serialization
archive & boost::serialization::base_object<Parent>(*this);
// Do the child serialization
archive & mChildData;
}
};
int main()
{
Child child(1.2, 3.4);
{
std::ofstream outputStream("test.txt");
boost::archive::text_oarchive outputArchive(outputStream);
outputArchive << child;
outputStream.close();
}
{
std::ifstream inputStream("test.txt");
boost::archive::text_iarchive inputArchive(inputStream);
Child childRead(inputArchive);
std::cout << "childRead:" << std::endl
<< childRead.mParentData << std::endl // Outputs 0.2 (expected 1.2)
<< childRead.mChildData << std::endl; // Outputs 3.4 correctly
}
return 0;
}
It seems like somehow we need to call a different version of Child::serialize()
from the Child
deserializing constructor? Or set a flag to not explicitly deserialize Parent
from Child::serialize()
if it is called from the Child
deserializing constructor?
If we change the Child::serialize()
to the following, I get a segfault:
template<class TArchive>
void serialize(TArchive& archive, const unsigned int version)
{
// Let the parent do its serialization
Parent::serialize(archive, version);
// Do the child serialization
archive & mChildData;
}
I believe that you don't need to forward the deserialization to the parent. Changing your code to
#include <boost/archive/text_oarchive.hpp>
#include <boost/archive/text_iarchive.hpp>
#include <fstream>
class Parent
{
public:
double mParentData;
Parent(const double data) : mParentData(data) {}
template<typename TArchive>
Parent(TArchive& archive, bool deserialize = false)
{
if (!deserialize)
archive >> *this;
}
template<class TArchive>
void serialize(TArchive& archive, const unsigned int version)
{
archive & mParentData;
}
};
class Child : public Parent
{
public:
Child(const double data) : Parent(data) {}
template<typename TArchive>
Child(TArchive& archive) : Parent(archive, true)
{
archive >> *this;
}
template<class TArchive>
void serialize(TArchive& archive, const unsigned int version)
{
// Let the parent do its serialization
archive & boost::serialization::base_object<Parent>(*this);
// Nothing else to do, as the only data to read/write is in Parent
}
};
int main()
{
{
Child child(1.2);
std::ofstream outputStream("test.txt");
boost::archive::text_oarchive outputArchive(outputStream);
outputArchive << child;
outputStream.close();
}
{
std::ifstream inputStream("test.txt");
boost::archive::text_iarchive inputArchive(inputStream);
Child childRead(inputArchive);
std::cout << "childRead:" << std::endl
<< childRead.mParentData << std::endl; // Outputs 0 (expected 1.2)
}
return 0;
}
works for me.
这篇关于反序列化构造层次的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!