编辑:我刚刚意识到一个更简单的方法来问这个问题:
给定以下两个结构:
class Thing {public: int a; public: int b; public: int c;} class Thing {public: int a, private: int b; public: int c;}
对于这两个定义,成员
a
、b
和c
是否保证在内存中的顺序相同?
老问题
假设我们在fileA.cpp
中有这个C++代码:
class Thing
{
public:
int a;
double num;
Thing()
{
b = 10;
}
float getB()
{
return b;
}
private:
float b;
Thing * other;
}
void doSomething(Thing thing);
int main()
{
Thing thing;
doSomething(thing);
std::cout << thing.b;
}
假设我们在fileB.cpp
中有以下代码:
class Thing
{
public:
int a;
double num;
Thing()
{
b = 10;
}
float getB()
{
return b;
}
float b;
private:
Thing * other;
}
void doSomething(Thing thing)
{
thing.b = 30;
}
假设编译器不会抱怨,那么这段代码会按预期工作吗?也就是说,结构数据的排列是否独立于某些组件是公共的、私有的还是受保护的?
编辑:为了使它更明显,Thing
的两个定义之间的唯一区别是float b;
在fileA.cpp
是私有的,但在fileB.cpp
是公开的。
标准没有这样的保证。您仅对标准布局类具有布局保证:
标准布局类是具有以下特性的类:
- 没有非标准布局类(或此类类型的数组(类型的非静态数据成员或引用,
- 没有虚函数(10.3(也没有虚拟基类(10.1(,
- 对所有非静态数据成员具有相同的访问控制(条款 11(,
- 没有非标准布局基类,
- 要么在派生最多的类中没有非静态数据成员,并且最多有一个基类 非静态数据成员,或者没有具有非静态数据成员的基类,以及
- 没有与第一个非静态数据成员类型相同的基类。
(C++14, [类] ¶7(
如果类是标准布局的,则其布局定义良好(并且具有布局兼容初始序列的两个标准布局类可以通过union
读取彼此的布局兼容成员(。
但是,这里的情况并非如此,因为在整个类中有不同的访问说明符。特别是,它明确指出
未指定具有不同访问控制的非静态数据成员的分配顺序
(C++14, [class.mem] ¶13(
话虽如此,我从未使用过任何利用标准提供的这种灵活性的真实编译器 - 我认识的每个编译器都使用访问说明符进行编译时检查,但就成员布局而言完全忽略了它们。