指向struct或class的指针与指向first字段的指针

App*_*ish 6 c++ oop struct pointers field

我最近尝试通过打印几个指向控制台的指针来调试一个小程序.第一个是结构的内存地址,其他是其字段的内存地址.该代码的精简版本如下:

#include <iostream>

struct testingPointers
{
    int i;
    float f;
    double d;
} test;

int main()
{
   std::cout << &test << '\n' << &(test.i) << '\n' << 
            &(test.f) << '\n' << &(test.d);
}
Run Code Online (Sandbox Code Playgroud)

输出是:

0x681110
0x681110
0x681114
0x681118
Run Code Online (Sandbox Code Playgroud)

(显然,不同运行的确切值是不同的,但它们相对于彼此总是具有相同的位置).

我很困惑,因为第一个指针的值 - 与第二个指针test(第一个字段test)的内存位置相同.这是否意味着对象没有真正唯一的内存地址,并且指向结构或类的指针只是指向其第一个字段?如果是这样,声明怎么样

a.b
a->b
a.b()
Run Code Online (Sandbox Code Playgroud)

如果a实际上只是它的第一个字段,那么它是否有意义,因此没有任何字段或方法?

Who*_*aig 6

对象的地址应始终是该对象中第一个非静态成员的地址.引用标准(C++ 11-9.2-20):

指向标准布局结构对象的指针,使用reinterpret_cast进行适当转换,指向其初始成员(或者如果该成员是位字段,则指向它所在的单元),反之亦然.[注意:因此,在标准布局结构对象中可能存在未命名的填充,但不是在其开头,以实现适当的对齐.

这里提到了标准布局的要求:StandardLayoutType.

这当然可以通过嵌套来应用.除了位字段之外,该标准对第一个成员的类型没有例外.即:

class X
{
public:
    int x;
};

class Y
{
public:
    X x;
    int y;
};

Y yobj;
Run Code Online (Sandbox Code Playgroud)

按标准,&yobj == &yobj.x == &yobj.x.x.


Jos*_*eld 5

类或结构只描述了应该在内存中保存在一起的字段集合,并且它们之间存在一些语义关系以及对它们进行操作的一些操作.在简单的情况下,内存中类类型对象的内容与构成它的成员(以及一些填充)相比没有更多内容.当你testingPointers在内存中有一个对象时,它实际上只是一个int,一个float和一个double.该类的概念仅用于生成正确的可执行代码 - 它在运行时不存在(至少不是为此目的).

关于对象是否可以共享内存地址的标准的重要部分是§1.8/ 6:

除非对象是零字段或零大小的基类子对象,否则该对象的地址是它占用的第一个字节的地址.如果一个是另一个的子对象,或者如果至少一个是零大小的基类子对象并且它们是不同类型的,则不是位字段的两个对象可以具有相同的地址; 否则,他们应有不同的地址.

我们可以从中推断出因为成员test.i是子对象test,所以他们可能具有相同的地址.

一旦你深入了解程序中的所有对象,你真正拥有的是标量值和相邻位域的大集合.这些被称为标准中的存储位置.这些是真正占据空间的东西.其余的对象都是以某种方式组成的.

存储器位置或者是标量类型的对象或相邻位字段都具有非零宽度的最大序列.[ 注意:该语言的各种功能,例如引用和虚函数,可能涉及程序无法访问但由实现管理的其他内存位置.- 结束说明 ]