C++ - 为什么这种菱形继承结构不会引起歧义?

问题描述

我已经浏览了几十个多重继承问题,但没有找到这个问题的答案。

我明白为什么这不会编译:

struct B{
    virtual void f(){
        printf("B");
    }
};

struct C1 : virtual B{
   void f() override{
        printf("C1");
    }
};

struct C2: virtual B{
    void f() override{
        printf("C2")
    }
};

struct D: C1,C2{
    
};

因为无法确定哪个 f 应该在 B 的 vtable 中。

然而,我很惊讶地看到这段代码会编译:

struct B{
    virtual void f(){
        printf("B");
    }
};

struct C1 : virtual B{
   void f() override{
        printf("C1");
    }
};

struct C2: virtual B{

};

struct D: C1,C2{
    
};

我的(错误的)直觉是我们仍然有两条路径从 DB 并且在每一条路径中,最后一个位置 f 被覆盖是不同的 - 在一条路径中它在 { {1}} 并且在一个路径中它在 C1 中,但这确实可以编译。

为什么这不会引起歧义?

解决方法

因为 C1::f1 覆盖 B::f1,它将优先用于任何具有 C1 动态类型或任何子类的对象。

在模棱两可的情况下,虽然 C1::f1 和 C2::f1 都覆盖了 B::f1,但它们并不相互覆盖,所以歧义是在它们之间——事实上它们都覆盖了一个共同的基函数无关紧要。