【C++】C++对象内存模型简介

32 篇文章 2 订阅

C++相比C,增加了class类特性,用于封装数据和方法。C和C++都有struct结构体。C中的struct纯粹是数据和函数的集合。而C++中的struct则相当于另外一类class,与class的区别是,class如果没有关键字,默认成员为私有,struct则默认为公有;如果显式指定私有公有等关键字,则C++的struct和class几乎没有区别。我们来看看C++如何将数据和方法封装在一起。

           C++中class类可以包含non-static和static两种类别的成员数据,non-static、static和virtual三种类别的成员函数。对于空类,一般其size为1个字节以填充。class生成的对象,一般只包含non-static成员数据,如果有虚函数,则会增加一个指向虚表(vtbl)的成员指针,我们不应该修改这个成员指针,应该只让编译器操作;static成员数据和函数则不包含在对象中,存放在一个所有该类对象都可以访问的内存地址中。

           包含虚函数的class对象包含一个指向虚表Vtbl的指针,vtbl则保存了该类的多态信息,应该调用的虚函数地址。

Class内存分布图如下:


我在64位clang中编译如下代码,64位系统中指针是8个字节:

struct A{virtual voidprint(){printf("A\n");}};
struct B:public A{};
struct C:public B{int a;};
struct D:public C{int a;int b;};
struct E{};
struct F:public E{};
struct G:public F{int a;};
struct H:public G{int b;};
struct I:public G{void nonvirtual(){}};
struct J:public G{virtual voidnonvirtual(){}};
struct K{static int a;};
int main()
{
    cout<< sizeof(A) << endl;//8字节,包含一个vtbl指针
   cout << sizeof(B) << endl;//8字节,同上,继承并不增加内存消耗
   cout << sizeof(C) << endl;//16字节,vtbl指针是8字节,int是4字节,为了内存对齐,int内存补全为8字节
   cout << sizeof(D) << endl;//24字节,同上需要内存补齐
   cout << sizeof(E) << endl;//1字节,仅仅只是一个用于编译器辨识的地址,不包含任何信息
   cout << sizeof(F) << endl;//1字节,继承并不增加内存消耗
   cout << sizeof(G) << endl;//4字节,包含1个int数据
   cout << sizeof(H) << endl;//8字节,包含2个int数据
   cout << sizeof(I) << endl;//4字节,包含1个int数据,函数不占空间
   cout << sizeof(J) << endl;//16字节,一般编译器会在class起始处包含一个8字节的vtbl指针,后面再包含一个int数据,并内存补齐为8字节
   cout << sizeof(K) << endl;//1字节,static数据并不保存在对象中。
           return0;
}

由于每个对象访问的成员函数的地址是一样的,为了让成员函数辨识是哪个对象在调用自己,编译器会将目标对象传递给成员函数,因此实际上编译器把如下类(为了方便,用struct):

struct A{
int a;
void print(){printf(“%d\n”,a);}
}; 
A a;
a.print();

相当于替换成这样的C代码:

struct A{
int a;
};
void A_print(void *arg){
A* this = (A*)arg;
printf(“%d\n”,this->a);
} 
A a;
A_print(a);


当然,编译器做的工作是更加复杂的。很多书籍中告诉我们class成员函数隐含一个this指针,并且成员函数实际上的第一个参数其实是这个指向自身指针。早期C++编译器的工作是预先将C++代码变成C代码,然后用C编译器编译成机器码,其中面向对象特性就是采用类似上述的方法实现的。这个例子证明了,C++面向对象特性等价于一段简单的C代码,因此不会造成数据膨胀,也不会造成明显的性能下降,但大大提升了软件开发效率。

更加明显的是python语言,python解释器是用C语言编写的,我们可以看到python的类模块如下:

class A:

           def SetName(self,name):

                     self.name = name

其中python类的成员函数的第一个参数是self,就是指向自身的指针,而C++则允许我们不用书写指向自身的指针参数。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值