resueltos - Herencia múltiple, C++ y la misma firma de método en varias súper clases
relaciones entre clases c++ (5)
El compilador marcará este tipo de situación (es decir, al intentar llamar (some instance of RoboticsEngineer).buildRobot()
) como un error.
Esto sucede porque el objeto derivado tiene una copia de ambos objetos base (una instancia de MechanicalEngineer
y una instancia de ElectricalEngineer
) dentro de sí mismo y la firma del método por sí sola no es suficiente para indicar cuál usar.
Si reemplaza buildRobot
en su RoboticsEngineer
, podrá decir explícitamente qué método heredado usar prefijando el nombre de la clase, por ejemplo:
void RoboticsEngineer::buildRobot() {
ElectricalEngineer::buildRobot()
}
Por la misma moneda, puedes "forzar" al compilador a usar una versión u otra de buildRobot
con el nombre de la clase:
(some instance of RoboticsEngineer).ElectricalEngineer::buildRobot();
En este caso, se llamará a la implementación del método ElectricalEngineer
, sin ambigüedad.
Se da un caso especial cuando tiene una clase base de Engineer
tanto para MechanicalEngineer
como para ElectricalEngineer
y especifica que la herencia sea virtual
en ambos casos. Cuando se usa virtual
, el objeto derivado no contiene dos instancias de Engineer
, pero el compilador se asegura de que solo haya una de ellas. Esto se vería así:
class Engineer {
void buildRobot();
};
class MechanicalEngineer: public virtual Engineer {
};
class ElectricalEngineer: public virtual Engineer {
};
En este caso,
(some instance of RoboticsEngineer).buildRobot();
Se resolverá sin ambigüedades. Lo mismo es cierto si buildRobot se declara virtual
y se invalida en una de las dos clases derivadas. De todos modos, si ambas clases derivadas (ElectricalEngineer y MechanicalEngineer) anulan a buildRobot
, entonces la ambigüedad surge una vez más y el compilador marcará el intento de llamar (some instance of RoboticsEngineer).buildRobot();
como un error
No tengo experiencia en C ++, y provengo de un entorno Java. Últimamente, en una entrevista me preguntaron por qué Java no permitía la herencia múltiple y la respuesta fue bastante fácil. Sin embargo, todavía siento curiosidad por cómo C ++ se ocupa de eso, ya que le permite heredar de más de una clase.
Específicamente, digamos que hay una clase llamada MechanicalEngineer
y otra llamada ElectricalEngineer
. Ambos tienen un método llamado buildRobot()
.
¿Qué sucede si hacemos un RoboticsEngineer
tercera clase, que hereda de ambos y no invalida ese método, y usted solo llama:
(some instance of RoboticsEngineer).buildRobot()
¿Se lanzará una excepción o se usará el método de una de las superclases? Si es así, ¿cómo sabe el compilador qué clase usar?
El compilador se quejará de este tipo de situación.
En tal caso, c ++ sugiere crear una interfaz con una función buildRobot () del método "virtual puro". MechanicalEngineer y EletricalEnginner heredarán la Interfaz y anularán la función buildRoboot ().
Cuando creas el objeto RoboticsEnginner y llamas a la función buildRobot (), se llamará a la función de la interfaz.
No hay nada acerca de la herencia de clases múltiples que permita esto. Java produce el mismo problema con las interfaces.
public interface A {
public void doStuff();
}
public interface B {
public void doStuff();
}
public class C implements A, B {}
La respuesta simple es que el compilador arroja un error en él.
No lo maneja. Es ambiguo error C2385: ambiguous access of ''functionName''
El compilador es lo suficientemente inteligente como para saber que no debería adivinar su significado.
Para que el programa se compile, debe decirle al compilador que:
A. Sabes que es un problema problemático.
B. Dile a qué te refieres exactamente.
Para hacer esto, necesita decirle explícitamente al compilador qué método está solicitando:
RoboticsEngineer myRobot;
myRobot.ElectricalEngineer::buildRobot();
struct MecEngineer {
void buildRobot() { /* .... */ }
};
struct EleEngineer {
void buildRobot() { /* .... */ }
};
struct RoboticsEngineer : MecEngineer, EleEngineer {
};
Ahora cuando lo hagas,
robEngObject -> buildRobot() ;
Dicha llamada no se puede resolver y es ambigua porque ambos subobjetos tienen una función miembro con la misma firma y el compilador no sabe a cuál llamar. En tal situación, necesita mencionarlo explícitamente usando ::
operator o usando static_cast
.
static_cast<MecEngineer*> (robEngObject) -> buildRobot() ;