如果我有一个课程如下
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 = 8
和foo_struct.y = 9
(即:与foo_class中的x,y值相同的值)?
我问的原因是我有一个C ++库(不想改变它),它与C代码共享一个对象,我想使用一个结构来表示来自C ++库的对象。我只对对象的属性感兴趣。
我知道理想情况是将Example_class包装在C和C ++代码之间的公共结构中,但是更改正在使用的C ++库并不容易。
答案 0 :(得分:61)
C ++标准保证 C struct
和C ++ class
(或struct
- 相同的东西)的内存布局将是相同的,前提是C ++ class
/ struct
符合 POD (“普通旧数据”)的标准。 POD是什么意思?
如果出现以下情况,则类或结构为POD:
关于唯一允许的“C ++ - isms”是非虚拟成员函数,静态成员和成员函数。
由于您的类同时具有构造函数和析构函数,因此它正式说不是POD类型,因此保证不成立。 (尽管正如其他人所提到的,实际上,只要没有虚函数,在您尝试的任何编译器上,两个布局可能都是相同的。)
有关详细信息,请参阅C++ FAQ Lite的[26.7]部分。
答案 1 :(得分:10)
example_struct的内存结构是否与Example_Class
中的结构相似
行为无法保证,并且与编译器有关。
话虽如此,答案是“是的,在我的机器上”,只要Example_Class不包含虚方法(并且不从基类继承)。
答案 2 :(得分:7)
在您描述的情况下,答案是“可能是的”。但是,如果该类具有任何虚函数(包括可以从基类继承的虚析构函数),或者使用多重继承,那么类布局可能会有所不同。
答案 3 :(得分:3)
添加其他人所说的内容(例如:编译器特定的,只要你没有虚函数就可能会有效):
如果您这样做,我强烈建议使用sizeof(Example_class)== sizeof(example_struct)的静态断言(编译时检查)。请参见BOOST_STATIC_ASSERT,或等效的编译器特定或自定义构造。如果某人(或某些东西,例如编译器更改)修改了类以使匹配无效,那么这是一个很好的第一道防线。如果你想要额外的检查,你也可以运行时检查成员的偏移量是否相同,哪些(与静态大小断言一起)将保证正确性。
答案 4 :(得分:1)
在C ++编译器的早期,有一些例子,编译器首先用类更改struct关键字然后编译。关于相似之处。
差异来自类继承,尤其是虚函数。如果类包含虚函数,那么它必须在其布局的开头有一个指向描述符类型的指针。另外,如果B类继承自A类,则首先是A类的布局,然后是B类自己的布局。
因此,关于将类实例转换为结构实例的问题的准确答案是:取决于类的内容。对于具有方法(构造函数和非虚函数析构函数)的特定类,布局可能会相同。如果析构函数被声明为虚拟,那么布局在结构和类之间肯定会有所不同。
这篇文章表明,从C结构到C ++类没有太多需要做的事情:Lesson 1 - From Structure to Class
这篇文章解释了如何将虚函数表引入具有虚函数的类:Lesson 4 - Polymorphism
答案 5 :(得分:0)
课程& C ++中的结构是等价的,除了结构的所有成员都是默认公共的(默认情况下类成员是私有的)。这确保了在C ++编译器中编译遗留C代码将按预期工作。
没有什么能阻止你在结构中使用所有奇特的C ++特性:
struct ReallyAClass
{
ReallyAClass();
virtual !ReallAClass();
/// etc etc etc
};
答案 6 :(得分:0)
当您想要将数据传递给C时,为什么不明确地将类的成员分配给结构?这样你就知道你的代码可以在任何地方使用。
答案 7 :(得分:-2)
您可能只是公开或私下从结构派生类。然后转换它将在C ++代码中正确解析。