Что такое ромбовидное наследование (diamond problem)?

«Что такое ромбовидное наследование (diamond problem)?» — вопрос из категории ООП, который задают на 33% собеседований Data Инженер. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

Ромбовидное наследование — это проблема неоднозначности, возникающая в языках с множественным наследованием, когда класс наследуется от двух классов, которые, в свою очередь, наследуются от одного общего базового класса. Это создаёт неопределённость: от какого из двух промежуточных родителей должен быть унаследован метод общего предка?

Пример на C++ (где проблема проявляется явно):

class A {
public:
    void method() { cout << "A"; }
};

class B: public A {};
class C: public A {};

class D: public B, public C {}; // Ромбовидное наследование

int main() {
    D d;
    d.method(); // Ошибка компиляции: неоднозначность — method() из B::A или C::A?
}

Решение в C++ — виртуальное наследование:

class B: virtual public A {};
class C: virtual public A {};
// Теперь в D будет только одна копия A, и вызов d.method() корректен.

В Python эта проблема решается автоматически с помощью порядка разрешения методов (MRO), который следует алгоритму C3 linearization. MRO определяет чёткий порядок обхода родительских классов.

class A:
    def method(self): print("A")
class B(A): pass
class C(A): pass
class D(B, C): pass

print(D.mro()) # [<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>]
d = D()
d.method() # Однозначно выведет "A", найденный через класс B согласно MRO.