首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >虚拟表的意外大小

虚拟表的意外大小
EN

Stack Overflow用户
提问于 2020-02-10 11:21:34
回答 2查看 383关注 0票数 1

我正在研究C++继承,所以我编写了以下代码:

代码语言:javascript
复制
// 08 Diamond Inheritance 02.cpp : Defines the entry point for the console application.
//   I'm using Microsoft Visual Studio 2015

#include <iostream>

using namespace std;

class SuperVirtual
{
public:
    int sv;
    SuperVirtual(int p1 = 11) : sv(p1)
    {
        cout << "\n SuperVirtual ctor for &" << this;
    }

    virtual void methodSuperVirtual_01()
    {
        cout << "\n Inside SuperVirtual::methodSuperVirtual_01(): sv = " << ++sv;
    }

    virtual void methodSuperVirtual_02()
    {
        cout << "\n Inside SuperVirtual::methodSuperVirtual_02(): sv = " << ++sv;
    }
};

//---------------------------------- 
class DerivedSV_01 : public SuperVirtual
{
public:
    int dsv;
    DerivedSV_01(int p1 = 21) : dsv(p1)
    {
        cout << "\n DerivedSV_01 ctor for &" << this;
    }
    virtual void methodSuperVirtual_01() override
    {
        cout << "\n Inside DerivedSV_01::methodSuperVirtual_01()";
    }
    //----------------------------------------------------
    virtual void onlyForDerivedSV_01()
    {
        cout << "\n Inside DerivedSV_01::onlyForDerivedSV_01()";
    }
};

int main()
{
    SuperVirtual sv1(1);
    sv1.methodSuperVirtual_01();

    DerivedSV_01 dsv_01;
    dsv_01.methodSuperVirtual_01();
    dsv_01.onlyForDerivedSV_01();

    return 0;
}

我读过这篇文章:

每当类本身包含虚拟函数或重写父类的虚拟函数时,编译器将为该类构建一个vtable。vtable包含指向该类中的虚拟函数的函数指针。每个类只能有一个vtable,而同一个类的所有对象都将共享同一个vtable。

此时,我假设类SuperVirtual的虚拟表包含2个元素,而DerivedSV_01类的虚拟表包含3个元素:2个用于继承(并最终被卵巢覆盖)方法+1用于新的虚拟方法onlyForDerivedSV_01()

但是,在使用Visual检查main()中创建的对象时,我发现:

  1. 例如,类SuperVirtual的虚拟表包含两个元素(OK !)
  2. 例如,类DerivedSV_01的虚拟表包含两个元素(,为什么?)

为了信息的完整性,我提供以下截图:

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2020-02-10 13:09:14

在调试模式下编译(编译器优化关闭)时,我可以在VS2019中准确地使用您的代码来再现这一点。我确信这只是调试器窗口中的一个显示问题。

请注意,__vfptr数组仅显示在SuperVirtual下,而不是直接显示在dsv_01下,因此调试器当然只知道SuperVirtual vtable中的函数。

但是,如果您查看__vfptr__vfptr列,您会注意到在SuperVirtual::'vftable'[3]DerivedSV_01::'vftable[4]' (都标记为绿色)中给出了不同的数组大小。

让我们看看vftable上的内存(vftable的地址可以在Value列的开头看到,用于__vfptr条目,并标记为橙色和红色)。

您将注意到SuperVirtual::'vftable'[3]有两个函数指针(标记为褐色)和一个nullptrDerivedSV_01::'vftable[4]'有三个指针(标记为紫色和蓝色)和一个nullptr。调试器窗口告诉我们前两个条目是什么(也标记为紫色),但是查看一下“监视”窗口中的第三个条目(标记为蓝色)。

调试器说第三个条目是DerivedSV_01::onlyForDerivedSV_01。这完全符合你(和我)的期望。

票数 2
EN

Stack Overflow用户

发布于 2020-02-10 11:33:22

答案很简单,“就像”规则起作用了。

编译器指出,onlyForDerivedSV_01从未以多态方式使用(因为没有DerivedSV_01的子类),因此它被转换为常规方法。

因此,您只有两个继承表单基类的虚拟方法。

实际上,在完全优化的情况下,编译器应该能够删除对此代码的所有虚拟调用。在这里你可以看到所有方法都直接放在main函数中,只有虚拟调用才能在std::cout上执行。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/60149330

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档