Já existem bons pontos em outras respostas, mas eu gostaria de fornecer uma resposta mais completa, abordando suas perguntas e declarações individualmente.
Se o Java não fornece um recurso que o C ++ possui, significa que o recurso não é bom, portanto, devemos evitar usá-lo.
Isso foi muito bem respondido: Java não é "as partes boas" do C ++, nem há qualquer razão para pensar isso.
Em particular, embora os méritos de cada recurso C ++ individual sejam discutíveis, muitos dos recursos do C ++ 11 / C ++ 14 que não fazem parte do Java não são necessariamente excluídos porque os designers do Java acharam que era uma má idéia. Como exemplo, até a versão 8, o Java não tinha lambdas, mas elas foram introduzidas no C ++ no padrão C ++ 11. Antes do Java 8, sua suposição de que os recursos C ++ ausentes do Java estavam ausentes por design porque eles "não são bons" implicaria que lambdas como um recurso de linguagem "não são bons" (para o horror dos LISPers em todos os lugares, apesar de serem provavelmente horrorizado o suficiente para ouvir que você aparentemente gosta de Java). Mas agora os designers de Java colocaram seu Stamp of Approval (TM) em lambdas, então agora são uma coisa boa.
Para aprofundar um pouco mais, mesmo no Java 8, os lambdas como fechamentos não são tão flexíveis quanto os lambdas do C ++ 14, mas isso pode ser devido a limitações da arquitetura da JVM, em vez de uma decisão consciente de que a abordagem mais flexível é ruim para um cliente. perspectiva de design de linguagem.
O código C ++ com recursos específicos do C ++ (por exemplo: funções de amigo, herança múltipla) só pode ser mantido ou revisado pelos programadores de C ++, mas se escrevermos C ++ como Java (sem o recurso específico da linguagem C ++), o código poderá ser mantido ou revisado por ambos. Programadores em C ++ e Java.
Esta é a principal coisa que eu queria responder.
Em termos gerais, pode haver algum valor em obter análises de código de programadores que não estão intimamente familiarizados com o idioma que você está usando. Eles podem fornecer um feedback valioso sobre a clareza dos nomes e comentários de suas funções / métodos e (como sua pergunta indica corretamente), se o idioma for semelhante a um ou mais idiomas que eles já conhecem, eles poderão seguir o fluxo básico do programa e potencialmente capturar erros lógicos.
No entanto, não é esse o caso que esse tipo de revisão será "tão boa quanto" ou "equivalente a" a revisão de desenvolvedores que realmente conhecem o idioma que você está usando. Essencialmente, isso ocorre porque fazer com que uma linguagem pareça com outra normalmente oculta diferenças sutis, enquanto faz com que uma linguagem se comporte como outra (especialmente no caso de C ++ e Java) pode não ser idiomática para a linguagem e / ou ainda pode ser muito confusa. para os revisores.
Primeiro, vamos pensar no que significaria fazer o C ++ "parecer" Java. Como um caso simples, você pode usar new
para instanciar objetos, assim como em Java:
Foo foo = new Foo();
Mas os objetos instanciados dessa maneira usam em ->
vez de .
chamar métodos, portanto, se você deseja que as chamadas se pareçam com Java, você deve escrever:
Foo& foo = *new Foo();
Mas isso não é idiomático; em particular, a memória deve ser limpa posteriormente delete &foo
, que alguns desenvolvedores experientes em C ++ podem nem perceber que é um código legal . De qualquer forma, existem símbolos não-Java-like engraçadas polvilhadas por toda parte, por isso não podemos bastante tornar a linguagem "parecer" Java. (Você pode eliminar o *new
uso #define New *new
, ou, pior, #define new *new
mas você está apenas implorando para que seus colegas desenvolvedores o odeiem.) E, como mencionado acima, delete
não existe em Java, portanto, em qualquer caso (como mencionado em outra resposta ) você nunca pode realmente fazer com que o uso de objetos "pareça" da maneira que acontece em Java sem vazamentos de memória.
Mas o C ++ moderno inclui ponteiros compartilhados inteligentes, que se comportam muito como as referências de variáveis gerenciadas por memória do Java. Então, em todo lugar em Java que você pode escrever Foo foo = new Foo();
, você pode escrever:
std::shared_ptr<Foo> foo = std::make_shared<Foo>();
Agora você está usando um recurso de linguagem que é realmente muito parecido com o Java. Mas de repente você tem muito a explicar aos revisores que não são do C ++: o que é isso shared_ptr
? Quais são os truques sutis e complicados make_shared
? (Ele usa o encaminhamento perfeito, que tem alguns casos de falha e pode levar à chamada do construtor "errado".) Por que os métodos precisam ser chamados ->
, mas o uso .
com alguns métodos é permitido pelo compilador? ( shared_ptr
possui métodos próprios.) Se o método Foo::reset(void)
existe, um desenvolvedor incauto pode tentar chamá-lo foo.reset()
, o qual (se houver apenas um ponteiro compartilhado apontando para a instância de Foo
quando a chamada ocorre) excluirá a memória subjacente e anulará foo
, e É provável que os desenvolvedores Java não detectem esse problema.
Além disso, C ++ tem um monte de armadilhas que são específicas para a linguagem. Tanto quanto posso dizer, a maioria dos desenvolvedores de C ++ aprende a lidar com essas armadilhas desenvolvendo gradualmente seu próprio idioma para práticas "seguras" de C ++, que geralmente são únicas para eles ou para sua equipe de desenvolvimento (veja, por exemplo, a resposta existente que menciona o As práticas de codificação do Google e o comentário dizendo que "veteranos experientes em C ++ geralmente rejeitam as diretrizes de codificação do Google"). Todas as alegações de que a linguagem pode ser muito complicada, ao que parece (pelo menos na minha experiência), geralmente são encontradas com algumas variações de "bem, pare de usá-la de maneira errada". Sei que esta é uma visão altamente negativa da ++ comunidade C, e há certamente desenvolvedores experientes mais dispostos a ajudar de linguagem alunos, mas não faz parece ser uma certa atitude defensiva sobre, por exemplo, comportamento indefinido (veja, por exemplo, grande parte da discussão no meu link 'armadilhas' acima).
Os desenvolvedores de Java simplesmente não serão úteis para encontrar e corrigir essas armadilhas via revisão de código.
Você pode ser solicitado a converter o código em Java algum dia.
É totalmente válido - até recomendável - tentar levar em consideração o que pode acontecer com seu código no futuro enquanto você estiver na fase de design.
Mas, primeiro, essa consideração em particular parece uma possibilidade remota: o código normalmente é reutilizado como está (por exemplo, você pode conectar parte ou todo o código C ++ em trabalho em algum software Java futuro usando uma interface JNI) ou reescrito inteiramente do que diretamente "transcrito" manualmente.
E, segundo, você diz mais tarde,
Todo recurso específico da linguagem C ++ (por exemplo: herança múltipla) deve ter alternativas a serem implementadas em Java ....
Isso basicamente cancela o ponto "converter para Java". Se o software é escrito em C ++ idiomático e depois convertido em Java idiomático, não há razão para esperar que essa conversão (ou possa!) Seja feita aplicando um mapeamento preciso dos recursos do C ++ aos recursos Java.
Código sem recursos específicos do C ++ geralmente é mais sustentável.
Não está claro o que você quer dizer aqui, mas concordo um pouco com parte disso: a menos que você seja muito cuidadoso e, mesmo quando cuidadoso, os recursos do C ++ podem levar a problemas de manutenção. O C ++ FQA Lite (um site crítico da linguagem e de seus seguidores de alguém que pelo menos parece realmente entendê-la bastante bem) afirma que
... 80% dos desenvolvedores entendem no máximo 20% da linguagem. Não é o mesmo 20% para pessoas diferentes, portanto, não conte com elas para entender o código uma da outra.
ATENÇÃO: Se você é um fã de C ++ e chega a esse ponto na minha resposta, sente-se inclinado a pular para os comentários para argumentar que o autor do FQA não entende realmente C ++ ou é falso na maioria de seus argumentos , observe que (1) exatamente duas frases depois que eu o citei, reconheço que o FQA é uma fonte muito tendenciosa e (2) realmente não importa o que estou tentando dizer se o autor do FQA entende ou não C ++ , e não estou tentando bash em C ++, e você deve ler o restante da postagem sem assumir que sou anti-C ++ apenas porque citei o FQA. Fim da nota.
Da mesma forma, Linus Torvalds odeia C ++ por esse motivo (aviso: o link envolve muitos palavrões, no verdadeiro estilo infame de Linus).
Obviamente, essas abordagens são muito tendenciosas, mas mesmo os proponentes de C ++ costumam dizer que você não deve usar a totalidade do conjunto de recursos de idiomas (mais uma vez, consulte as diretrizes de codificação do Google; também Bjarne Stroustrup, criador de C ++ , declarou publicamente: "No C ++, há uma linguagem muito menor e mais limpa lutando para sair").
Então, acho que há algum mérito na ideia de que os recursos do C ++ podem ser muito fáceis de usar, especialmente se você é oriundo de Java. Além disso, há mérito na idéia de aliviar esses problemas, restringindo-se a algum subconjunto do idioma.
No entanto, decidir qual subconjunto usar com base em um idioma diferente não parece a abordagem correta, a menos que o "idioma diferente" seja C, pois realmente existe um subconjunto do tipo C da linguagem C ++. (Linus se refere a isso em seu discurso acima, e Scott Meyers até se refere a esse subconjunto como uma "sub-linguagem".) O paradigma de tempo de execução do Java (coletado de lixo, executando em uma VM) é tão fundamentalmente diferente dos C ++ que é não está claro que existem lições úteis a serem tiradas sobre o uso do C ++ e, como observado acima, tentar extrair lições sobre o C ++ diretamente do Java pode levar a um código muito não-idiomático.
Em vez disso, tente definir seu "subconjunto aceitável" do idioma para entender como o idioma pode ser usado idiomaticamente. Se você deseja um subconjunto bastante restritivo que ainda aproveite muitos dos recursos do C ++ além do que o C oferece, a diretriz do Google Coding acima mencionada pode ser um bom ponto de partida. Claro, você terá desenvolvedores que dizem que "não há argumento racional" para algumas das restrições do Google , mas, a menos que você esteja procurando contratar Alexandrescu para longe do trabalho dele na linguagem D (que por si só deveria lhe dizer algo), provavelmente está bem. Certamente é melhor do que tentar transformar C ++ em Java.
Outro bom ponto de partida para um conjunto de diretrizes de código é o novo C ++ Core Guidelines , um trabalho em andamento de Bjarne Stroustrup e Herb Sutter.
A única outra maneira de lidar com as deficiências do C ++ é escolher um idioma diferente. Parece que você gosta de Java e acha que há uma chance de que esse projeto possa ser convertido em Java eventualmente. Como observado em outra resposta, você pode simplesmente ... começar com Java.
Há duas razões pelas quais você pode realmente precisar usar algo diferente de Java:
- Você realmente precisa do desempenho em tempo de execução. Nesse caso, tratar C ++ como Java provavelmente não o ajudará, porque técnicas semelhantes a Java, como ponteiros compartilhados, degradam seu desempenho em tempo de execução.
- Você precisa que o software funcione em uma plataforma obscura que ainda não suporta a JVM. Nesse caso, você provavelmente está preso a idiomas que possuem front-ends GCC ou Clang. C e C ++ são candidatos óbvios, mas você também pode procurar algo como Rust. (Plugue rápido: não usei Rust extensivamente, mas parece incrível e estou ansioso para trabalhar em um grande projeto Rust o mais rápido possível, e acho que todos que estão pensando em iniciar um projeto C ++ devem considerar o Rust como uma alternativa.)
Todo recurso específico da linguagem C ++ (por exemplo: herança múltipla) deve ter alternativas a serem implementadas em Java. Caso contrário, isso significa que o padrão de design ou a arquitetura de código é problemática.
Eu já falei sobre isso um pouco, mas intencionalmente deixei de fora sua segunda frase.
Não estou convencido de que algo como constexpr
, que não faria sentido em uma linguagem parcialmente JIT como Java, seja uma indicação de arquitetura inválida. Estou mais aberto à ideia de que o uso excessivo da meta-programação de modelos pode ser mais problemático do que vale a pena, especialmente agora que constexpr
existe para fazer a avaliação de funções em tempo de compilação, mas fica claro a partir do caso constexpr
que não há falha de design se você está usando: você está simplesmente garantindo que alguns cálculos ocorram antes mesmo de executar o código, o que é um incrível aumento de desempenho (veja, por exemplo, esta entrada para o problema de corpo n do jogo Benchmark Game , que supera todas as outras entradas, exceto outra escrito em C ++,