我试图理解虚拟函数以及虚拟继承。在大多数情况下,我认为我已经成功地掌握了它及其与多态性的关系,我一直在阅读vptr如何与派生对象一起工作,而哪些则不行,但是下面的示例让我失望,这是我在算法和C ++书籍中的数据结构:

#include <iostream>
using namespace std;

class Class1 {
public:
    virtual void f() {
        cout << "Function f() in Class1\n";
    }

    void g() {
        cout << "Function g() in Class1\n";
    }
};

class Class2 {
public:
    virtual void f() {
        cout << "Function f() in Class2\n";
    }

    void g() {
        cout << "Function g() in Class2\n";
    }
};

class Class3 {
public:
    virtual void h() {
        cout << "Function h() in Class3\n";
    }
};

int main() {
    Class1 object1, *p;
    Class2 object2;
    Class3 object3;

    p = &object1;
    p->f();
    p->g();

    p = (Class1*) &object2;
    p->f();
    p->g();

    p = (Class1*) &object3;
    p->f(); // possibly abnormal program termination;
    p->g();
    // p->h(); // h() is not a member of Class1;
    return 0;
}


输出:

Function f() in Class1
Function g() in Class1
Function f() in Class2
Function g() in Class1
Function h() in Class3
Function g() in Class1


除了最后一个p->f();,我了解所有内容。作为一个序言,由于强制转换为h()类型,我们不能直接从p调用Class1,但是Class3 vptr不应仅指向其vtable中的虚函数h() ,如果是这样,它是否不应该在f() vtable中寻找Class3's而找不到呢?为什么它认为Class1::f()Class3::h(),而不是Class3是从Class1继承而来的...为了记录,如果我们将Class3重写为:

class Class3 : public Class1 { // publicly inherit from Class1 is only difference
    public:
    virtual void h() {
        cout << "Function h() in Class3\n";
    }
};


并向上转换为Class1指针,然后调用p->f()它将按预期提供给我们Class1::f(),我只是想不出为什么p->f()不继承自Class3时为何甚至允许我们调用Class1的原因。

最佳答案

这个例子很糟糕,您正在相互转换不相关的类型。这导致未定义的行为。

该代码利用了不同对象类型之间假定的布局相似性。 vtable将在每个对象中的相同位置,并且虚拟函数将通过索引而不是名称找到。因此,对Class1的第一个虚拟函数的调用会在表中生成一个调用,从而导致对Class3的第一个虚拟函数的调用。请记住,尽管这是偶然的,并且C ++的任何属性都不能保证。

09-30 18:07