#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 回答
有许多因素决定了C中类的对象的大小 .
这些因素是:
所有非静态数据成员的大小
数据成员的顺序
字节对齐或字节填充
其直接基类的大小
虚函数的存在(使用虚函数的动态多态) .
正在使用的编译器
继承方式(虚拟继承)
当我在MVSC 2010上编译你的代码时,x64位 . 这是内存布局的结果:
Base1 :: virt1这个调整器:0
您应该阅读有关vTable,虚函数,类/结构的字节对齐的更多信息 . 在这里,一些链接可以帮助您 . 希望对您有所帮助:
确定类对象的大小:http://www.cprogramming.com/tutorial/size_of_class_object.html
内存布局:http://www.phpcompiler.org/articles/virtualinheritance.html
填充以确保
Base1
s处于必需连续†数组时正确对齐8字节指针 .†C标准要求数组元素在内存中是连续的,并计算索引i处元素的内存地址和数组的基地址加上元素大小的i倍
填充物已被回收用于额外的
int
成员 . 您可以通过输出d
,&d->data1
,&d->derivedData
来观察此情况 .在使用虚拟调度表指针的实现中(我知道的每个编译器,但它不是C标准规定的),
Derived
类构造函数和析构函数会覆盖"vptr" - 前者写入指向Derived
的VDT后的指针构造函数体运行,后者在析构函数体运行之前恢复指向Base
VDT的指针(这可确保您不会在其正式生命周期之前或之后调用对象上的Derived
成员函数) .