Por que inheritance múltipla não é permitida em Java ou C #?

Eu sei que inheritance múltipla não é permitida em Java e C #. Muitos livros apenas dizem que inheritance múltipla não é permitida. Mas isso pode ser implementado usando interfaces. Nada é discutido sobre por que isso não é permitido. Alguém pode me dizer precisamente porque não é permitido?

A resposta curta é: porque os designers de linguagem decidiram não fazê-lo.

Basicamente, parecia que os designers .NET e Java não permitiam inheritance múltipla, porque eles acreditavam que a adição de MI adicionava muita complexidade às linguagens e, ao mesmo tempo, proporcionava muito pouco benefício .

Para uma leitura mais divertida e profunda, há alguns artigos disponíveis na web com entrevistas de alguns dos designers de linguagem. Por exemplo, para .NET, Chris Brumme (que trabalhou no MS no CLR) explicou as razões pelas quais eles decidiram não:

  1. Diferentes linguagens têm expectativas diferentes sobre como o MI funciona. Por exemplo, como os conflitos são resolvidos e se as bases duplicadas são mescladas ou redundantes. Antes de implementar o MI no CLR, temos que fazer um levantamento de todas as linguagens, descobrir os conceitos comuns e decidir como expressá-los de maneira neutra em relação ao idioma. Também teríamos que decidir se o MI pertence ao CLS e o que isso significaria para idiomas que não querem esse conceito (presumivelmente VB.NET, por exemplo). Claro, esse é o negócio em que estamos como um tempo de execução de linguagem comum, mas ainda não conseguimos fazer isso para o MI.

  2. O número de lugares onde o MI é verdadeiramente apropriado é realmente muito pequeno. Em muitos casos, a inheritance de várias interfaces pode realizar o trabalho. Em outros casos, você poderá usar o encapsulamento e a delegação. Se fôssemos adicionar um construto um pouco diferente, como mixins, seria realmente mais poderoso?

  3. A inheritance de implementação múltipla injeta muita complexidade na implementação. Essa complexidade afeta o lançamento, o layout, o despacho, o access ao campo, a serialização, as comparações de identidade, a verificação, a reflection, os genéricos e provavelmente muitos outros lugares.

Você pode ler o artigo completo aqui.

Para Java, você pode ler este artigo :

As razões para omitir múltiplas inheritances da linguagem Java derivam principalmente do objective “simples, orientado a objects e familiar”. Como uma linguagem simples, os criadores de Java queriam uma linguagem que a maioria dos desenvolvedores pudesse entender sem treinamento extensivo. Para esse fim, eles trabalharam para tornar a linguagem tão semelhante ao C ++ quanto possível (familiar) sem carregar a complexidade desnecessária do C ++ (simples).

Na opinião dos designers, a inheritance múltipla causa mais problemas e confusão do que resolve. Então, eles cortam várias inheritances da linguagem (assim como cortam a sobrecarga do operador). A extensa experiência em C ++ dos designers ensinou-lhes que a inheritance múltipla não valeria a dor de cabeça.

Herança múltipla de implementação é o que não é permitido.

O problema é que o compilador / tempo de execução não pode descobrir o que fazer se você tiver uma class Cowboy e uma Artist, ambas com implementações para o método draw (), e então tentar criar um novo tipo CowboyArtist. O que acontece quando você chama o método draw ()? Alguém está morto na rua, ou você tem uma linda aquarela?

Eu acredito que é chamado de problema de inheritance de duplo diamante.

Razão: Java é muito popular e fácil de codificar, devido à sua simplicidade.

Então, o que os desenvolvedores Java acham difícil e complicado de entender para os programadores, eles tentaram evitá-lo. Um desses tipos de propriedade é inheritance múltipla.

  1. Eles evitaram pointers
  2. Eles evitaram inheritance múltipla.

Problema com inheritance múltipla: problema de diamante.

