多重继承,无函数覆盖。为什么含糊不清

时间:2015-02-22 13:27:16

标签: c++ multiple-inheritance

这是我的课程。这只是

#include<iostream>
using namespace std;

class Base
{
public:
    int var;

    Base(int val) : var(val)
    {}

    void foo()
    {
        cout << "Class Base foo()" << endl;
    }
};

class Derived_A : public Base
{
public:
    Derived_A(int val) : Base(val)
    {}
};

class Derived_B : public Base
{
public:
    Derived_B(int val) : Base(val)
    {}
};

class Derived_AB : public Derived_A, public Derived_B
{
public:
    Derived_AB(int var1, int var2) : Derived_A(var1), Derived_B(var2)
    {}
};

int main(int argc, char** argv)
{
    Derived_AB ABDerObj(1,2);
    ABDerObj.foo();
    return 0;
}

这给了我一个编译器错误,说foo调用是不明确的。

函数foo不会在任何地方被覆盖。我知道有两个类Base实例,因为没有虚继承。所以有两个&#39; var&#39;变量。但我不明白为什么编译器在foo调用中有歧义。函数不是特定于实例的。他们是特定阶级的。为什么编译器会出错?

我正在使用Visual Studio 2013。

谢谢。

2 个答案:

答案 0 :(得分:3)

多重继承使你继承函数foo()的两倍:一个作为Derived_A的一部分,一个作为Derived_B的一部分,因为它们都继承了自己的BaseClass

BaseClass      BaseClass
    |               |
Derived_A      Derived_A  
     \           /
      \         /
       Derived_AB

因此,编译器不知道它是否应该使用Derived_ADerived_B子对象的数据执行它。

解决方案:

1)您可以在每次通话中明确消除歧义:

ABDerObj.Derived_A::foo();  // execute foo() for the Deived_A object

2)您可以通过定义公共foo来明确地在类级别消除歧义,例如:

void foo()
{
    Derived_A::foo();   // you want all the foos called
    Derived_B::foo();
}

3)如果您希望BaseClass只有一个Derived_AB,那么您应该将BaseClass设为Derived_ADerived_B的虚拟基类。然后Derived_AB将只有一个BaseClass,而对foo()的调用不再含糊不清。

        BaseClass
       /        \
      /          \
Derived_A      Derived_A  
     \           /
      \         /
       Derived_AB  

(在这种情况下,您还应为BaseClass()定义Dervived_AB.初始值设定项

答案 1 :(得分:2)

  

功能不是特定于实例的。他们是特定阶级的。

仅适用于静态函数。假设我将foo()的实现更改为以下内容:

void foo()
{
    cout << "My value is " << var << endl;
}

您希望ABDerObj.foo();打印什么?


由于这是一个答案,我还提供两种可能的解决方案。

如果foo确实是特定于实例的(例如,因为它使用类字段var,您可以轻松地告诉编译器您要调用哪个Base::foo()({{ 1}}或Derived_A版本)指定您要使用的那个

Derived_B

或者只是扔掉另一部分:

ABDerObj.Derived_A.foo();      // prints: My value is 1
ABDerObj.Derived_B.foo();      // prints: My value is 2

如果你有一段代码,你将只使用 ((Derived_A) ABDerObj).foo(); // prints: My value is 1 ((Derived_B) ABDerObj).foo(); // prints: My value is 2 功能,后者最有用,例如:

Derived_A

另一方面,如果 - 坚持你的术语 - Derived_A& ABDerObjPartA = ABDerObj; ABDerObjPartA.foo(); // more code using ABDerObjPartA. 的定义实际上取决于类而不是实例,请将其foo

static

通常,一旦你开始出现这些消歧问题,他们就会变得更糟,稍微重新设计你的代码会使其更易于维护。