sizeof 类

     sizeof计算的是变量、指针或者类在栈中占用的字节数。这里重点讲解一下类的大小。

     计算方法:

              sizeof(类)=成员变量所占字节数(1、2、4、8字节对齐后)+虚函数指针

             sizeof(虚继承类)=

                     本身成员变量所占字节数+

                      父类的大小(多继承也是一样的,如果多个父类公用一个基类,则去掉重复的基类占的空间)+

                      指向父类指针的大小+

                      虚函数指针大小(虚继承条件下:如果子类新定义了新的虚函数,需要重新开一份虚表,则此处添加一个指向虚函数表的指针;

                                                     如果覆盖了父类的虚函数,则将这个虚函数也放到父类的虚函数表里面。) 

             sizeof(普通继承类)=

                     本身成员变量所占字节数+

                      父类的大小(多继承也是一样的,如果多个父类公用一个基类,则去掉重复的基类占的空间)+

                      虚函数指针大小(非虚继承条件下:把虚函数地址放到父类的虚函数表里面。若父类中没有虚函数,则新建一个)

             综合上述两方面的继承,得到总的继承类大小计算方法:

             sizeof(继承类)=

                     本身成员变量所占字节数+

                      父类的大小(多继承也是一样的,如果多个父类公用一个基类,则去掉重复的基类占的空间)+

                      指向父类指针的大小(若是虚继承父类才有此项)+

                      虚函数指针大小(虚继承条件下:如果子类新定义了新的虚函数,需要重新开一份虚表,则此处添加一个指向虚函数表的指针;

                                                     如果覆盖了父类的虚函数,则将这个虚函数也放到父类的虚函数表里面。非虚继承条件下:把虚函数地址放到父类的虚函数表里面。

                                                )

 

                 注:虚函数统一放在虚函数表里管理,然后类中仅保存一份指向虚函数表的指针。上面红色部分是在别人的博文中找到的,但是我使用vs2010发现在虚继承条件下,只要子类中出现虚函数就需要创建一个虚函数指针。

  (1)空类

   class   A
  {
  };

运行cout<<"sizeof(A)="<<sizeof(A)<<endl;之后输出1。

先了解一个概念:类的实例化,所谓类的实例化就是在内存中分配一块地址,每个实例在 内存中都有独一无二的地址。同样空类也会被实例化,所以编译器会给空类隐含的添加一个字节,这样空类实例化之后就有了 独一无二的地址了。所以空类的sizeof为1。

(2)非空类

   class B
  {
    int  a;//成员变量占4字节
   char *p;//指针占4字节
  };

运行cout<<"sizeof(B)="<<sizeof(B)<<endl;之后输出8。

(3)带有虚函数

class  C
{
public :
C(
void );
virtual   ~ C( void );//需要建立虚函数表,类中存储一个大小为4字节的虚函数指针
private :
int    a;//4字节
char   * p;//4字节
};

sizeof(C)=12

(4)子类

class  D: public  C
{
public :
D(
void );
~ D( void );
private :
int  b;//4字节
};

sizeof(D)=16;//4+12(父类的大小)

(5)普通继承子类有新的虚函数,覆盖

class E

{

public:

    E(){printf("Construct\n");}

    ~E(){printf("Desctruct\n");}

    virtual void Foo(){printf("Foo\n");} //或者是virtual void Foo()=0;都是占4个字节大小,建立一个虚函数表,类内保存一个虚函数表指针占4字节

};

class F: public E//非虚继承

{

public:

    F(){m_iVD=0xFF;};

    ~F(){};

    virtual void Foo2(){printf("Foo2\n");}; //虚函数直接放在父类的虚函数表内,并没有重新建一个虚函数表。

private:

    int m_iVD;//4字节

};

sizeof(F)=8

 

长度:8  内存结构:

24 61 42 00 //虚表指针

FF 00 00 00 //m_iVD

 

00426124:(虚表)

23 10 40 00

50 10 40 00

 

class E2: public E//非虚继承

{

public:

   E2(){m_iVD=0xFF;};

    ~F(){};

    virtual void Foo(){printf("Foo\n");}; //虚函数直接放在父类的虚函数表内,并没有重新建一个虚函数表。

private:

    int m_iVD;//4字节

};

sizeof(E2)=8

(6)虚拟继承

class G

{

public:

    G(int iValue = 0){m_iOne = iValue;};

private:

    int m_iOne;

};

class H:virtual public G

{

private:

    int m_iTwo;

};

长度:12;// 4字节(成员变量)+4字节(指向父类的虚拟指针)+4字节(父类大小)

内存结构:

E8 2F 42 00 //指针,指向一个关于偏移量的数组,且称之虚基类偏移量表指针

CC CC CC CC // m_iTwo

00 00 00 00 // m_iOne(虚基类数据成员)

(7)虚继承子类中定义了新的虚函数,新建一个虚拟表,在子类中存储一个虚拟表指针

class HH: public virtual G

{

public:

    HH(int iValue = 0){m_iOne = iValue;};

   virtual void Foo();//建立新的虚表,类内存储虚函数表指针

private:

 int m_iTwo;

};
sizeof(HH)=sizeof(成员变量)+sizeof(虚拟表指针)+sizoof(指向父类指针)+sizeof(父类)=4+4+4+4=16。

(8)虚继承子类中覆盖父类的虚函数,覆盖函数地址仍放在父类虚函数表中,在子类中不需要存储一个虚函数表指针

class HHH: public virtual HH

{

public:

    HHH(int iValue = 0){m_iOne = iValue;};

   virtual void Foo();//需建立新的虚表

};
sizeof(HHH)=sizeof(成员变量)+sizeof(虚拟表指针)+sizoof(指向父类指针)+sizeof(父类)=0+4+4+16=24。


class H2: public virtual HH

{

public:

    H2(int iValue = 0){m_iOne = iValue;};

    void Foo();//需建立新的虚表

};
sizeof(H2)=24。

sizeof(HHH)=sizeof(成员变量)+sizeof(虚拟表指针)+sizoof(指向父类指针)+sizeof(父类)=0+4+4+16=24。



(9)static 成员

class CStaticNull

{

public:

    CStaticNull(){printf("Construct\n");}

    ~CStaticNull(){printf("Desctruct\n");}

    static void Foo(){printf("Foo\n");}

    static int m_iValue;

};

长度:1

static成员存储在内存的公共数据区(数据段),不占用栈空间。

(10)多重继承

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值