Existem vários problemas com herança múltipla quando usados com classes de pleno direito, mas todos eles giram em torno da ambiguidade .
A ambiguidade aparece de algumas maneiras diferentes:
- Se você tem duas classes base com o mesmo campo
x
e o tipo derivado pede x
, o que ele obtém?
- Se as duas
x
variáveis tiverem tipos incongruentes, você poderá inferir.
- Se eles são do mesmo tipo, você pode tentar mesclá-los na mesma variável.
- Você sempre pode expô-los como nomes totalmente qualificados e estranhos.
- Se você tem duas classes base com a mesma função
f
com assinaturas idênticas e alguém chama f
, qual é chamado?
- E se as duas classes base compartilharem outro ancestral virtual comum (o problema do diamante).
- E se a função tiver assinaturas diferentes, mas compatíveis?
- Quando você constrói uma classe com duas classes base, qual construtor das classes base é chamado primeiro? Quando você destrói o objeto, o que é morto?
- Quando você coloca o objeto na memória, como o faz de maneira consistente?
- Como você lida com todos esses casos com 3 classes base? 10?
E isso ignora coisas como despacho dinâmico, inferência de tipo, correspondência de padrões e outras coisas que sei menos sobre as quais se tornam mais desafiadoras quando o idioma suporta herança múltipla de classes completas.
Traços ou mix-ins (ou interfaces ou ...) são todos os constructos que limitam especificamente os recursos de um tipo para que não haja ambiguidade. Eles raramente possuem algo. Isso permite que a composição dos tipos fique mais suave, porque não há duas variáveis ou duas funções ... há uma variável e uma referência; uma função e uma assinatura. O compilador sabe o que fazer.
A outra abordagem comum adotada é forçar o usuário a "construir" (ou misturar) seu tipo, um de cada vez. Em vez de as classes base serem parceiros iguais no novo tipo, você adiciona um tipo a outro - substituindo tudo o que estava lá (geralmente com sintaxe opcional para renomear e / ou reexpor os bits substituídos).
Existe algo que não é possível com mixins / características, mas possível com herança múltipla no estilo C ++?
Dependendo do idioma - geralmente se torna problemático ou impossível mesclar implementações de funções e armazenamento para variáveis de várias classes base e expô-las no tipo derivado.
É possível encontrar um problema de diamante com eles?
Ocasionalmente, variações menos graves aparecerão com base no seu idioma, mas geralmente não. O ponto principal das características é quebrar esse tipo de ambiguidade.