给定foo
类型的变量FooClass*
以及该类名为bar
的成员变量,foo
和&(foo->bar)
之间的距离是相同的任何有一些限制的情况:
FooClass
是非POD类型。
我们知道foo
将始终指向FooClass
的实例,而不是其中的某个子类型。
我们只关心单个编译器和单个编译的行为;也就是说,在gcc下可能导致的值从未在使用MSVC编译的代码中使用,并且永远不会保存以便在编译之间重复使用。它以二进制计算并在二进制文件中使用,即它。
我们不使用自定义new
,尽管该类的某些实例可能是堆栈分配的,也可能是堆分配的。
ctor
没有明确的FooClass
;它依赖于编译器生成的一个(FooClass
中的每个字段都是POD或默认构造的。)
我无法在标准中找到这方面的保证(我也没想到),但是我用gcc进行的基本测试让我相信它总会如此。我也知道这个保证是针对POD类型的,但我们假设这种类型不能是POD。
更新/澄清:这仅适用于单个二进制文件的单个编译;计算出的偏移量永远不会离开那一次执行。基本上,我希望能够在静态地图中唯一地标识类的字段,然后能够在某个宏/模板/ EVIL欺骗中查找该映射。这仅仅是为了我自己的娱乐,没有生命支持机器会依赖这个代码。
答案 0 :(得分:5)
编译完程序后,是* 。
偏移量将保持不变。
但有一个非常重要的限制: foo必须专门指向FooClass对象。不是从FooClass派生的类,或其他任何东西。
C ++对成员偏移进行POD区分的原因是因为多重继承和vtable指针的位置(或缺少)可能会创建一个对象的地址与该对象的基地址不同的情况
答案 1 :(得分:3)
我不是专家,但无论如何我会尝试回答你:)
private
,public
或protected
的多个部分。在这样的部分中,顺序是成员定义的顺序,但是在这些部分中,顺序是任意的而且未指定。 所以我认为你不能保证在整个编辑中偏移量是恒定的。对于一个编译中的考虑因素(因此,如果我们将使用其生成的代码使用随每个不同编译而变化的ABI的编译器),则偏移量不能相同。但即使您知道偏移量,也无法访问该成员。访问成员的唯一方法是使用成员访问运算符->
和.
(在9.2 / 9中说过)。
为什么不使用数据成员指针?它们允许安全地访问成员。这是一个例子:(looking up members by name)。
答案 2 :(得分:3)
在单个编译器中,编译器设置始终相同且没有任何内容添加到FooClass或从FooClass中删除,那么是,foo
和&(foo->bar)
中存储的地址之间的距离将始终为是相同的,否则编译器将无法生成适用于编译单元的正确代码。
但是,一旦向类中添加任何内容或更改编译器设置,所有投注都将关闭。
答案 3 :(得分:3)
据我所知,这应该是这样的,POD课程与否。在编译时,基于编译器,体系结构,设置等,编译器确定类的大小和所有成员的偏移量。然后在编译单元中为类的所有实例修复此问题(如果保留了单定义规则,则扩展为链接单元)。
由于编译器按字面意思处理类型指针,即使基础类型错误(例如:指针已被错误地c样式转换),& foo和&(foo.bar)之间的计算距离将是同样,因为偏移量在编译时是静态已知的。
注意:这有效地完成了之前。例如,参见Microsoft的ATL数据绑定代码,使用它们的'offsetof'宏...
答案 4 :(得分:1)
我的头顶有两件事会影响对象的内部布局:
答案 5 :(得分:1)
底线:如果此类包含除POD之外的任何内容,则您绝对不能对偏移量做出任何假设。如果该课程只是公共POD的集合,那么您就是安全的。
这是一本优秀的中级C ++书中章节的一部分链接。如果你认真对待C ++,我建议大家阅读这本书。
这个特别的摘录解决了这里提出的问题的一部分:
http://my.safaribooksonline.com/0321321928/ch11?portal=oreilly
关于其他细节,请查看书籍。我上面的“底线”是对本章的简单概述。
答案 6 :(得分:1)
是的,偏移量是在编译时确定的,因此只要您不在比较编译器或编译器的偏移量,它就会始终保持不变。