内存中C ++对象的结构与结构

如果我有一个类如下

class Example_Class { private: int x; int y; public: Example_Class() { x = 8; y = 9; } ~Example_Class() { } }; 

和一个结构如下

 struct { int x; int y; } example_struct; 

example_struct内存结构与Example_Class类似

例如,如果我做了以下

 struct example_struct foo_struct; Example_Class foo_class = Example_Class(); memcpy(&foo_struct, &foo_class, sizeof(foo_struct)); 

foo_struct.x = 8foo_struct.y = 9 (即:与foo_struct.y = 9中的x,y值相同的值)?

我问的原因是我有一个C ++库(不想改变它)与C代码共享一个对象,我想用一个结构来表示来自C ++库的对象。 我只对对象的属性感兴趣。

我知道最理想的情况是让Example_class将C和C ++代码之间的通用结构包起来,但是改变使用的C ++库并不容易。

C ++标准保证 C struct和C ++ class (或struct相同的东西)的内存布局是相同的,只要C ++ class / struct符合POD (“普通旧数据”)的标准即可。 那么POD是什么意思?

一个类或结构是POD,如果:

  • 所有数据成员都是公共的,它们自己是POD或基本types(但不包括引用或指向成员types)或这样的数组
  • 它没有用户定义的构造函数,赋值运算符或析构函数
  • 它没有虚拟function
  • 它没有基类

关于唯一允许的“C ++ – isms”是非虚拟成员函数,静态成员和成员函数。

既然你的类有一个构造函数和一个析构函数,它在forms上不是PODtypes的,所以保证不成立。 (虽然,正如其他人所提到的,实际上,只要没有虚拟函数,这两种布局在你试过的任何编译器上可能是相同的)。

有关更多详细信息,请参见C ++ FAQ Lite的 [26.7]节。

example_struct的内存结构与Example_Class类似

行为不能保证,并且依赖于编译器。

话虽如此,答案是“是的,在我的机器上”,假设Example_Class不包含虚方法(并且不从基类inheritance)。

在你描述的情况下,答案是“可能是的”。 但是,如果类有任何虚函数(包括可以从基类inheritance的虚析构函数),或者使用多重inheritance,那么类的布局可能会有所不同。

添加到其他人所说的话(例如:编译器特定的,只要你没有虚函数,就可能工作):

我会强烈build议静态断言(编译时检查),如果你正在做这个sizeof(Example_class)== sizeof(example_struct)。 请参阅BOOST_STATIC_ASSERT或等效的编译器特定或自定义构造。 如果某人(或者某个东西,比如编译器发生变化)修改了这个类来使匹配无效,那么这是一个很好的第一道防线。 如果你想额外的检查,你也可以运行时检查成员的偏移量是否相同,哪个(和静态大小声明一起)将保证正确性。

C ++中的类和结构是等价的,除了一个结构的所有成员默认是公共的(类成员默认是私有的)。 这可以确保在C ++编译器中编译遗留的C代码将按预期工作。

没有什么能阻止你在结构体中使用所有奇特的C ++特性:

 struct ReallyAClass { ReallyAClass(); virtual !ReallAClass(); /// etc etc etc }; 

为什么不想在将数据传递给C时将类的成员分配给结构? 这样你就知道你的代码将在任何地方工作。

在C ++编译器的早期,有一些编译器首先用类更改struct关键字然后编译的例子。 非常相似。

差异来自类inheritance,特别是虚函数。 如果类包含虚函数,那么它的布局开始时必须有一个指向types描述符的指针。 另外,如果B类inheritance自A类,那么A类的布局首先是B类自己的布局。

因此,只需将类实例转换为结构实例的准确答案就是:取决于类的内容。 对于具有方法的特定类(构造函数和非虚拟析构函数),布局可能会相同。 如果将析构函数声明为虚拟的,则结构和类之间的布局肯定会变得不同。

下面是一篇文章,显示从C结构到C ++类没有太大的需要: 第1课 – 从结构到类

下面这篇文章解释了如何将虚拟函数表引入具有虚函数的类: 第4课 – 多态性

你可能只是公开或私下从结构中派生类。 然后将其转换成在C ++代码中正确parsing。