【问题标题】:Virtual functions - where's the pointer?虚函数——指针在哪里?
【发布时间】:2011-04-10 17:48:53
【问题描述】:

一个开始的例子。

class A
{
    public:
    virtual const char* GetName() { return "A"; }
};

class B: public A
{
public:
    virtual const char* GetName() { return "B"; }
};

class C: public B
{
public:
    virtual const char* GetName() { return "C"; }
};

    class D: public C
{
public:
    virtual const char* GetName() { return "D"; }
};

int main()
{
    C cClass;
    A &rBase = cClass;
    cout << "rBase is a " << rBase.GetName() << endl;

    return 0;
}

在这个特定的例子中,输出是:

rBase 是一个 C

以下是它的工作步骤:

rBase 是 A 类型的指针,因此它会转到 A 类并查找 GetName()。但是 GetName() 在那里是虚拟的,因此编译器会检查 A 和 C 之间的所有类,并从最派生的类(即 C)中获取 GetNAme() 函数

但是,我的疑问是编译器如何知道哪个是 A 类的子类,以及它如何能够从父类移动到 B 类等等?孩子知道自己是父母,但父母不知道自己是孩子(我想!)。

在我看来,正确的执行步骤应该是:

rBase 是 A 类型的指针,因此它会转到 A 类并查找 GetName()。但是 GetName() 在那里是虚拟的,因此编译器会检查指针指向的类。在这种情况下是 C 类对象,所以转到 C 类并检查它是否具有函数 GetName() 以便使用它。如果 C 类中不存在该函数(假设),编译器可以轻松地跟踪 C 的父级并检查相同的内容,这可以继续直到它返回到 A(假设除 A 之外的所有类都不包含 GetName())。

现在,这似乎是一种更合乎逻辑的方法,因为在继承树中向后移动(从子到父)似乎比向前(从父到子)更容易实现。

问候,

【问题讨论】:

    标签: c++ function inheritance virtual


    【解决方案1】:

    您描述的第二种算法是“正确的”,因为它会以这种方式有效地解决问题。但是,编译器使用了一个很好的技巧来快进该算法。基本上,它使用通常称为virtual method table 的查找,通常缩写为“vtable”。

    基本上,具有虚拟方法的类的实例持有指向其类的虚拟方法表的指针。编译器将虚拟方法名称映射到虚拟表中的偏移量,这样调用虚拟表就不需要复杂的算法:只需进行数组查找,然后在结果地址处调用。

    【讨论】:

      【解决方案2】:

      rBase 是类型 A 的指针,因此它会转到类 A 并查找 GetName()。但是 GetName() 在那里是虚拟的,因此编译器会检查 A 和 C 之间的所有类,并从最派生的类(即 C)中获取 GetName() 函数

      不,这不是它的工作方式。编译器在生成代码以通过指向A 的指针调用virtual GetName() 时只是放置类似“调用与对象关联的虚拟表中的第7 个条目”之类的内容。在生成覆盖GetName() 的派生类时,编译器会将其GetName() 实现放在虚拟表中的此条目处。

      这样父类不需要知道它的子类。孩子们有责任正确填写他们的虚拟桌子。

      【讨论】:

        猜你喜欢
        • 2010-10-10
        • 2016-07-12
        • 1970-01-01
        • 1970-01-01
        • 2019-08-03
        • 2014-05-04
        • 1970-01-01
        • 2012-11-10
        • 1970-01-01
        相关资源
        最近更新 更多