Подтвердить что ты не робот

Множественное наследование, С++ и та же подпись метода в нескольких суперклассах

У меня нет опыта работы на С++, и я исхожу из фона Java. В последнее время меня спросили в интервью, почему Java не допускает множественного наследования, и ответ был довольно прост. Тем не менее, мне все еще интересно, как С++ имеет дело с этим, поскольку он позволяет наследовать более чем один класс.

В частности, скажем, что существует класс под названием MechanicalEngineer, а другой - ElectricalEngineer. Оба имеют метод под названием buildRobot().

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

(some instance of RoboticsEngineer).buildRobot()

Будет ли выбрано исключение, или будет использоваться метод из одного из суперклассов? Если да, то каким образом компилятор знает, какой класс использовать?

4b9b3361

Ответ 1

Компилятор будет отмечать такую ​​ситуацию (т.е. пытаться вызвать (some instance of RoboticsEngineer).buildRobot()) как ошибку.

Это происходит из-за того, что производный объект получил копию обоих базовых объектов (экземпляр MechanicalEngineer и экземпляр ElectricalEngineer) внутри себя и одна только сигнатура метода недостаточно, чтобы указать, какой из них использовать.

Если вы переопределите buildRobot в RoboticsEngineer, вы сможете явно указать, какой унаследованный метод использовать, префикс имени класса, например:

void RoboticsEngineer::buildRobot() {
    ElectricalEngineer::buildRobot()
}

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

 (some instance of RoboticsEngineer).ElectricalEngineer::buildRobot();

в этом случае будет реализована реализация метода ElectricalEngineer метода, без двусмысленности.

Частный случай задается, если у вас есть базовый класс Engineer как для MechanicalEngineer, так и ElectricalEngineer, и вы укажете наследование как virtual в обоих случаях. Когда используется virtual, производный объект не содержит двух экземпляров Engineer, но компилятор гарантирует, что есть только один из них. Это будет выглядеть так:

 class Engineer {
      void buildRobot();
 };

 class MechanicalEngineer: public virtual Engineer {

 };

 class ElectricalEngineer: public virtual Engineer {

 };

В этом случае

(some instance of RoboticsEngineer).buildRobot();

будет разрешаться без двусмысленностей. То же самое верно, если buildRobot объявлен virtual и переопределен в одном из двух производных классов. В любом случае, если оба производных класса (ElectricalEngineer и MechanicalEngineer) переопределяют buildRobot, тогда неоднозначность возникает снова, и компилятор будет отмечать попытку вызова (some instance of RoboticsEngineer).buildRobot(); в качестве ошибки.

Ответ 2

Он не справляется с этим. Это двусмысленно. error C2385: ambiguous access of 'functionName'

Компилятор достаточно умен, чтобы знать, что он не должен угадывать ваш смысл.
Для компиляции программы вам необходимо сообщить компилятору, что:
О. Вы знаете, что это проблема. B. Расскажите, что именно вы имеете в виду.

Для этого вам нужно явно указать компилятору, какой метод вы запрашиваете:

RoboticsEngineer myRobot;
myRobot.ElectricalEngineer::buildRobot();

Ответ 3

Компилятор будет жаловаться на подобную ситуацию.

В таком случае С++ предлагает создать интерфейс с функцией "pure virtual" метода buildRobot(). MechanicalEngineer и EletricalEnginner наследуют интерфейс и переопределяют функцию buildRoboot().

Когда вы создаете объект RoboticsEnginner и вызываете функцию buildRobot(), вызывается функция интерфейса.

Ответ 4

struct MecEngineer {

     void buildRobot() { /* .... */ }

};

struct EleEngineer {

     void buildRobot() { /* .... */ }

};

struct RoboticsEngineer : MecEngineer, EleEngineer {

};

Теперь, когда вы это сделаете,

robEngObject -> buildRobot() ;

Такой вызов не может быть разрешен и неоднозначен, потому что оба под-объекта имеют функцию-член с одной и той же сигнатурой, а компилятор не знает, какой из них вызывать. В такой ситуации вам нужно явно указать его с помощью оператора :: или с помощью static_cast.

static_cast<MecEngineer*> (robEngObject) -> buildRobot() ;

Ответ 5

Нет ничего о множественном наследовании класса, которое позволяет это. Java создает ту же проблему с интерфейсами.

public interface A {
    public void doStuff();
}
public interface B {
    public void doStuff();
}
public class C implements A, B {}

Простой ответ заключается в том, что компилятор выдает ему ошибку.