更改继承顺序会产生不同的结果 我在C++中阅读思维,发现这段代码: //: C06:Persist1.cpp // Simple persistence with MI #include <iostream> #include <fstream> using namespace std; class Persistent { int objSize; // Size of stored object public: Persistent(int sz) : objSize(sz) {} void write(ostream& out) const { out.write((char*)this, objSize); } void read(istream& in) { in.read((char*)this, objSize); } }; class Data { float f[3]; public: Data(float f0 = 0.0, float f1 = 0.0, float f2 = 0.0) { f[0] = f0; f[1] = f1; f[2] = f2; } void print(const char* msg = "") const { if(*msg) cout << msg << " "; for(int i = 0; i < 3; i++) cout << "f[" << i << "] = " << f[i] << endl; } }; class WData1 : public Persistent, public Data { public: WData1(float f0 = 0.0, float f1 = 0.0, float f2 = 0.0) : Data(f0, f1, f2), Persistent(sizeof(WData1)) { cout<<"size of w1 "<<sizeof(WData1)<<endl; } }; class WData2 : public Data, public Persistent { public: WData2(float f0 = 0.0, float f1 = 0.0, float f2 = 0.0) : Data(f0, f1, f2), Persistent(sizeof(WData2)) { cout<<"size of w2 "<<sizeof(WData2)<<endl; } }; int main() { { ofstream f1("f1.dat"), f2("f2.dat"),f3("f3.dat"), f4("f4.dat"); WData1 d1(1.1, 2.2, 3.3); WData2 d2(4.4, 5.5, 6.6); WData1 d3(1.1, 2.2, 3.3); WData2 d4(4.4, 5.5, 6.6); d1.print("d1 before storage"); d2.print("d2 before storage"); d3.print("d3 before storage"); d4.print("d4 before storage"); d1.write(f1); d2.write(f2); d3.write(f3); d4.write(f4); } // Closes files ifstream f1("f1.dat"), f2("f2.dat"),f3("f3.dat"), f4("f4.dat"); WData1 d1; WData2 d2; WData1 d3; WData2 d4; d1.read(f1); d2.read(f2); d3.read(f3); d4.read(f4); d1.print("d1 before storage"); d2.print("d2 before storage"); d3.print("d3 before storage"); d4.print("d4 before storage"); } ///:~

更改继承顺序会产生不同的结果 我在C++中阅读思维,发现这段代码: //: C06:Persist1.cpp // Simple persistence with MI #include <iostream> #include <fstream> using namespace std; class Persistent { int objSize; // Size of stored object public: Persistent(int sz) : objSize(sz) {} void write(ostream& out) const { out.write((char*)this, objSize); } void read(istream& in) { in.read((char*)this, objSize); } }; class Data { float f[3]; public: Data(float f0 = 0.0, float f1 = 0.0, float f2 = 0.0) { f[0] = f0; f[1] = f1; f[2] = f2; } void print(const char* msg = "") const { if(*msg) cout << msg << " "; for(int i = 0; i < 3; i++) cout << "f[" << i << "] = " << f[i] << endl; } }; class WData1 : public Persistent, public Data { public: WData1(float f0 = 0.0, float f1 = 0.0, float f2 = 0.0) : Data(f0, f1, f2), Persistent(sizeof(WData1)) { cout<<"size of w1 "<<sizeof(WData1)<<endl; } }; class WData2 : public Data, public Persistent { public: WData2(float f0 = 0.0, float f1 = 0.0, float f2 = 0.0) : Data(f0, f1, f2), Persistent(sizeof(WData2)) { cout<<"size of w2 "<<sizeof(WData2)<<endl; } }; int main() { { ofstream f1("f1.dat"), f2("f2.dat"),f3("f3.dat"), f4("f4.dat"); WData1 d1(1.1, 2.2, 3.3); WData2 d2(4.4, 5.5, 6.6); WData1 d3(1.1, 2.2, 3.3); WData2 d4(4.4, 5.5, 6.6); d1.print("d1 before storage"); d2.print("d2 before storage"); d3.print("d3 before storage"); d4.print("d4 before storage"); d1.write(f1); d2.write(f2); d3.write(f3); d4.write(f4); } // Closes files ifstream f1("f1.dat"), f2("f2.dat"),f3("f3.dat"), f4("f4.dat"); WData1 d1; WData2 d2; WData1 d3; WData2 d4; d1.read(f1); d2.read(f2); d3.read(f3); d4.read(f4); d1.print("d1 before storage"); d2.print("d2 before storage"); d3.print("d3 before storage"); d4.print("d4 before storage"); } ///:~,c++,inheritance,C++,Inheritance,到 我很好奇为什么继承顺序在这种情况下会有所不同。这难道不应该有什么区别吗?问题是,在类Persistent中,您使用this指向要读/写的内存的开头。这是一个问题,因为您将其用作继承类。因此,除非Persistent不是继承的第一个类,这个不会指向基类的开头: 这是我们为Wdata1和Wdata2所做的(填充和对齐忽略): Wdata1 +-----------+----------------------+ |objSize | f[0]f[1]f[2]| +-----------+----


