首页 文章

C中基类对象和派生类对象的大小

提问于
浏览
3
#include <stdio.h>

class Base1
{
  public:

  virtual int virt1() { return 100; }

  int data1;
};

class Derived : public Base1
{
  public:

  virtual int virt1() { return 150; }

  int derivedData;
};

int Global1( Base1 * b1 )
{
  return b1->virt1();
}

main1()
{
  Derived * d = new Derived;

  printf( "%d %d\n", d->virt1(), Global1( d ));
  printf("size: Base1:%d\n", sizeof(Base1));
  printf("size: Derived:%d\n", sizeof(Derived));
}

我使用上面的代码打印出基类和派生类的大小 . 我在64位机器上运行代码 . 我的电脑输出是

150 150
size: Base1:16
size: Derived:16

我还尝试使用sizeof(int)打印出int的大小,它是4 .

我有以下问题:

  • 对于Base1类的大小,它应包含指向vtable的vptr和一个整数data1 . 为什么它的大小是16而sizeof(int)在我的机器中是4 .

  • 对于派生类,它应该具有从Base1类继承的数据和一个额外的整数 . 它应该比Base1类更大,为什么它们是相同的?

  • 除了这些大小之外,Derived类中的vptr是什么? Derived类中的vptr是否会覆盖从Base1类继承的vptr?

2 回答

  • 3

    有许多因素决定了C中类的对象的大小 .

    这些因素是:

    • 所有非静态数据成员的大小

    • 数据成员的顺序

    • 字节对齐或字节填充

    • 其直接基类的大小

    • 虚函数的存在(使用虚函数的动态多态) .

    • 正在使用的编译器

    • 继承方式(虚拟继承)

    当我在MVSC 2010上编译你的代码时,x64位 . 这是内存布局的结果:

    class Base1 size(16):
        +---
     0  | {vfptr}
     8  | data1
        | <alignment member> (size=4)
        +---
    
    Base1::$vftable@:
        | &Base1_meta
        |  0
    0   | &Base1::virt1
    

    Base1 :: virt1这个调整器:0

    class Derived    size(24):
        +---
        | +--- (base class Base1)
    0   | | {vfptr}
    8   | | data1
        | | <alignment member> (size=4)
        | +---
    16  | derivedData
        | <alignment member> (size=4)
        +---
    
    Derived::$vftable@:
        | &Derived_meta
        |  0
     0  | &Derived::virt1
    

    您应该阅读有关vTable,虚函数,类/结构的字节对齐的更多信息 . 在这里,一些链接可以帮助您 . 希望对您有所帮助:

    确定类对象的大小:http://www.cprogramming.com/tutorial/size_of_class_object.html

    内存布局:http://www.phpcompiler.org/articles/virtualinheritance.html

  • 0

    对于Base1类的大小,它应包含vtable指向vtable和整数data1 . 为什么它的大小是16而sizeof(int)在我的机器中是4 .

    填充以确保 Base1 s处于必需连续†数组时正确对齐8字节指针 .

    †C标准要求数组元素在内存中是连续的,并计算索引i处元素的内存地址和数组的基地址加上元素大小的i倍

    对于派生类,它应该具有从Base1类继承的数据和一个额外的整数 . 它应该比Base1类更大,为什么它们是相同的?

    填充物已被回收用于额外的 int 成员 . 您可以通过输出 d&d->data1&d->derivedData 来观察此情况 .

    除了这些大小之外,Derived类中的vptr是什么? Derived类中的vptr是否会覆盖从Base1类继承的vptr?

    在使用虚拟调度表指针的实现中(我知道的每个编译器,但它不是C标准规定的), Derived 类构造函数和析构函数会覆盖"vptr" - 前者写入指向 Derived 的VDT后的指针构造函数体运行,后者在析构函数体运行之前恢复指向 Base VDT的指针(这可确保您不会在其正式生命周期之前或之后调用对象上的 Derived 成员函数) .

相关问题