C++中非static类成员使用class::variable语法的输出与内存疑问
关于C++成员指针输出与类内存布局的疑问解答
一、为什么cout << p1.p输出固定为1?
你定义的p是指向类非静态成员的指针(int Person::*类型),和普通对象指针不是一回事。C++的标准输出流无法直接打印这类成员指针的原始值,会默认将其转换为布尔类型处理:
- 对于指向普通非虚成员的指针,编译器通常用偏移量0表示指向类的第一个非静态数据成员(这里就是
age)。 - 布尔类型中,非零值会被判定为
true,而cout输出true时就会显示1,这就是你看到固定输出1的原因。
如果要查看成员指针的实际偏移量,可以通过强制类型转换输出:
cout << "p的实际偏移量: " << reinterpret_cast<std::ptrdiff_t>(p1.p) << endl;
此时会输出0,对应age相对于Person对象起始地址的偏移量。
二、为什么成员p的地址在age前8字节?
这是由C++类的内存布局规则决定的:
- 编译器会严格按照类中成员的声明顺序分配内存(无访问控制或对齐干扰时),你的
Person类声明顺序是:int Person::* p→int age→int a。 - 在64位系统中,指向类成员的指针大小为8字节(即使存储的是偏移量,编译器也会用8字节的空间来适配通用的成员指针实现),而
int类型占4字节。 - 对应
p1对象的内存布局大致如下:
因此地址区间 对应成员 0xXXXX0000-0xXXXX0007 p(8字节) 0xXXXX0008-0xXXXX000B age(4字节) 0xXXXX000C-0xXXXX000F a(4字节)p的地址会比age的地址小8字节,也就是在内存中位于age的前方。
三、调试器显示p的值为&Person::age的原因
int Person::* p = &Person::age;是将指向Person::age的成员指针赋值给p。这类成员指针的本质是存储目标成员相对于类对象起始地址的偏移量(针对非虚成员),调试器为了直观展示,会把这个偏移量对应到具体的成员符号,所以直接显示为&Person::age,而非原始的偏移数值。
补充:成员指针的正确用法
成员指针不能直接访问内存,必须结合具体的对象实例才能获取对应成员的值,比如:
cout << "p1的age值: " << p1.*(p1.p) << endl; // 输出18
内容的提问来源于stack exchange,提问作者Baymiiing
相关产品推荐
相关产品推荐

