Herencia múltiple

Compartir Imprimir Citar

La herencia múltiple es una característica de algunos lenguajes de programación informáticos orientados a objetos en los que un objeto o clase puede heredar características de más de un objeto o clase principal. Es diferente de la herencia única, donde un objeto o clase solo puede heredar de un objeto o clase en particular.

La herencia múltiple ha sido un tema controvertido durante muchos años, y los opositores señalan su mayor complejidad y ambigüedad en situaciones como el "problema del diamante", donde puede ser ambiguo en cuanto a qué clase padre un determinado La característica se hereda si más de una clase principal implementa dicha característica. Esto se puede abordar de varias maneras, incluido el uso de la herencia virtual. También se han propuesto métodos alternativos de composición de objetos que no se basan en la herencia, como mixins y rasgos, para abordar la ambigüedad.

Detalles

En la programación orientada a objetos (POO), la herencia describe una relación entre dos clases en las que una clase (la clase secundaria) subclases la clase padre. El hijo hereda métodos y atributos del padre, lo que permite una funcionalidad compartida. Por ejemplo, se podría crear una clase variable Mamífero con características como comer, reproducirse, etc.; luego defina una clase secundaria Gato que herede esas funciones sin tener que programarlas explícitamente, mientras agrega nuevas funciones como perseguir ratones.

La herencia múltiple permite a los programadores usar más de una jerarquía totalmente ortogonal simultáneamente, como permitir que Gato herede de Personaje de dibujos animados y Mascota y Mamífero y acceder a funciones desde dentro de todas esas clases.

Implementaciones

Los lenguajes que admiten herencia múltiple incluyen: C++, Common Lisp (a través de Common Lisp Object System (CLOS)), EuLisp (a través de The EuLisp Object System TELOS), Curl, Dylan, Eiffel, Logtalk, Object REXX, Scala (a través del uso de clases mixtas), OCaml, Perl, POP-11, Python, R, Raku y Tcl (integrado desde 8.6 o a través de Incremental Tcl (Incr Tcl) en versiones anteriores).

El tiempo de ejecución de IBM System Object Model (SOM) admite la herencia múltiple, y cualquier lenguaje de programación destinado a SOM puede implementar nuevas clases de SOM heredadas de varias bases.

Algunos lenguajes orientados a objetos, como Swift, Java, Fortran desde su revisión de 2003, C# y Ruby implementan herencia única, aunque los protocolos o interfaces proporcionan parte de la funcionalidad de la verdadera herencia múltiple.

PHP usa clases de rasgos para heredar implementaciones de métodos específicos. Ruby usa módulos para heredar múltiples métodos.

El problema del diamante

Un diagrama de herencia de clase de diamante.

El "problema del diamante" (a veces denominado "Diamante mortal de la muerte") es una ambigüedad que surge cuando dos clases B y C heredan de A, y la clase D hereda tanto de B como de C. Si hay un método en A que B y C han anulado, y D no lo anula, entonces, ¿qué versión del método hereda D: la de B o la de C?

Por ejemplo, en el contexto del desarrollo de software GUI, una clase Button puede heredar de ambas clases Rectangle (por apariencia) y Clickable (para funcionalidad/manejo de entrada), y las clases Rectangle y Clickable heredan de la clase Object. Ahora, si se llama al método equals para un objeto Button y no existe tal método en la clase Button pero hay un anulado equals en Rectangle o Clickable (o ambos), ¿a qué método debería llamarse finalmente?

Se llama el "problema del diamante" debido a la forma del diagrama de herencia de clases en esta situación. En este caso, la clase A está en la parte superior, tanto B como C por separado debajo de ella, y D une las dos en la parte inferior para formar una forma de diamante.

Mitigación

Los lenguajes tienen diferentes formas de lidiar con estos problemas de herencia repetida.

Los lenguajes que solo permiten herencia única, donde una clase solo puede derivar de una clase base, no tienen el problema del diamante. La razón de esto es que dichos lenguajes tienen como máximo una implementación de cualquier método en cualquier nivel de la cadena de herencia, independientemente de la repetición o ubicación de los métodos. Por lo general, estos lenguajes permiten que las clases implementen múltiples protocolos, llamados interfaces en Java. Estos protocolos definen métodos pero no proporcionan implementaciones concretas. Esta estrategia ha sido utilizada por ActionScript, C#, D, Java, Nemerle, Object Pascal, Objective-C, Smalltalk, Swift y PHP. Todos estos lenguajes permiten que las clases implementen múltiples protocolos.

Además, Ada, C#, Java, Object Pascal, Objective-C, Swift y PHP permiten la herencia múltiple de interfaces (llamados protocolos en Objective-C y Swift). Las interfaces son como clases base abstractas que especifican firmas de métodos sin implementar ningún comportamiento. (Las interfaces "puras", como las de Java hasta la versión 7, no permiten ninguna implementación o datos de instancia en la interfaz). Sin embargo, incluso cuando varias interfaces declaran la misma firma de método, tan pronto como ese método está implementado (definido) en cualquier parte de la cadena de herencia, anula cualquier implementación de ese método en la cadena anterior (en sus superclases). Por lo tanto, en cualquier nivel dado de la cadena de herencia, puede haber como máximo una implementación de cualquier método. Por lo tanto, la implementación del método de herencia única no presenta el Problema del Diamante, incluso con la herencia múltiple de interfaces. Con la introducción de la implementación predeterminada para las interfaces en Java 8 y C# 8, todavía es posible generar un problema Diamond, aunque esto solo aparecerá como un error en tiempo de compilación.