Exemplo :

  1. Suponha que a class A esteja tendo um método divertido (). class B e class C derivam da class A.
  2. E ambas as classs B e C, sobrescrevem o método fun ().
  3. Agora suponha que a class D herda tanto a class B como a C. (apenas Suposição)
  4. Criar object para a class D.
  5. D d = novo D ();
  6. e tente acessar d.fun (); => vai chamar diversão da class B () ou diversão da class C ()?

Essa é a ambigüidade existente no problema dos diamantes.

Não é impossível resolver este problema, mas cria mais confusão e complexidades para o programador ao lê-lo. Causa mais problemas do que tenta resolver.

Nota : Mas, de qualquer forma, você sempre pode implementar várias inheritances indiretamente usando interfaces.

Porque o Java tem uma filosofia de design muito diferente do C ++. (Eu não vou discutir C # aqui.)

Ao projetar o C ++, o Stroustrup queria include resources úteis, independentemente de como eles poderiam ser usados ​​de maneira incorreta. É possível estragar tempo grande com inheritance múltipla, sobrecarga de operadores, modelos e vários outros resources, mas também é possível fazer algumas coisas muito boas com eles.

A filosofia de design do Java é enfatizar a segurança em construções de linguagem. O resultado é que há coisas que são muito mais difíceis de fazer, mas você pode estar muito mais confiante de que o código que você está olhando significa o que você acha que faz.

Além disso, o Java foi, em grande medida, uma reação do C ++ e do Smalltalk, as linguagens OO mais conhecidas. Há muitas outras linguagens OO (o Common Lisp foi o primeiro a ser padronizado), com diferentes sistemas OO que lidam melhor com MI.

Sem mencionar que é perfeitamente possível fazer MI em Java, usando interfaces, composição e delegação. É mais explícito que em C ++ e, portanto, é mais desajeitado para ser usado, mas vai te dar algo que você está mais propenso a entender à primeira vista.

Não há resposta certa aqui. Existem respostas diferentes e qual é a melhor para uma dada situação depende das aplicações e da preferência individual.

A principal (embora não a única) razão pela qual as pessoas se afastam do MI é o chamado “problema do diamante” que leva à ambigüidade na sua implementação. Este artigo da wikipedia discute e explica melhor do que eu poderia. O MI também pode levar a um código mais complexo, e muitos projetistas OO afirmam que você não precisa de MI, e se você usá-lo, seu modelo provavelmente está errado. Não tenho certeza se concordo com este último ponto, mas manter as coisas simples é sempre um bom plano.

Em C ++, inheritance múltipla era uma grande dor de cabeça quando usada de forma inadequada. Para evitar esses problemas de design populares, várias interfaces “inheritance” foram forçadas em linguagens modernas (java, C #).

A inheritance múltipla é

  • dificíl de entender
  • É difícil depurar (por exemplo, se você misturar classs de várias estruturas que possuem methods com nome idêntico no fundo, podem ocorrer sinergias inesperadas)
  • fácil de usar mal
  • não é realmente tão útil
  • difícil de implementar, especialmente se você quer que seja feito de forma correta e eficiente

Portanto, pode ser considerado uma escolha sábia não include a inheritance múltipla na linguagem Java.

Outra razão é que a inheritance única torna o lançamento trivial, não emitindo instruções de assembly (além de verificar a compatibilidade dos tipos, quando necessário). Se você tivesse inheritance múltipla, precisaria descobrir em que ponto da class filha um determinado pai é iniciado. Portanto, o desempenho é certamente um privilégio (embora não seja o único).

Eu tomo a afirmação de que “inheritance múltipla não é permitida em Java” com uma pitada de sal.

Herança Múltipla é definida quando um “Tipo” herda de mais de um “Tipo”. E as interfaces também são classificadas como tipos, pois possuem comportamento. Então, o Java tem inheritance múltipla. Só que é mais seguro.

O carregamento dynamic de classs dificulta a implementação de inheritance múltipla.

Em java, na verdade, eles evitavam a complexidade de várias inheritances, usando inheritance e interface únicas. Complexidade de inheritance múltipla é muito alta em uma situação como abaixo explicada

problema de diamante de inheritance múltipla. Temos duas classs B e C herdando de A. Suponha que B e C estejam substituindo um método herdado e forneçam sua própria implementação. Agora D herda de B e C fazendo inheritance múltipla. D deve herdar esse método sobrescrito, o jvm não pode decidir qual método sobrescrito será usado?

Em c ++ funções virtuais são usadas para manipular e temos que fazer explicitamente.

Isso pode ser evitado usando interfaces, não há corpos de método. Interfaces não podem ser instanciadas – elas só podem ser implementadas por classs ou estendidas por outras interfaces.

Nos velhos tempos (anos 70) quando a Ciência da Computação tinha mais ciência e menos produção em massa, os programadores tinham tempo para pensar em bom design e boa implementação e como resultado os produtos (programas) tinham alta qualidade (por exemplo, design TCP / IP). e implementação). Hoje em dia, quando todo mundo está programando, e os gerentes estão mudando as especificações antes dos prazos, questões sutis, como a descrita no link da wikipedia do Steve Haigh, são difíceis de rastrear; portanto, a “inheritance múltipla” é limitada pelo design do compilador. Se você gosta, você ainda pode usar o C ++ …. e ter toda a liberdade que você deseja 🙂

Na verdade, múltiplas inheritances surgirão a complexidade se as classs herdadas tiverem a mesma function. ou seja, o compilador terá uma confusão que deve ser escolhida (problema de diamante). Então, em Java, essa complexidade foi removida e deu interface para obter a funcionalidade como a inheritance múltipla deu. Nós podemos usar a interface

Java tem conceito, ou seja, polymorphism. Existem dois tipos de polymorphism em java. Há sobrecarga de methods e substituição de methods. Entre eles, a substituição de methods acontece com relação de super e subclass. Se estamos criando um object de uma subclass e invocando o método da superclass, e se a subclass estender mais de uma class, qual método de superclass deve ser chamado?

Ou, enquanto chama o construtor de superclass de super() , qual construtor de superclass será chamado?

Essas decisões são impossíveis pelos resources atuais da API Java. Portanto, inheritance múltipla não é permitida em java.

A inheritance múltipla não é permitida diretamente em Java, mas por meio de interfaces é permitida.

Razão:

Herança Múltipla: Introduz mais complexidade e ambigüidade.

Interfaces: Interfaces são classs completamente abstratas em Java que fornecem uma maneira uniforme de delinear adequadamente a estrutura ou o funcionamento interno de seu programa a partir de sua interface disponível publicamente, com a conseqüência de maior flexibilidade e código reutilizável, bem como maior controle sobre como você cria e interage com outras classs.

Mais precisamente, eles são uma construção especial em Java com a característica adicional que permite que você execute um tipo de inheritance múltipla, isto é, classs que podem ser convertidas para mais de uma class.

Vamos dar um exemplo simples.

  1. Suponha que haja duas classs de superclasss A e B com os mesmos nomes de methods, mas com funcionalidades diferentes. Através do seguinte código com (extends) palavra-chave inheritance múltipla não é possível.

      public class A { void display() { System.out.println("Hello 'A' "); } } public class B { void display() { System.out.println("Hello 'B' "); } } public class C extends A, B // which is not possible in java { public static void main(String args[]) { C object = new C(); object.display(); // Here there is confusion,which display() to call, method from A class or B class } } 
  2. Mas através de interfaces, com (implementa) palavra-chave inheritance múltipla é possível.

     interface A { // display() } interface B { //display() } class C implements A,B { //main() C object = new C(); (A)object.display(); // call A's display (B)object.display(); //call B's display } } 

Alguém pode me dizer precisamente porque não é permitido?

Você pode encontrar respostas neste link de documentação

Uma razão pela qual a linguagem de programação Java não permite estender mais de uma class é evitar os problemas de inheritance múltipla de estado, que é a capacidade de herdar campos de várias classs.

Se inheritance múltipla for permitida e quando você criar um object instanciando essa class, esse object herdará campos de todas as superclasss da class. Isso causará dois problemas.

  1. E se methods ou construtores de diferentes super classs instanciarem o mesmo campo?

  2. Qual método ou construtor terá precedência?

Mesmo que a inheritance múltipla do estado seja permitida agora, você ainda pode implementar

Herança múltipla do tipo : Capacidade de uma class para implementar mais de uma interface.

Herança múltipla de implementação (através de methods padrão em interfaces): Capacidade de herdar definições de methods de várias classs

Consulte esta questão SE relacionada para obter informações adicionais:

Ambiguidade de inheritance múltipla com interface

Em C ++, uma class pode herdar (direta ou indiretamente) de mais de uma class, que é chamada de inheritance múltipla .

C # e Java, no entanto, limitam as classs à inheritance única que cada class herda de uma única class pai.

A inheritance múltipla é uma maneira útil de criar classs que combinam aspectos de duas hierarquias de classs diferentes, o que geralmente acontece quando se usam estruturas de classs diferentes em um único aplicativo.

Se duas estruturas definirem suas próprias classs base para exceções, por exemplo, você poderá usar várias inheritances para criar classs de exceção que possam ser usadas com qualquer estrutura.

O problema com inheritance múltipla é que isso pode levar à ambigüidade. O exemplo clássico é quando uma class herda de duas outras classs, cada uma delas herdada da mesma class:

 class A { protected: bool flag; }; class B : public A {}; class C : public A {}; class D : public B, public C { public: void setFlag( bool nflag ){ flag = nflag; // ambiguous } }; 

Neste exemplo, o membro de dados do flag é definido pela class A Mas a class D desce da class B e da class C , ambas derivadas de A , portanto, em essência, duas cópias do flag estão disponíveis porque duas instâncias de A estão na hierarquia de classs de D Qual você quer definir? O compilador irá reclamar que a referência a flag em D é ambígua . Uma correção é explicitamente desambiguar a referência:

 B::flag = nflag; 

Outra correção é declarar B e C como virtual base classs , o que significa que apenas uma cópia de A pode existir na hierarquia, eliminando qualquer ambigüidade.

Outras complexidades existem com inheritance múltipla, como a ordem em que as classs base são inicializadas quando um object derivado é construído ou a maneira como membros podem ser ocultados inadvertidamente de classs derivadas. Para evitar essas complexidades, algumas linguagens restringem-se ao modelo de inheritance simples mais simples.

Embora isso simplifique consideravelmente a inheritance, também limita sua utilidade, pois somente classs com um ancestral comum podem compartilhar comportamentos. As interfaces atenuam essa restrição, permitindo que classs em diferentes hierarquias exponham interfaces comuns, mesmo se não forem implementadas pelo compartilhamento de código.

Imagine este exemplo: eu tenho uma class Shape1

Tem o método CalcualteArea :

 Class Shape1 { public void CalculateArea() { // } } 

Existe outra class Shape2 que também tem o mesmo método

 Class Shape2 { public void CalculateArea() { } } 

Agora eu tenho uma class de criança Circle, deriva de Shape1 e Shape2;

 public class Circle: Shape1, Shape2 { } 

Agora, quando eu crio o object para Circle, e chamo o método, o sistema não sabe qual método de área de cálculo deve ser chamado. Ambos tem as mesmas assinaturas. Então, o compilador vai ficar confuso. É por isso que várias inheritances não são permitidas.

Mas pode haver várias interfaces porque as interfaces não têm definição de método. Mesmo as duas interfaces possuem o mesmo método, ambas não possuem nenhuma implementação e o método always na class filha será executado.