2011-07-20 17 views
21

No tengo experiencia en C++, y vengo de un fondo de Java. Últimamente, en una entrevista me preguntaron por qué Java no permitiría la herencia múltiple y la respuesta fue bastante fácil. Sin embargo, todavía tengo curiosidad sobre cómo trata C++ con eso, ya que te permite heredar de más de una clase.Herencia múltiple, C++ y el mismo método Firma en múltiples súper clases

Específicamente, dicen que hay una clase llamada MechanicalEngineer y otra llamada ElectricalEngineer. Ambos tienen un método llamado buildRobot().

¿Qué pasa si hacemos una tercera clase RoboticsEngineer, que inherets tanto y no anula ese método, y que acaba de llamar al:

(some instance of RoboticsEngineer).buildRobot() 

se lanzará una excepción, o el método de una de las se usarán superclases? Si es así, ¿cómo sabe el compilador qué clase usar?

+4

¿Qué sucede en Java si una clase tiene un método 'buildRobot' y una interfaz tiene un método' buildRobot' y define una subclase que también implementa la interfaz? – toto2

+0

@toto Aparentemente está bien siempre que el tipo de devolución sea el mismo, vea este [hilo] (http://stackoverflow.com/questions/2801878/implemeting-2-interfaces-in-a-class-with-same- method-which-interface-method-is-ov). – toto2

Respuesta

20

El compilador marcará este tipo de situación (es decir, intentando llamar al (some instance of RoboticsEngineer).buildRobot()) como un error.

Esto ocurre porque el objeto derivado tiene una copia de ambos objetos base (una instancia MechanicalEngineer y una instancia) dentro de sí mismo y la firma del método por sí sola no es suficiente para indicar cuál utilizar.

Si reemplaza buildRobot en su RoboticsEngineer, usted será capaz de decir explícitamente que heredó método a utilizar como prefijo el nombre de la clase, por ejemplo:

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

Por la misma moneda, en realidad se puede "forzar" el compilador de usar una u otra versión de buildRobot prefijándolo con el nombre de clase:

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

en este caso la aplicación ElectricalEngineer del método será llamado, sin ambigüedad.

Un caso especial se da cuando se tiene una clase base para Engineer tanto MechanicalEngineer y ElectricalEngineer y especifica la herencia de ser 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. Este sería el siguiente:

class Engineer { 
     void buildRobot(); 
}; 

class MechanicalEngineer: public virtual Engineer { 

}; 

class ElectricalEngineer: public virtual Engineer { 

}; 

En este caso,

(some instance of RoboticsEngineer).buildRobot(); 

se resolverán sin ambigüedades. Lo mismo es cierto si buildRobot se declara virtual y se reemplaza en una de las dos clases derivadas. De todos modos, si ambas clases derivadas (ElectricalEngineer y MechanicalEngineer) anulan buildRobot, entonces la ambigüedad surge una vez más y el compilador marcará el intento de llamar a (some instance of RoboticsEngineer).buildRobot(); como un error.

+0

se puede decir que virtual es lo mismo que la palabra clave "implementar" en java? –

+0

@Yochai Timmer: ¿podría ser más preciso? ¿Qué debería ser virtual en ambos? la herencia o el método? Cualquier declaración que hice fue respaldada por una prueba de compilación que hice ... @Kit Ho: no sé mucho de Java, pero como la herencia 'virtual' tiene sentido para la herencia múltiple, y Java no tiene nada de esto, lo haría lo dudo ... – sergio

+0

@sergio: antes de editar, dijiste que solo necesitas hacer que ambos métodos sean virtuales. Lo que tienes ahora funcionará. Aunque OP preguntó qué pasa si ambas clases base tienen una implementación del método (La pregunta no es acerca de la herencia del diamante) –

5

No lo maneja. Es ambiguo error C2385: ambiguous access of 'functionName'

El compilador es lo suficientemente inteligente como para saber que no debe adivinar su significado.
Para que el programa compile, debe decirle al compilador que:
A. Sabe que es un problema problemático.
B. Diga a qué se refiere exactamente.

Para hacer esto, es necesario indicar explícitamente al compilador el método que está pidiendo:

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

El compilador se quejará de este tipo de situtation.

En tal caso, C++ sugiere crear una interfaz con un método "puro virtual" buildRobot(). MechanicalEngineer y EletricalEnginner heredarán la interfaz y anularán la función buildRoboot().

Cuando crea un objeto RoboticsEnginner y llama a la función buildRobot(), se llamará a la función de la interfaz.

+0

¿Está seguro de que C++ puede heredar de más de dos clases? –

0
struct MecEngineer { 

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

}; 

struct EleEngineer { 

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

}; 

struct RoboticsEngineer : MecEngineer, EleEngineer { 

}; 

Ahora cuando lo hace,

robEngObject -> buildRobot() ; 

Tal llamada no puede ser resuelto y es ambiguo porque tanto los sub-objetos tiene una función miembro con misma firma y el compilador no sabe cuál de ellos llamada. En tal situación, debe mencionarlo explícitamente usando el operador :: o usando static_cast.

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

Demostración: http://ideone.com/EgD7B – Mahesh

+0

Realmente no hay ninguna razón lógica para emitir ya que el uso del operador de alcance es suficiente, más corto y, por lo general, más aceptable en la práctica. –

0

No hay nada acerca de la herencia de clases múltiples que lo permita. 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 sobre él.

+0

En este caso, ¿por qué el compilador lanzará un error/qué error se lanzará? Recuerde que las interfaces en Java son como funciones virtuales puras. Por lo tanto, C necesitará implementar la función y llamarla no generará ambigüedad. – Pratham