如何在C ++中将对象存储在内存中?
对于常规课程,例如
class Object
{
public:
int i1;
int i2;
char i3;
int i4;
private:
};
使用Object作为数组的指针可以用来访问i1,如下所示?
((Object*)&myObject)[0] === i1?
关于SO的其他问题似乎暗示将结构转换为指针将指向POD类型的第一个成员。如果有构造函数的类,这有什么不同? 另外,对于非POD类型,它有何不同?
编辑:
因此,在记忆中,上述课程的布局如下:
[i1 - 4bytes][i2 - 4bytes][i3 - 1byte][padding - 3bytes][i4 - 4bytes]
答案 0 :(得分:16)
几乎。你转换为一个Object *,而忽略了一个地址。让我们重新询问如下:
((int*)&myObject)[0] == i1
你必须非常小心这样的假设。正如您已定义的结构一样,在您可能遇到的任何编译器中都应如此。但是,正如其他人所说,对象的所有其他属性(您可能已从示例中省略)将使其成为非POD并且可能(可能以编译器相关的方式)使上述语句不正确。
请注意,如果你问过i3,我就不会这么快告诉你它会起作用 - 在这种情况下,即使对于普通的POD,对齐或字节顺序也很容易搞砸你。
无论如何,如果可能的话,你应该避免这种事情。即使它现在工作正常,如果你(或任何不理解你正在做这个技巧的人)改变结构顺序或添加新字段,这个技巧将在你使用它的所有地方失败,这可能很难找到。
回答您的编辑:如果这是您的整个类定义,并且您使用的是具有默认选项的主流编译器之一,并且在x86处理器上运行,那么是的,您可能已经猜到了正确的内存布局。但是,编译器,编译器选项和不同CPU架构的选择很容易使您的假设无效。
答案 1 :(得分:5)
没有虚拟成员且没有继承的类在内存中布局,就像结构一样。但是,当你开始获得继承级别时,事情会变得棘手,很难弄清楚内存中的顺序(特别是多重继承)。
当你有虚拟成员时,它们在内存中有一个“vtable”,它包含指向实际函数的指针,该函数是根据类的继承层次结构创建的。
底线是:如果你能避免它,就不要以这种方式访问类(也不要记住它们或记忆它们)。如果你必须这样做(为什么?),那么请注意你确切知道你的类对象将如何在内存中,并小心避免继承。
答案 2 :(得分:3)
不同之处在于此技巧仅对POD类型有效。这就是它的全部内容。该标准指定此强制转换对POD类型有效,但不保证非POD类型会发生什么。
答案 3 :(得分:2)
这实际上取决于编译器,或者更确切地说,由编译器决定内存布局。
例如,可以布置公共,私有和受保护成员变量的混合,以使每个访问类型是连续的。或者,派生类可以将成员变量与超类中未使用的空间交织。
虚拟继承会变得更糟,虚拟继承的基类可以在为该特定实例分配的内存中任何地方布局。
POD不同,因为它需要与C兼容。
答案 4 :(得分:0)
通常重要的不是类是否有构造函数:重要的是类是否有任何虚方法。有关详细信息,请搜索“vtable”和“vptr”。