虚拟指针大小因类数据成员而异
virtual pointer size varies based on class data members
正如这个问题的解决方案之一(虚拟指针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
您得到没有数据成员的7
,因为空类的大小1
,而虚拟类包含指向大小为 8:8-1=7
的虚拟表的指针。
当涉及数据成员时,您获得的结果取决于成员的实际类型。如果您使用int
则差异12
,因为 vptr 必须与8
的倍数对齐。 这意味着 int 数据成员占用字节 frm 0 到 4,并且 vptr 不能存储在字节4
处,而是从字节 8 开始存储。因此,虚拟结构的总大小8+8=16
。尝试使用双精度,您将看到差异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;
}
在这里尝试: https://www.ideone.com/Ycpg64
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 |
请看一下这个。这可能会有所帮助。
对于int
数据成员:
sizeof(virtual_base) is
16 [4(整数)+ 4(填充) +8(vftable)] 字节sizeof(non_virtual_base)
是 4 个字节,即int
的大小。
如果没有int
数据成员:
sizeof(virtual_base) is
8 个字节,即 vftable 指针的大小。没有填充。- 没有任何数据成员
sizeof(non_virtual_base)
为 1 个字节。
当您在C++中将任何函数声明为virtual
时,该类会收到一个隐藏成员vptr
,该成员指向vtable
。这用于选择在使用动态多态性时实际应调用哪个函数。
免责声明:我将使用您发布的在线编译器的结果,以及您设置的选项(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。在这里,结构对齐的机制开始发挥作用。据推测,它正在编译的系统只允许访问偏移量为 8 的字节,因此编译器为了优化访问时间,添加了人工填充字节,这些字节不保存任何数据。基本上,类的对象如下所示:[int(4B)|padding(4B)|vptr(8B)]
这导致类的大小为 16。所以我们得到 16 - 4 = 12。
- int数据类型的指针指向的是什么,如果是一个类的私有数据成员,我们创建了该类的两个对象?
- 使用指针访问数组中的对象数据成员
- 共享 C++ 的数据成员指针
- C++数据成员:值与指针
- 如何使用数据成员填充派生类的对象到基类的指针数组中
- 如何在C++中使用类对象访问指针数据成员
- 将指向数据成员的指针传递给 std::invoke 时有哪些用例和有用性?
- 通过指针算法访问结构数据成员
- 如何强制实施有关指针数据成员的常量正确性
- 类数据成员指针的非类型模板参数包无法使用 gcc 编译
- constexpr 偏移量,带有指向成员数据的指针
- 指向未由对象地址初始化的对象的指针如何将值分配给类的数据成员
- 将数据成员的指针传递给基类构造函数是否安全?
- 虚拟指针大小因类数据成员而异
- "new"不会将内存分配给作为类的数据成员的指针
- 关于Lambdas,转换以功能指针以及私人数据成员的可见性
- 向上转换指向数据成员及其多态行为的指针
- 指向数据成员转换的 Constexpr 指针
- 关于C++中指向数据成员的指针的一些混淆
- C 细分故障访问类数据成员,而无需明确使用指针