多重继承虚拟调用歧义

Multiple Inheritance Virtual Call Ambiguity

手头的问题很难描述,所以为了更清楚起见,代码放在前面。

struct Base
{
    int b;
    virtual void foo(){cout << b << endl;}
    Base(int x) : b(x){}
};

struct Derived1 : Base    //not virtual
{
    virtual void foo(){/*Derived2's code*/}
    Derived1() : Base(1){}
};

struct Derived2 : Base    //not virtual
{
    virtual void foo(){/*Derived2's code*/}
    Derived2() : Base(2){}
};

struct MultiInheritance : Derived1, Derived2
{
    void bar1()
    {
        //needs to access Derived1's Base foo()
    }
    void bar2()
    {
        //needs to access Derived2's Base foo()
    }
};

假设在一些奇怪的情况下,我想要一个基数 class MultiInheritance 有两个基数 classes Derived1Derived2有一个共同的 非虚拟 基础 class Base.

MultiInheritance里有两个Base,如何指定我想在MultiInheritance里访问哪个Baseclass?

上面的代码似乎可以通过转换几次来正常工作,但我不确定这是否是已定义的行为。如果是,编译器如何实现它来满足多态性的需要?一方面,virtual 调用都应该产生相同的 virtual 函数 table,但另一方面,如果是,则不会输出不同的答案。

编辑

我想强调 Base classes 必须是 non-virtual

EDIT2

深表歉意,我严重歪曲了自己。上面的代码更新后更好地反映了我原来的问题。

这就是众所周知的菱形问题。

http://www.cprogramming.com/tutorial/virtual_inheritance.html

如果你想保持 base 非虚拟并获得你现在正在寻找的行为,你可以在 MultipleInheritance 中按照以下方式执行此操作,以确保你从正确的 base class

struct MultiInheritance : Derived1, Derived2
{
    void bar1()
    {
       Derived1::foo();
    }
    void bar2()
    {
        Derived2::foo();
    }
};

There are two Base in MultiInheritance, how do I specify which Base class I wish to access in MultiInheritance?

您不清楚调用哪个基对象

void MultiInheritance::bar1(){
     foo();
}

解决这个问题的方法是告诉编译器在哪里寻找 foo。

void MultiInheritance::bar1(){
     Derived1::foo();  // The same foo() as in your question.
}

这是您

完成的
void MultiInheritance::bar1()
{
    Derived1& d = *this;

标准中的 §10.2.12 对此进行了描述。这是明确定义的。和你的

连锁店一样
void MultiInheritance::bar1()
{
    Derived1& d = *this;
    Base& b = *this;

同款

不幸的是,范围解析运算符无法让您从 MultiInhteritance 直接跳转到 Base as

MultiInheritance::foo(){
     Derived1::Base::foo();

正在描述一个嵌套 class Base

要获取属于 Base 的 foo(),您可以在 MultiInheritance 以及 Derived1 和 Derived2 中使用范围解析语法。

Derived1()::foo(){
    Base::foo; 

如果这不合适,那么您提出的选项就是剩余的选项。

If it is, how is this implemented by the compiler to fulfill the needs of polymorphism? On one hand virtual calls should all result in the same virtual function table, but on the other if it does it wouldn't output different answers.

编译器实现因编译器而异,正如评论者所说:对虚函数使用 vtables 是一个实现细节。如果一个实现使用虚函数的虚表,实现需要考虑到这种情况。

这是一个更能说明问题的例子。

#include <iostream>
using namespace std;

template <typename Res, typename Arg>
Res& as(Arg& arg)
{
  return arg;
}

struct Base
{
    virtual void foo() = 0;
};

struct Derived1 : Base {};
struct Derived2 : Base {};

struct MoreDerived1 : Derived1
{
    void foo() { cout << "Derived1\n"; }
};

struct MoreDerived2 : Derived2
{
    void foo() { cout << "Derived2\n"; }
};

struct MultiInheritance : MoreDerived1,  MoreDerived2
{
    void bar1() { as<Derived1>(*this).foo(); }
    void bar2() { as<Derived2>(*this).foo(); }
};

int main ()
{
     MultiInheritance m;
     m.bar1();
     m.bar2();
}

这个例子说明:

  1. 您不需要使用完整的继承路径明确指定您需要哪个 Base,向下到具有明确 Base 子对象的子对象就足够了
  2. 虚函数机制在这里发挥作用。如果您尝试调用 Derived1::foo().
  3. ,它将不起作用

as辅助函数只是一个语法糖,你也可以说

Derived1& d = *this;
d.foo();