2016-01-29 2 views
2

В следующем примере:О множественного наследования и неоднозначности

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 

} 

Почему a.h(); дают ошибку неоднозначности еще q->h(); нет?

Не имеет *q экземпляр GS, который должен вызывать такую ​​же проблему двусмысленности?

ответ

4

Ваше использование множественного наследования приводит к появлению двух экземпляров A в GS. Когда вы используете S1 *q для доступа к экземпляру GS, он следует примеру A, связанному с S1. Так как S1 не реализует h(), выход q->h() будет реализован сам по себе.

Для использования реализации, предоставляемой S2, вам необходимо создать алмаз, используя виртуальное наследование. Это также устранит двусмысленность при использовании a.h(), поскольку виртуальное наследование приведет к появлению только одного экземпляра A в 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; } 
}; 
+0

С виртуальным наследованием 'GS' всегда будет искать ближайший базовый класс с функцией, которая ему нужна? Здесь 'a.h();' перейдет к 's2 :: h()' перед 'A :: h()'? – shinzou

+0

Это нормальное правило виртуального интерфейса. Реализация производного класса переопределяет интерфейс базового класса, если интерфейс виртуальный. – jxh

1

Хорошо, это потому, что, когда компилятор оценивает q-> h(), q имеет только одну функцию с именем «h» в своей области действия, поскольку она имеет тип s1.

Когда компилятор оценивает a.h(), a имеет две функции с именем «h» в своей области. Один из s1 и один из s2.

Компилятор не знает, какой из них вы хотите использовать, поэтому он выдает ошибку.

1

*q не дает ошибку двусмысленности, потому что ее тип s1*. Это означает, что компилятор вызовет s1::h, что недвусмысленно.

3

Потому что ваш указатель имеет тип s1, поэтому компилятор знает, чтобы позвонить h() (унаследован от класса A). Попробуйте использовать указатель типа GS и вы получите сообщение об ошибке для указателя. В случае GS вы наследуете от s1 и s2, оба класса наследуют от A и, таким образом, найдено несколько (2) определений h(), что является двусмысленным. Это dreaded diamond.

+0

Страшный бриллиант, на который вы указываете, не совсем проблема OP. Однако очень похожее и виртуальное наследование все еще остается решением. – AndyG

+0

@AndyG Виртуальное наследование может быть «решением». Но неясно, в чем проблема, или даже если проблема существует. – curiousguy

4

Поиск по имени основан на статическом типе, а не динамическом типе. (И это должно быть, поскольку оно происходит во время компиляции, а не во время выполнения.)

Смежные вопросы