我很好奇为什么继承顺序在这种情况下会有所不同。这难道不应该有什么区别吗?

问题是,在类Persistent中,您使用
this
指向要
读/写的内存的开头。这是一个问题,因为您将其用作继承类。因此,除非
Persistent
不是继承的第一个类,
这个
不会指向基类的开头:

这是我们为
Wdata1
Wdata2
所做的(填充和对齐忽略):

Wdata1
+-----------+----------------------+
|objSize | f[0]f[1]f[2]|
+-----------+----------------------+
|持久数据|
^
|
这(指持久的)
||
WData2
+----------------------+-----------+
|f[0]f[1]f[2]|对象化|
+----------------------+-----------+
|数据|持久|
^
|
这(指持久的)
||

问题的原因可能是
WData2
构造函数初始化列表中的基类初始化。您需要按照继承基类的相同顺序调用基类构造函数

所以改变

WData2(...) : Data(...), Persistent(...) { ... }


问题在于
持久性
中的调用:

out.write((char*)this, objSize);
in.read((char*)this, objSize);
这里,
this
是一个
Persistent*
,假设它指向完整对象的开始。只有当
Persistent
是第一个基类时,这才是正确的

要想在任何地方工作,你都可以使用这个鲜为人知的技巧:

void *that = dynamic_cast<void*>(this);
out.write((char*)that, objSize);
in.read((char*)that, objSize);
void*that=dynamic\u cast(此);
写出((char*),objSize);
in.read((char*)that,objSize);
dynamic\u cast()
保证您将拥有指向最派生对象的指针


警告:唉!除非类型是多态的,否则这将不起作用。而且
持久性
技巧对多态类型不起作用。所以这个答案,实际上是没有用的。我不会删除它,因为它可能仍然很有趣,为什么你不应该这样做。

,而且别忘了阅读Mat的评论。这种持久性看起来很糟糕,但它在我的机器中工作。问题是,第二个没有。我读的是我写的同一个类的结构,所以数据成员布局应该无关紧要,因为我读写了这个类的全部内容,我来看看WData2。它的布局可能看起来像:float int。可能有可选的填充。当机器从对象的请求中保存内存,并以对象的请求+其大小结束时,它应该在将以前读取的内容写入内存后恢复该对象。请参阅我的编辑关于
。这是你的核心问题。但其余的还是值得考虑的,我还是不明白。WData2中的“this”指向类的持久部分,这不是Begging?然后,如果我从这里读取,以这个+大小结束,我读取持久化的内存内容,以及一些不属于WData2对象的内存内容,但是其他内容?是的,因为你不使用
WData2的
this
,你使用
持久化的
this
WData2(...) : Data(...), Persistent(...) { ... }
WData2(...) : Persistent(...), Data(...) { ... }
out.write((char*)this, objSize);
in.read((char*)this, objSize);
void *that = dynamic_cast<void*>(this);
out.write((char*)that, objSize);
in.read((char*)that, objSize);