Existe uma lógica de uso diferente para classes / interfaces abstratas em C ++ e Java


13

De acordo com Herb Sutter, deve-se preferir interfaces abstratas (todas as funções virtuais puras) a abstrair classes em C ++ para dissociar a implementação o máximo possível. Embora eu pessoalmente ache essa regra muito útil, ingressei recentemente em uma equipe com muitos programadores Java e, no código Java, essa diretriz parece não existir. Funções e suas implementações são frequentemente localizadas em classes abstratas. Então, eu errei o Herb Sutter, mesmo em C ++, ou existe uma diferença geral no uso de funções abstratas em C ++ em comparação com Java. As classes abstratas com código de implementação são mais sensíveis em Java do que em C ++ e, se sim, por quê?


1
Eu tive algumas dúvidas e finalmente coloquei aqui porque poderia ser devido a alguns princípios de design que estou perdendo no java oo. Assim, pois, não se trata de um conselho geral, mas mais sobre o certo eo errado para usar a linguagem
Martin

As interfaces devem ser puramente virtuais. A ideia das classes abstratas é que elas sejam parcialmente implementadas e cabe à implementação preencher as lacunas sem repetir o código desnecessariamente (por exemplo, por que escrever (byte) e escrever (int) em todas as subclasses quando você pode ter o classe chamada de classe write (byte) de write (int))

1
Possivelmente relacionado: stackoverflow.com/q/1231985/484230 fornece um motivo para preferir classes abstratas em java. Para C ++ isso não parece ser verdade, devido à existência de funções livres que podem adicionar funcionalidades ao nível da interface
Martin

1
Eu acho que a Regra de Ouro é "tornar as classes não-folha abstratas", mas isso não torna nenhum requisito "apenas puro" ou "vazio".
31512 Kerrek SB

1
Se funciona para você, funciona para você. Realmente não vejo por que as pessoas entram em pânico quando seu código não adere mais às últimas opiniões.
James James

Respostas:


5

OOP tem composição e substituição.

O C ++ possui herança múltipla, especialização de modelo, incorporação e semântica de valor / movimentação / ponteiro.

Java possui herança e interfaces únicas, semântica de incorporação e referência.

A maneira comum de a escola OOP usar esses idiomas é empregar herança para substituição de objetos e incorporação para composição. Mas você também precisa de um ancestral comum e de uma maneira de converter o tempo de execução (em C ++ é chamado dynamic_cast, em Java é apenas pedir uma interface a outra).

Java faz tudo isso por sua própria java.lang.Objecthierarquia enraizada. O C ++ não possui uma raiz comum predefinida, portanto, você deve pelo menos defini-la, para obter a mesma "imagem" (mas isso está limitando algumas possibilidades do C ++ ...).

Depois disso, a possibilidade de ter polimorfismo em tempo de compilação (pense no CRTP) e semântica de valor também pode oferecer outras alternativas à maneira como o conceito de "objeto OOP" pode ser portado para um programa C ++.

Você pode até imaginar a heresia de usar a incorporação e a conversão implícita para gerenciar a substituição e a herança privada para gerenciar a composição, de fato invertendo o paradigma tradicional da escola. (É claro que, dessa maneira, é 20 anos mais novo que o outro, por isso não espere um amplo apoio da comunidade para fazer isso)

Ou você pode imaginar uma base comum virtual para todas as classes, interface de formulário (sem implementação) para classes finais (totalmente implementada) passando por interfaces parcialmente implementadas e até clusters de interface, usando "dominância" como despacho da interface para implementações através de um "multi-stacked" -parallelogram "esquema de herança.

Comparar OOP com java e C ++, assumindo que há apenas uma e única maneira de OOP está limitando os recursos de ambos os idiomas.

Forçar o C ++ a aderir estritamente aos idiomas de codificação Java está desnaturando o C ++, como forçar o Java a se comportar como uma linguagem semelhante ao C ++ está desnaturando o Java.

