11

Я пытаюсь понять множественное наследование, вот мой код:множественное наследование без виртуального наследования

struct A { 
    A() {} 
    static int n; 
    static int increment() { return ++n; } 
}; 
int A::n = 0; 

struct B : public A {}; 
struct C : public A {}; 
struct D : public B, C {}; 

int main() { 
    D d; 
    cout<<d.increment()<<endl; 
    cout<<d.increment()<<endl; 
} 

Этот код работает. Однако, если я изменю increment() на нестатический, это не удастся.

Мои вопросы:

  1. Почему компилятор жалуется неоднозначный вызов нестатической версии increment(), а удовлетворяет с статическим?
  2. Если я добавлю еще одну функцию increment() в B или C, компилятор также будет жаловаться, даже объявлен как статический. Зачем?
+0

Примечание: [работает на идеоне] (http://ideone.com/4Hollz) –

ответ

10

Что неоднозначное значит?

Компилятор жалуется на неоднозначные вызовы, когда не может решить, какую функцию вызывать с учетом контекста. Итак, чтобы понять жалобы, вы должны проверить, какие могут быть возможные двусмысленности.

Почему компилятор жалуется на неоднозначный вызов нестатической версии increment(), но удовлетворяет статическому?

По определению функция класса static не зависит от какого-либо экземпляра класса. Это подчеркивается тем фактом, что вы могли бы назвать его A::increment() (см., Нет примера).

Проблема алмаза наследования не то, что компилятор не знает, какой код выполнить, то, что это не знает, какие this обеспечить (есть два A в вашем D объекта, один содержащийся в B и один в C).

Если вы используете функцию staticA, не пропускается неявный this, поэтому проблем нет; если вы попытаетесь использовать функцию не static, тогда компилятор не может решить, должно ли this указывать на A в B или в C, это неоднозначно.

Если я добавлю другую функцию increment() в B или C, компилятор также будет жаловаться, даже объявлен как статический. Зачем?

На данный момент, компилятор может выбрать между B::increment() и C::increment(), что он должен выбрать?Это неоднозначно.

Если у вас есть линейная иерархия, она называет «ближе» к нему (который скрывает тот, далее вниз по дереву наследования), но здесь B и C две независимых ветви, и нет «лучше» филиала.

Примечание: даже если B не реализует increment, поскольку A делает вы можете вызвать B::increment(), который на самом деле вызывает A::increment(). То же самое касается C.

9
  1. Это называется проблемой наследования алмазов. У вас есть два класса, которые являются производными от A. Тогда класс получен из двух. У вас есть две версии нестатического приращения void(). Со статикой у вас есть один.
  2. Поскольку вы можете, но не должны переопределять не виртуальную функцию, и, возможно, ваш компилятор является строгим или строгим.

Алмазные наследование: http://www.parashift.com/c++-faq/mi-diamond.html Скрытие функции: http://www.parashift.com/c++-faq/hiding-inherited-public.html

2

Это заявление:

struct D : public B, C {}; 

создать бы два экземпляра A. Компилятор должен знать от , который экземпляр вы намерены вызвать метод. Функция static - это не что иное, как глобальная функция, которая является дружественной к классу - единственное требование - это полное имя, когда собеседник намерен его вызвать. Static не будет играть никакой роли в наследовании.

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