About multiple inheritance and ambiguity

2019-07-15 08:41发布

问题:

In the following example:

class A {
public:
    virtual void f() { cout << "a" << endl; }
    virtual void h() { cout << "A" << endl; }
};
class s1 : public A {
public:
    virtual void f() { cout << "s1" << endl; }
};
class s2 : public A {
public:
    virtual void h() { cout << "s2" << endl; }
};
class GS : public s1, public s2 {
public:
};
int main()
{
    s1 *q = new GS;
    q->h();//no problem

    GS a;
    a.h();//error

}

Why does a.h(); give an ambiguity error yet q->h(); doesn't?

Doesn't *q have an instance of GS which should cause the same ambiguity problem?

回答1:

Your use of multiple inheritance causes two instances of A to appear in GS. When you use S1 *q to access the GS instance, it follows the A instance associated with S1. Since S1 does not implement h(), the output of q->h() will be the implementation provided by A itself.

If you want q->h() to use the implementation provided by S2, then you need to create a diamond using virtual inheritance. Doing so will also remove the ambiguity when using a.h(), since virtual inheritance will cause only one instance of A to appear in GS.

class s1 : virtual public A {
public:
    virtual void f() { cout << "s1" << endl; }
};
class s2 : virtual public A {
public:
    virtual void h() { cout << "s2" << endl; }
};


回答2:

Name lookup is based on static type not dynamic type. (And it has to be, since it occurs at compile time not run time.)



回答3:

Because your pointer is of type s1 so the compiler knows to call h() (inherited from class A). Try using a pointer of type GS and you'll get an error for the pointer too. In the case of GS you are inheriting from s1 and s2, both classes inherit from A and thus, multiple(2) definitions of h() are found which is ambigious. This is the dreaded diamond.



回答4:

Ok, this is because when the compiler evaluates q->h(), q only has one function named 'h' in its scope since it is of type s1.

When the compiler evaluates a.h(), a has two functions named 'h' in its scope. The one from s1 and the one from s2.

The compiler doesn't know which one you wanted to use, so it throws an error.



回答5:

*q doesn't give an ambiguity error because its type is s1*. This means that the compiler will call s1::h, which is unambiguous.