GCC编译环境C++类对象存储结构

本文深入探讨C++中类成员变量的内存布局规律,包括直接继承与虚继承下成员变量的排列顺序,以及虚函数表指针的位置。通过具体实例代码演示,揭示GCC编译器在64位UNIX系统环境中如何处理类成员变量的内存分配。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

严谨声明以下结论均为GCC编译和UNIX 64位系统环境下得出的结论,非GCC和UNIX环境结论部分结论可能有所不同

1.C++类成员变量分为两部分:类自身声明的成员变量,来自于基类的成员变量

2.成员变量在内存中的顺序和声明顺序保持一致,从低地址向高地址扩展

3.直接继承的情况下, 基类成员变量的地址,在子类成员变量的地址之前;

4.虚继承的情况下,基类成员变量的地址,在子类成员变量的地址之后;

5.虚函数表指针,处于所有对象指针之前

完整的验证代码:

#include<iostream>
using namespace std;

class base
{
 public:
 int base_a;
 virtual void method(){};
};

class A: public base
{
 public: 
 int a;
 int b;
 int c;
 virtual void method(){};
};

int main()
{
 A obj;

 cout<<"address obj:"<<&obj<<endl;
 cout<<"address base_a:"<<&obj.base_a<<endl;
 cout<<"address a:"<<&obj.a<<endl;
 cout<<"address b:"<<&obj.b<<endl;
 cout<<"address c:"<<&obj.c<<endl;
return 0;
}

有虚函数的情况下输出(64位的环境,一个指针占8个字节):

address obj:0x7ffee9fe99b0 #(对象起始地址)
address base_a:0x7ffee9fe99b8 #(基类的一个成员变量起始地址)
address a:0x7ffee9fe99bc #(子类的第一个成员变量起始地址)
address b:0x7ffee9fe99c0 #(子类的第二个成员变量起始地址)
address c:0x7ffee9fe99c4 #(子类的第三个成员变量起始地址)

可以看出(对象起始地址)和(基类的一个成员变量起始地址)中间差了一个指针的空间,把基类和子类的虚函数注释掉之后看看输出:

address obj:0x7ffeec0d39c0 #(对象起始地址)
address base_a:0x7ffeec0d39c0 #(基类的一个成员变量起始地址)
address a:0x7ffeec0d39c4
address b:0x7ffeec0d39c8
address c:0x7ffeec0d39cc

所以可以猜想虚函数指针被编译器安插在了对象的头部,指针占用固定长度字节。

虚继承的情况下程序输出:

 

address obj:0x7ffee15359b0 #(对象起始地址)
address base_a:0x7ffee15359c4 #(基类成员变量在最后)
address a:0x7ffee15359b8 #(子类的第一个成员变量起始地址)
address b:0x7ffee15359bc #(子类的第二个成员变量起始地址)
address c:0x7ffee15359c0 #(子类的第三个成员变量起始地址)

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值