Il problema più ovvio è con l'override della funzione.
Supponiamo di avere due classi A
e B
, entrambe definiscono un metodo doSomething
. Ora definisci una terza classe C
, che eredita da A
e B
, ma non sovrascrivi il doSomething
metodo.
Quando il compilatore esegue il seed di questo codice ...
C c = new C();
c.doSomething();
... quale implementazione del metodo dovrebbe utilizzare? Senza ulteriori chiarimenti, è impossibile per il compilatore risolvere l'ambiguità.
Oltre all'override, l'altro grosso problema con l'ereditarietà multipla è il layout degli oggetti fisici in memoria.
Linguaggi come C ++ e Java e C # creano un layout basato su indirizzi fissi per ogni tipo di oggetto. Qualcosa come questo:
class A:
at offset 0 ... "abc" ... 4 byte int field
at offset 4 ... "xyz" ... 8 byte double field
at offset 12 ... "speak" ... 4 byte function pointer
class B:
at offset 0 ... "foo" ... 2 byte short field
at offset 2 ... 2 bytes of alignment padding
at offset 4 ... "bar" ... 4 byte array pointer
at offset 8 ... "baz" ... 4 byte function pointer
Quando il compilatore genera codice macchina (o bytecode), utilizza quegli offset numerici per accedere a ciascun metodo o campo.
L'ereditarietà multipla lo rende molto complicato.
Se la classe C
eredita da A
e B
, il compilatore deve decidere se disporre i dati in AB
ordine o in BA
ordine.
Ma ora immagina di chiamare metodi su un B
oggetto. È davvero solo un B
? O è effettivamente un C
oggetto chiamato polimorficamente, attraverso la sua B
interfaccia? A seconda dell'identità effettiva dell'oggetto, il layout fisico sarà diverso ed è impossibile conoscere l'offset della funzione da richiamare nel sito di chiamata.
Il modo per gestire questo tipo di sistema è abbandonare l'approccio del layout fisso, consentendo a ogni oggetto di essere interrogato per il suo layout prima di tentare di invocare le funzioni o accedere ai suoi campi.
Quindi ... per farla breve ... è una seccatura per gli autori di compilatori supportare l'ereditarietà multipla. Quindi, quando qualcuno come Guido van Rossum progetta python, o quando Anders Hejlsberg progetta c #, sa che supportare l'ereditarietà multipla renderà le implementazioni del compilatore significativamente più complesse e presumibilmente non pensano che il vantaggio valga il costo.