正如本问题的一个解决方案(Size of virtual pointer-C++)中所解释的那样,您可以通过以下方式计算虚拟指针大小:
struct virtual_base {
int data;
virtual_base() {}
virtual ~virtual_base() {}
};
struct non_virtual_base {
int data;
non_virtual_base() {}
~non_virtual_base() {}
};
int main() {
std::cout << sizeof( virtual_base ) - sizeof( non_virtual_base ) << '\n';
return 0;
}
但是当我在cpp.sh http://cpp.sh/7o5av上尝试这个时,没有数据(成员变量)我得到的大小为7,数据大小为12,所以我无法理解这种行为和任何洞察力将是有帮助的,我知道空类的大小是1,在第二个数据成员我希望这应该是11而不是7
答案 0 :(得分:1)
由于空类的大小为7
,因此没有数据成员1
,因此虚拟类包含指向大小为8的虚拟表的指针:8-1=7
。
当涉及数据成员时,您获得的结果取决于成员的实际类型。如果您使用int
,则差异为12
,因为vptr必须与8
的多个对齐。
这意味着int数据成员占用字节frm 0到4,并且vptr不能存储在字节4
,而是从字节8开始。因此,虚拟结构的总大小为8+8=16
。尝试使用double,您将看到差异为8
,如下面的代码所示。
#include <iostream>
using namespace std;
struct virtual_base {
double data;
virtual_base() {}
virtual ~virtual_base() {}
};
struct non_virtual_base {
double data;
non_virtual_base() {}
~non_virtual_base() {}
};
int main() {
std::cout << sizeof( virtual_base ) - sizeof( non_virtual_base ) << '\n';
return 0;
}
答案 1 :(得分:1)
virtual_base
仅包含vftable
指针,在您的平台上显然是8个字节。 virtual_base
也有一个int,vftable
与8个字节对齐。所以它是这样的:
4 bytes for int | 4 padding bytes | 8 bytes for vftable pointer |
| x | x | x | x | | | | | v | v | v | v | v | v | v | v |
请查看this。它可能会有所帮助。
使用int
数据成员:
sizeof(virtual_base) is
16 [4(int)+ 4(填充)+8(vftable)] bytes sizeof(non_virtual_base)
是4个字节,即int
的大小。 没有int
数据成员:
sizeof(virtual_base) is
8个字节,即vftable指针的大小。没有填充物。sizeof(non_virtual_base)
是1个字节。答案 2 :(得分:0)
当您在C ++中将任何函数声明为virtual
时,该类会收到一个隐藏的成员vptr
,该成员指向vtable
。这用于选择在使用dynamic polymorphism时实际应该调用哪个函数。
免责声明:我将使用您发布的在线编译器的结果,使用您设置的选项(C ++ 14,O2优化)
我们可以很容易地看到空类的sizeof
等于1,而具有虚函数的sizeof
类是8。
然后,使用数据成员,没有虚函数的类获得sizeof
4,具有虚函数的类获得sizeof
16。
我们还可以检查sizeof
指针类型(例如int *)是否等于8
所以,这里发生了什么:默认情况下,空类被赋值为1。但是,具有虚函数的类必须具有vptr
成员,该成员本身长度为8个字节。这给你8-1 = 7
当您将成员添加到非虚拟类时,它只会获得其所有成员的大小,在这种情况下它是int,因此您的大小为4.
对于虚拟类,您已经拥有大小为8的vptr
并向其添加大小为4的int。这里structure alignment的机制开始了。据推测,它编译的系统只允许访问偏移量乘以8的字节,因此编译器为了优化访问时间,增加了artifial padding 字节,不保存数据。基本上,你班级的对象看起来像这样:
[int(4B)|padding(4B)|vptr(8B)]
这导致类的大小为16.因此我们得到16 - 4 = 12。