虚拟指针大小因类数据成员而异

时间:2018-03-23 08:46:36

标签: c++ virtual

正如本问题的一个解决方案(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

3 个答案:

答案 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;
} 

在这里试试:https://www.ideone.com/Ycpg64

答案 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。