发布日期:2016-02-29 11:50 来源: 标签: 编程语言 C++开发语言 C++对象空间 C++对象存储
本章我们主要学习C++中类对象空间中虚继承下的对象存储,下面们就做一下具体讲解,希望大家多多支持中国站长网络学院。
首先,先看下面几个类:
class X{}; 
class Y : public virtual X {}; 
class Z : public virtual X {}; 
class A : public virtual Y {}; 
class B : public Y, public Z{}; 
class C : public virtual Y, public virtual Z {}; 
class D : public virtual C{}; 
在VC6.0上执行的结果为为: 
sizeof(X):1 
sizeof(Y):4 
sizeof(Z):4 
sizeof(A):8 
sizeof(B):8 
sizeof(C):12 
sizeof(D):16 
(1)首先,对于class X,其实它并不是空的,它隐含着被编译器添加了一个char,那么为什么要添加这个char ?我们来看,有这样的定义X x,则x肯定是有地址的,那既然x有地址,OK,sizeof(x)肯定就不为0了撒。 
    为什么会出现这种结果呢?初学者肯定会很烦恼是吗?类X明明是空类,它的大小应该为0,为什么编译器输出的结果为1呢?这就是因为实例化的原因(空类同样可以被实例化),每个实例在内存中都有一个独一无二的地址,为了达到这个目的,编译器往往会给一个空类隐含的加一个字节,这样空类在实例化后在内存得到了独一无二的地址.所以X的大小为1。 
(2)对于class Y和class Z,都有额外的负担,那么这个负担反映在指向virtual base class subobject(虚基类对象)上的指针。那照这样说,sizeof(Y)就应该等于5(先不考虑字节对齐)了?其实有些编译器提供了一些特殊处理,这使得一个empty virtual base class(空虚基类)被视为derived class object最开头的一部分,也就是说它并没有花费任何空间,即这个1bytes被省了。    
(3)同样,对于class A,本身base class Y的大小为4,加个指针,则为8了。   
(4)对于class B,也很简单,class Y和class Z的大小都为4。     
(5)现在来看class C,因为他虚继承了Y和Z,所以它应该添加2个指针,在加上Y和Z,不应该是16么,那为什么结果是12呢? 
 我们可以看到,Y和Z都是虚派生自class X,而一个virtual base class subobject只会在derived class中存在一份实体,不管它在class继承体系中出现了多少次。   如果说我把之前的类重新改下,新添加一个“class X1 {}; ”,而把class Z改成“class Z : public virtual X1 {}; ”,那么这个时候sizeof(C)就等于16了。      
 (6)最后对于class D来说,应该很简单了。 
再看下面的类定义: 
class A  {  int a; }      
sizeof(A) 其值为4,而int 型大小为4;为什么没有多一个插进去的char的大小? 
    为什么没有隐含加一个字节呢,那是因为成员变量int a 已经可以占4个字节了,也就是在内存中分配了4个字节的空间,所以没有必要隐含加一个字节也可以实例化了(只要分配了内存空间,也就是实例化了,这就是实例化的定义:类的实例化就是在内存中分配一块地址)。  
 最后看一个类定义:  
#include <cstdlib>  
#include <iostream>  
#include <memory>  
5using namespace std;  
class A  { 
       char k[3];       public:            virtual void aa(){}; };
class B : public virtual A { 
    char j[3];     public:          virtual void bb(){}; }; 
class C : public virtual B {    char i[3];      public:          virtual void cc(){}; }; int main(int argc, char *argv[]) { 
cout<<"sizeof(A):"<<sizeof(A)<<endl; 
cout<<"sizeof(B):"<<sizeof(B)<<endl; 
cout<<"sizeof(C):"<<sizeof(C)<<endl;
system("PAUSE");
return EXIT_SUCCESS;} 
问题:程序运行的结果? 
答案:8,16,24。 
解释: 
(1)对于类A,由于有一个虚函数,那么必须得有一个对应的虚函数表来记录对应的函数入口地址。每个地址需要一个虚指针,指针的大小为4。类中还有一个char k[3],当然大小为3。为什么是8呢?因为在计算机里,是以4为单位,所以第一条输出的结果为8。 
(2)对于类B,同类A一样,自己的大小为8,但是由于虚继承类A,所以在虚表中要加入一个虚类指针来指向其类A,然后在包含类A的所有成员,sizeof(A)为8,结果便是16。 (3)对于类C,同类B一样,自己的大小8,加上sizeof(B),结果为24。   
虚继承就是为了节约内存的,他是多重继承中的特有的概念。适用与菱形继承形式。函数继承就是覆盖。即基类中的虚函数被派生类中的同名函数所覆盖。 是实现多态的方法。 
 

相关评论

专题信息
    Visual C++是一个功能强大的可视化软件开发工具,是高等院校计算机及相关专业主要核心课程。 本教程对Visual C++ 的应用与开发进行了详细系统的介绍,内容主要包括:Visual C++程序的建立,菜单、工具栏和状态栏的创建,对话框和常用控件,窗口、文档与视图,图形绘制,数据库应用,多媒体技术等。 本教程以案例教学为主,各章节都附有大量的实例,并且操作步骤详细,有利于引导读者更好的消化、理解和实际应用本章节所学的知识内容,希望大家能多多支持中国站长网络学院!