C++对象在内存中的分布

来源:互联网 发布:同步软件 编辑:程序博客网 时间:2024/05/16 07:11


C++通过class的pointers和references来支持多态,这种程序风格就成为“面向对象”。


一、C++对多态的支持的三种方式

1.把一个派生类指针隐式转换成一个基类指针

ex: shape *ps = new circle();

2.经由virtual function机制

ex: ps->rotate();

2.经由dynamic_cast 和typeid运算符

ex:if(circle *pc = dynamic_cast<circle*>(ps)){...}


二、class object的大小包含三个部分

1.nonstatic data members的总和大小

2.字节对齐产生的大小

3.对virtual机制的支持产生的额外负担


三、示例

base class

#include <string>using namespace std;class ZooAnimal  {public:ZooAnimal(string _name);virtual ~ZooAnimal();virtual void rotate();protected:int loc;string name;};

derived class

#include "ZooAnimal.h"class Bear : public ZooAnimal  {public:Bear();Bear(string _name);virtual ~Bear();void rotate();virtual void dance();protected:enum Dances{FIRST_DANCE,SECOND_DANCE};Dances dances_known;int cell_bolock;};
测试函数:

#include "Bear.h"#include "ZooAnimal.h"int main(int argc, char* argv[]){ZooAnimal za("Zoey");ZooAnimal *pza = &za;printf("size of ZooAnimal = %d\n",sizeof(ZooAnimal));Bear b("Yogi");printf("size of Bear = %d\n",sizeof(Bear));Bear *pb = &b;ZooAnimal *pz = &b;Bear &rb = *pb;printf("Bear created!\n");return 0;}

在内存中的布局:




分析:

sizeof(ZooAnimal):__vfptr(4)+loc(4)+npos(4)+__Ptr(4)+_Len(4)+_Res(4)=24个字节

sizeof(Bear):sizeof(ZooAnimal)+dances_known(4)+cell_bolock(4) = 32字节


Data语意学


C++的非static 成员变量在内存中的存储之所以要进行边界对齐,原因之一是考虑了需要避免在派生类之间复制的时候产生意向之外的内存覆盖,而进行边界对齐,就可以避免这个问题。


为了拓展性,可以在基类中提供一个virtual function接口。(只不过这样的话,每一个derived class将会继承一个基类的vptr member,多一个virtual table,此外virtual member function的调用也会变得复杂,因此需要权衡)。

继承的这个虚函数表指针在vc6里面是放在整个内存块的前端的。因为这对于“在多重继承下,通过class members 的指针调用virtual function,会带来好处,因为不用找这个指针。而放在后端则是在派生的时候可以与C语言的struct结构体进行兼容,这也是需要权衡的(不过这点好像和我们程序猿没什么事)”


虚拟继承和继承多个虚拟基类是不一样的,这个一定要明白虚拟继承的概念,很多最顶层基类只需要保持一份的情况下可以采用虚拟继承机制来实现。

不过这里有一个问题是,采用虚拟机制来控制的派生体系,每一个派生类都会背负一个基类的指针,并且是逐级向上存取,因此当继承层数过多的时候,就会产生效率问题。


Function语意学


成员函数和非成员函数都会被编译器进行name mangling转换成相同的形式

http://blog.csdn.net/xt_xiaotian/article/details/5431410

因为static member functions没有this指针这个特性。

所以不能够直接存取其class的nonstatic members---->要借助于具体对象

所以不能声明为const volatile virtual--->没有必要

所以不需要经由类对象来调用--->不依赖于类对象


virtual member function

对这样一个对虚拟函数z的调用:

ptr->z()

为了达到在执行期调用正确z()实体的目的,我们需要知道两件事

1.ptr的真实类型

2.z()实体的位置

在单继承下,virtual member function机制下,每一个object都会有一个vptr指向虚函数表,虚函数表中存放的就是对象的虚函数的函数实体,pure virtual funtion会占用一个slot,但pure virtual class 的派生类中,因为这个pure virtual function不存在,所以这个slot会用来放置其他virtual function


nonvirtual function的调用需要绑定到具体的class object对象上,这是因为nonvirtual function与对象无关的特性,会导致取到nonvirtual function的返回值是其在内存中的地址,而不是一个函数指针。(因此不能调用一个函数地址,也就需要绑定到具体对象上,将这个返回的内存地址转换成对象的函数指针了)

 

将被共享的数据放在base class中是一种正当的设计,但需要对这个成员初始化(在基类中提供带单数的 protected constructor,或是在每一个构造函数中初始化它)


 



0 0
原创粉丝点击