`
iwebcode
  • 浏览: 2072381 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
文章分类
社区版块
存档分类
最新评论

C++ 内存布局(二) 虚继承 ---Empty virtual base classs (空虚基类)

 
阅读更多

上一次只是给出一个代码http://blog.csdn.net/OpenHero/archive/2006/04/02/648005.aspx,和运行过程中的内存位置,现在具体的按照步骤分析一下C++中虚拟继承中的情况,

由于C++ stand(C++ 标准委员会) 并没有规定具体实现的办法,各个编译器厂商可能都采用不同的实现方法,

或许在不同的年代使用的方法也不相同,有可能就会得到不同的结果,这里,我采用VC7.1作为调试工具,由潜

入深的一步步分析C++ 虚继承中的内存布局;

这一部分由Empty virtual base calss (空虚基类:空的calss)入手,查看VC7.1中是如何实现虚拟继承的.

下面给出测试的代码:

一,菱形的继承模式

class A
{ };

class B : virtual public A
{
};

class C : virtual public A
{
};

class D : public C, public B
{
};


int _tmain(int argc, _TCHAR* argv[])
{
A a;
B b;
C c;
D d;

int *pd = (int*)&d;
int *pd_c = (int*)(C*)(&d);
int *pd_b = (int*)(B*)(&d);
int *pd_a = (int*)(A*)(&d);

cout<< sizeof(a) << endl;
cout<< sizeof(b) << endl;
cout<< sizeof(c) << endl;
cout<< sizeof(d) << endl;
cout<< pd << endl;
cout<< pd_c << endl;
cout<< pd_b << endl;
cout<< pd_a << endl;

return 0;
}

有人会问,

class A
{ };

A a, 其中的a会有大小嘛?当然,a里面什么都没有,姑且就认为它是空的吧,但是,编译器如何才能记住a,而又

是空?你能想到一种实现的方法嘛?所以,编译器为了记住空的a,在a的内部放入了一个char的标记,作为它的

唯一标识,这样编译器才能认识那个a. 如果你有兴趣,你可以尝试定义A a,b; 然后你看看a和b是否是一

样的?现阶段来说,应该是不一样的,或许以后谁会发明新的实现方式,那个时候或许是一样也有可能了。

现在让我们看看上面程序的输出情况,如下:
1
4
4
8
0012FEAC
0012FEAC
0012FEB0
0012FEB4

这里我先不对上面的输出做出解释,或许你看了这样的输出会有疑惑,是不是和你想象的不一样?带着疑问

继续往下面看。
下面我再给出两段代码,同时给出他们各自的输出,然后再对这些输出做出解释:

二,六边形(菱形一)
class A
{ };

class B : virtual public A
{
};

class C : virtual public A
{
};

class D : /*virtual */public B
{
};

class E : /*virtual */public C
{

};
class F : public E, public D
{
};
int _tmain(int argc, _TCHAR* argv[])
{
A a;
B b;
C c;
D d;
E e;
F f;

int *pf = (int*)&f;
int *pf_e = (int*)(E*)(&f);
int *pf_d = (int*)(D*)(&f);
int *pf_c = (int*)(C*)(&f);
int *pf_b = (int*)(B*)(&f);
int *pf_a = (int*)(A*)(&f);

cout<< sizeof(a) << endl;
cout<< sizeof(b) << endl;
cout<< sizeof(c) << endl;
cout<< sizeof(d) << endl;
cout<< sizeof(f) << endl;
cout<< pf << endl;
cout<< pf_e << endl;
cout<< pf_d << endl;
cout<< pf_c << endl;
cout<< pf_b << endl;
cout<< pf_a << endl;

return 0;
}
输出结果:
1
4
4
4
4
8
0012FE94
0012FE94
0012FE98
0012FE94
0012FE98
0012FE9C

三,六边形(菱形二)

class A
{ };

class B : virtual public A
{
};

class C : virtual public A
{
};

class D : virtual public B
{
};

class E : virtual public C
{

};
class F : public E, public D
{
};
int _tmain(int argc, _TCHAR* argv[])
{
A a;
B b;
C c;
D d;
E e;
F f;

int *pf = (int*)&f;
int *pf_e = (int*)(E*)(&f);
int *pf_d = (int*)(D*)(&f);
int *pf_c = (int*)(C*)(&f);
int *pf_b = (int*)(B*)(&f);
int *pf_a = (int*)(A*)(&f);

cout<< sizeof(a) << endl;
cout<< sizeof(b) << endl;
cout<< sizeof(c) << endl;
cout<< sizeof(d) << endl;
cout<< sizeof(e) << endl;
cout<< sizeof(f) << endl;
cout<< pf << endl;
cout<< pf_e << endl;
cout<< pf_d << endl;
cout<< pf_c << endl;
cout<< pf_b << endl;
cout<< pf_a << endl;

return 0;
}
输出结果:
1
4
4
8
8
16
0012FE84
0012FE84
0012FE88
0012FE8C
0012FE90
0012FE8C

下面对其中的一,二做分析,三是一个有趣的现象,你可以考虑考虑:)

可以看到,只要有virtual的地方,都多出4个字节,用来干嘛?
在VC的编译器中,采用了virtual base calss pointer的方式来实现虚继承,从而保证子类回溯到基类的时

候只存在一个实体。多出来的4个字节就是用来存放各自的指向virtual base class 的地址的。

你可能又要问,a的大小为1,b,c……的大小只是4个4个增加,考虑内存对其,那不是会更大吗?

看到前面提到的一个问题了吗?
编译器只是为了记住a的时候才把a标示出来,如果知道a是空的,它既然有了子类,子类表示出来的时候,

当然基类就存在其中了:)

你可能又问? 那为什么不把子类也表示为1,不就行了吗?当然不行,就像上面提到的,因为是为了实现虚

继承的菱形一样的继承样式,在子类中只存在基类一个实体,所以,就才用了指针的方式,而不是把整个实

体放到子类的内存中。

在以后的内容中,会不断添加参数,函数,虚函数,分析虚继承中内存的分布。


声明:如果有网站转载,请把出处和连接加入到网页上,谢谢,咱,熬夜很困阿~~~
ps:太困,眼睛都睁不开了~~~~不行了,要睡觉了~~~~ 难免有打错的地方,请原谅

分享到:
评论

相关推荐

    C+++内1. 存布局虚继承+-Empty+virtual+base+classs+(空虚基类).docx

    。C+++内1.。存布局虚继承+-Empty+virtual+base+classs+(空虚基类).docx

    C+++内1. 存布局虚继承+-Empty+virtual+base+classs+(空虚基类).pdf

    。C+++内1.。存布局虚继承+-Empty+virtual+base+classs+(空虚基类).pdf

    绿色版PocketDOS 和 绿色版TC3.0

    OBJECT CPP - Base class for other objects SORTARRY CPP - Sorted array class definitions STACK CPP - Source file for classlibs STRNG CPP - String class definitions TIMER CPP - Timer class ...

    C++ 串口类 Serial port class.rar

    在C++编程中,串行通信(Serial Communication)是一种常用的数据传输方式,它允许设备通过串行接口交换数据。为了方便地操作串口,开发者通常会编写或使用串口类库。"C++ 串口类 Serial port class.rar"这个压缩包...

    Java+Classs+代码加密软件

    Java+Classs+代码加密软件

    atguigu-classs

    "atguigu-classs"项目,从其名称推测,可能是针对AtGuigu(也可能指的是“阿图购”)教育平台的Scala课程资料,包含了一系列的学习资源和示例代码。通过分析这个项目的文件结构和内容,我们可以深入探讨Scala的核心...

    tailwindcss-phx-live:TailwindCSS的Phoenix LiveView变体

    tailwindcss-phx-live是一个TailwindCSS插件,为Phoenix LiveView的phx-*-loading事件/ css-classs提供变体。 变体 phx-click phx-change phx-submit phx-focus 注意:顺风已经具有焦点变体! phx-blur phx-...

    java反编译工具以及去掉注释工具

    我们利用jd-gui反编译.classs代码之后,导出来的java源代码里面含有/**,其实这些标记是之前的java源码的注释,我们如何去掉这些标识了?需要利用jd-gui-cleaner.jar工具进行去掉,有需要的可以进行下载使用。 jd-...

    学生宿舍管理系统---C语言编程.doc

    char classs[8]; // 班级 }; ``` #### 模块功能说明 - **录入模块**:负责输入学生信息。 - **添加模块**:用于新增学生信息。 - **修改模块**:支持修改现有学生信息。 - **删除模块**:提供删除学生信息的功能...

    eclipse下查看class文件

    在Java开发过程中,Eclipse是一款广泛使用的集成开发环境(IDE),它提供了丰富的功能来支持代码编写、调试和项目管理。然而,在实际开发中,我们偶尔会遇到一些问题,比如Eclipse可能不会自动编译我们的代码,这...

    classs.jar

    android4.0源码编译出来的class.jar文件,可以尝试使用里面的隐藏api

    Gotta-This#java-study#Java方法 - 04 - 命令行传参1

    一、命令行传参 二、用命令行编译.java文件 三、用命令行运行.classs文件 四、命令行传参操作

    C++的template模板中class与typename关键字的区别分析

    在C++模板中,可以使用class或者typename来声明模板参数,那么这两个关键字有什么区别呢? 模板参数声明 对于模板参数声明,这两个参数没有区别,含义是一样的。 template class Simple; template class Simple; ...

    classs lcl_ssfw_test.txt

    classs lcl_ssfw_test.txt

    129.C语言程序设计--宿舍管理.docx

    - **结构体定义**:`struct st_message`定义了一个结构体,包含学生姓名(name)、宿舍号(dorm)、学号(num)、性别(sex)、年龄(age)、专业(major)和班级(classs)等字段,用于存储和管理学生信息。 4. **需求分析** -...

    Turbo C 3.0安装版

    - 内存管理:具备内存分配和释放的工具,有助于理解C语言内存操作。 - 库函数丰富:提供了大量的标准库函数和Borland特有的扩展库,方便开发者进行各种编程任务。 2. **安装过程**: - 解压缩:首先,你需要将...

    常用选择器1

    例如,`.classs{}`会选择所有class属性包含"classs"的元素。类选择器可以应用于多个元素,允许我们对多个元素应用相同的样式。 4. **通配选择器**:`*{}`选择页面上的所有元素,但通常不推荐使用,因为它会增加计算...

    postcss-foft-classes:一个postcss插件,可自动为各种字体加载策略添加类

    postcss-foft-classs 一个postcss插件,可以为各种自动添加类。 很大程度上基于 。 文档目前仅具有Gulp配置示例,但可以与其他构建工具配置一起使用! 这在postcss所做的任何地方都有效。 安装 npm install post...

    二进制交叉权限微型php类分享

    二进制是计算机科学中的基础概念之一,而位运算是实现高效数据处理的关键技术。在本PHP类中,通过将不同的权限映射为二进制位上的“1”来表示,可以非常高效地管理和判断用户是否拥有特定的权限。 **应用场景:** -...

Global site tag (gtag.js) - Google Analytics