Problema do diamante
En linguaxes de programación orientada a obxectos, o problema do diamante é unha ambigüidade que xorde cando dúas clases B e C herdan de A, e a clase D herda de B e C. Se un método en D chama a un método definido en A, por qué clase o herda, B ou C?
Chámase o problema do 'diamante' pola forma do diagrama de herdanza de clase nesta situación. A clase A está enriba, B e C están separadas debaixo dela, e D únese ás dúas na parte inferior conseguindo a forma dun diamante.
Propostas
[editar | editar a fonte]Diferentes linguaxes de programación diríxense a este problema de maneiras diferentes:
- C++ por defecto segue cada ruta de herdanza por separado, polo que un obxecto D realmente contendería dous obxectos A separados, e o uso dos membros de A debe ser adecuadamente definido. Se a herdanza de A a B e a herdanza de A a C están marcadas como "virtuais" ("class B : virtual A"), C++ preocúpase por crear só un obxecto A, e o uso dos membros de A funciona correctamente. Se herdanza virtual e herdanza non virtual son mesturadas, hai un só A virtual e un só A non virtual para cada ruta de herdanza non virtual a A.
- Common Lisp intenta ofrecer tanto o comportamento por defecto como a capacidade de redefinilo. Por defecto, escóllese o método coas clases argumento máis específicas ; é dicir, na orde na que as clases pai son nomeadas na definición da subclase. Porén, o programador pode redefinir isto, dando unha orde de resolución de método específico ou establecendo unha regra para a combinación de métodos.
- Eiffel manexa esta situación seleccionando e renomeando directivas, onde os métodos dos ascendentes a empregar nun descendente son explicitamente especificados. Isto permite que os métodos da clase base sexan compartidos entre seus descendentes o incluso dar a cada un deles unha copia separada da clase base.
- Perl e Ío manexan isto mediante a especificación das clases de herdanza nunha lista ordenada. Na ambigüidade mostrada arriba, a clase B e os seus ascendentes serían comprobados antes da clase C e os seus ascendentes, polo que o método A sería herdado a través de B.
- Python ten que tratar con isto dende a introdución de clases de novo estilo, das que todas teñen un ascendente común,
object
. Python crea unha lista de clases que se buscan de esquerda a dereita e de abaixo cara a arriba (D, B, A, C, A) e logo elimina tódalas aparicións dunha clase repetida menos a última. Polo que, a orde de resolución do método é: D, B, C, A.
Outros exemplos
[editar | editar a fonte]Linguaxes que só permiten herdanza simple como (como Objective-C, PHP, C#, e Java) permiten a herdanza múltiple de interfaces (chamadas protocolos en Objective-C). As interfaces son esencialmente clases base abstractas con tódolos métodos abstractos e sen membros de datos. O problema é por tanto evitado xa que sempre hai só unha posta en funcionamento para un método ou propiedade específico e non xorde ningunha ambigüidade.
O problema do diamante non está limitado á herdanza. Tamén xorde cando arquivos de cabeceira A, B, C e D inclúen ("#include") os uns ós outros nun diamante como arriba e cabeceiras precompiladas separadas son creadas dende B e C. Se estas dúas cabeceiras precompiladas son combinadas, as declaracións en A son duplicadas e a convención "#ifndef" non é efectiva. Tamén atópase ó compoñer pilas de middleware; por exemplo, se A é unha base de datos e B e C son cachés, D pode pedir tanto a B como a C a confirmación dunha transacción, dando lugar a chamadas de confirmación a A duplicadas.