Não é uma questão de "sensibilidade", mas de diferentes "mecanismos de agregação" que as duas línguas têm e uma maneira diferente de combiná-las, o que torna um idioma mais lucrativo em um idioma que o outro e vice-versa.


1
Penso que esta resposta é muito interessante, pois descreve sucintamente os recursos da linguagem como uma ferramenta para princípios de design e design, apenas como uma ajuda e não uma doutrina. No entanto, você não precisa de uma raiz comum se quiser fazer oo no c ++. Isso está simplesmente errado, também pelo fato de você ter operadores e modelos (que são uma alternativa muito poderosa ao design da árvore principal do java, como você também apontou). Para além de que seus pontos são os mais vantajoso em todas as respostas
Martin

1
@ Martin: No "sentido técnico", você está certo, mas se precisar de polimorfismo em tempo de execução (porque o tipo real dos objetos instanciados depende da entrada do programa), uma "raiz" ('a' é um artigo, não um atalho para " um e apenas ") é o que torna todos os objetos" primos "e a hierarquia executável em tempo de execução. Raízes diferentes originam ancestrais diferentes, não relacionados entre si. Se isso é "bom" ou "ruim" é uma questão de contexto, não de idioma.
Emilio Garavaglia

Isso é verdade. Eu pensei que você estava se referindo a fornecer artificialmente uma raiz geral para um programa inteiro em c ++ e vi como defeito que ele não está presente, comparado ao java. Mas após a sua edição, você deixa bem claro o ponto. Obrigado novamente
Martin

12

O princípio vale para os dois idiomas, mas você não está fazendo uma comparação justa. Você deve comparar as classes abstratas puras do C ++ com as interfaces Java.

Mesmo em C ++, você pode ter classes abstratas que possuem algumas das funções implementadas, mas derivam de uma classe abstrata pura (sem implementações). Em Java, você teria as mesmas classes abstratas (com algumas implementações), que podem derivar de interfaces (sem implementações).


Então, quando você prefere uma classe abstrata a uma classe de interface em c ++. Eu sempre optei pela interface, além de funções não membros em c ++.
Martin

1
@ Martin que depende do design. Basicamente, sempre prefira uma interface. Mas " sempre " regras têm exceções ...
Luchian Grigore

É verdade, mas no Código Java eu ​​estou vendo classes abstratas representando a maioria. Isso pode ser devido ao fato de que funções livres trabalhando em interfaces não são possíveis em java?
Martin

3
As funções bem livres do Martin não são de todo possíveis em Java, então isso pode ser um motivo. Bom lugar! Respondeu sua própria pergunta! Você pode adicionar uma resposta, acho que é isso.
Luchian Grigore 7/08

4

Geralmente, os mesmos princípios de OO são verdadeiros para Java e C ++. No entanto, uma grande diferença é que o C ++ suporta herança múltipla enquanto em Java você pode herdar apenas de uma classe. Essa é a principal razão pela qual o Java possui interfaces, acredito, para complementar a falta de herança múltipla e provavelmente restringir o que você pode fazer com ela (já que há muitas críticas sobre o abuso de herança múltipla). Portanto, provavelmente na mente de programadores Java, há uma distinção mais forte entre classes abstratas e interfaces. Classes abstratas são usadas para compartilhar e herdar comportamento, enquanto as interfaces são simplesmente usadas para adicionar funcionalidade extra. Lembre-se, em Java, você pode herdar de apenas uma classe, mas pode ter muitas interfaces. No C ++, no entanto, as classes abstratas puras (ou seja, uma "interface C ++") são usado para compartilhar e herdar comportamento, diferentemente do objetivo de uma interface Java (embora você ainda precise implementar as funções), portanto, o uso é diferente das interfaces Java.


0

Às vezes, faz sentido ter alguma implementação padrão. Por exemplo, um método genérico PrintError (string msg) aplicável a todas as subclasses.

virtual PrintError(string msg) { cout << msg; }

Ele ainda pode ser substituído, se realmente necessário, mas você pode economizar um pouco de trabalho ao cliente, permitindo que ele chame apenas a versão genérica.

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.