Ci sono già alcuni punti positivi in altre risposte, ma vorrei fornire una risposta più completa, rispondendo alle vostre domande e dichiarazioni singolarmente.
Se Java non fornisce una funzionalità di C ++, significa che la funzionalità non è buona, quindi dovremmo impedirne l'utilizzo.
La risposta è stata abbastanza buona: Java non è "la parte buona" di C ++, né c'è motivo di pensarlo.
In particolare, sebbene i meriti di ogni singola caratteristica C ++ siano discutibili, molte delle caratteristiche di C ++ 11 / C ++ 14 che non fanno parte di Java non sono necessariamente escluse perché i progettisti Java pensavano che fossero una cattiva idea. Ad esempio, fino alla versione 8, Java non aveva lambda, ma erano stati introdotti in C ++ nello standard C ++ 11. Prima di Java 8, il tuo presupposto che le funzionalità C ++ mancanti da Java mancassero dal punto di vista della progettazione perché "non buone" avrebbero implicato che lambdas come funzionalità del linguaggio non fosse "buono" (con orrore dei LISPer ovunque, sebbene siano probabilmente abbastanza inorridito da sentire che apparentemente in realtà ti piace Java). Ma ora i designer Java hanno messo il loro Stamp of Approval (TM) su lambdas, quindi ora sono una buona cosa.
Per scavare un po 'più a fondo, anche in Java 8, le lambda come chiusure non sono flessibili come le lambde di C ++ 14, ma ciò potrebbe essere dovuto alle limitazioni dell'architettura JVM piuttosto che alla decisione consapevole che l'approccio più flessibile è negativo da un prospettiva di progettazione del linguaggio.
Il codice C ++ con funzionalità specifiche di C ++ (ad esempio: funzioni amico, ereditarietà multipla) può essere gestito o esaminato solo dai programmatori C ++, ma se scriviamo semplicemente C ++ come Java (senza funzionalità specifica del linguaggio C ++), il codice può essere gestito o rivisto da entrambi Programmatori C ++ e Java.
Questa è la cosa principale a cui volevo rispondere.
In linea di massima, potrebbe essere utile ottenere revisioni del codice da programmatori che non hanno familiarità con la lingua che si sta utilizzando. Possono darti un prezioso feedback sulla chiarezza dei nomi e dei commenti della funzione / metodo e (come implica correttamente la tua domanda) se la lingua è simile a una o più lingue che già conoscono, potrebbero essere in grado di seguire il flusso del programma di base e potenzialmente rilevare errori logici.
Tuttavia, non è possibile che questo tipo di recensione sia mai "valida" o "equivalente a" recensione di sviluppatori che conoscono effettivamente la lingua che stai utilizzando. In sostanza, questo è perché fare una lingua sguardo come un altro in genere nascondono sottili differenze, pur facendo una lingua si comportano come un altro (in particolare nel caso di C ++ e Java) possono essere un-idiomatica della lingua e / o potrebbe essere ancora troppo confuso per i recensori.
Innanzitutto, pensiamo a cosa significherebbe far sembrare Java "C ++". Come semplice caso, puoi usare new
per creare un'istanza di oggetti, proprio come in Java:
Foo foo = new Foo();
Ma gli oggetti istanziati in questo modo usano ->
invece di .
chiamare i metodi, quindi se vuoi che le chiamate ai metodi appaiano come Java, devi invece scrivere:
Foo& foo = *new Foo();
Ma questo non è idiomatico; in particolare, la memoria deve essere successivamente ripulita utilizzando delete &foo
, che alcuni sviluppatori C ++ esperti potrebbero non realizzare nemmeno un codice legale . In entrambi i casi, ci sono divertenti simboli non-Java-like sparse in tutto, in modo che non può abbastanza rendere il linguaggio "assomigliare" Java. (Potresti eliminare *new
usando #define New *new
, o, peggio, #define new *new
ma poi stai solo chiedendo ai tuoi colleghi sviluppatori di odiarti.) E, come detto sopra, delete
non esiste in Java, quindi in ogni caso (come menzionato in un'altra risposta ) non puoi mai far "sembrare" l'utilizzo degli oggetti come in Java senza perdite di memoria.
Ma il moderno C ++ include puntatori condivisi intelligenti, che si comportano in modo molto simile ai riferimenti variabili gestiti dalla memoria di Java. Quindi ovunque in Java che potresti scrivere Foo foo = new Foo();
, puoi invece scrivere:
std::shared_ptr<Foo> foo = std::make_shared<Foo>();
Ora stai usando una funzionalità linguistica che in realtà è molto simile a quella di Java. Ma improvvisamente hai molto da spiegare ai revisori non C ++: che cos'è questa shared_ptr
roba? Quali sono i "trucchi" delicati e delicati make_shared
? (Utilizza l'inoltro perfetto, che presenta alcuni casi di errore e può portare alla chiamata del costruttore "sbagliato".) Perché i metodi devono essere chiamati con ->
, ma l'utilizzo .
con alcuni metodi è consentito dal compilatore? ( shared_ptr
ha i propri metodi.) Se il metodo Foo::reset(void)
esiste, uno sviluppatore inconsapevole potrebbe provare a chiamarlo con il foo.reset()
quale (se c'è solo un puntatore condiviso che punta a quell'istanza di Foo
quando si verifica la chiamata) eliminerà la memoria sottostante e annullerà foo
, e È probabile che gli sviluppatori Java non rilevino questo problema.
Inoltre, C ++ ha un sacco di insidie che sono specifici per la lingua. Come meglio posso dire, la maggior parte degli sviluppatori di C ++ impara a gestire queste insidie sviluppando gradualmente il proprio linguaggio per pratiche "sicure" in C ++, che è spesso in qualche modo unico per loro o per il loro team di sviluppo (vedere ad esempio la risposta esistente che menziona il Le pratiche di codifica di Google e il commento su di esso affermano che "I veterani C ++ stagionati di solito rifiutano le linee guida di codifica di Google"). Tutte le affermazioni secondo cui il linguaggio potrebbe essere troppo complicato, a quanto pare (almeno nella mia esperienza), in genere si incontrano alcune variazioni di "beh, smetti di usarlo nel modo sbagliato". Mi rendo conto che questa è una visione fortemente negativa della comunità di ++ C, e ci sono certamente sviluppatori esperti più disposti a dare una mano lingua-studenti, ma non lo fa sembra essere una certa capacità difensiva ad esempio su comportamenti indefiniti (vedi ad esempio gran parte della discussione nel mio link "insidie" sopra).
Gli sviluppatori Java semplicemente non saranno utili per trovare e correggere queste insidie tramite la revisione del codice.
Un giorno ti potrebbe essere chiesto di convertire il codice in Java.
È del tutto valido - lodevole, persino - provare a tenere conto di ciò che potrebbe accadere al tuo codice in futuro mentre sei in fase di progettazione.
Ma, in primo luogo, questa particolare considerazione sembra una possibilità remota: il codice è in genere o riutilizzato così com'è (ad esempio è possibile collegare parte o tutto il codice C ++ funzionante in un futuro software Java utilizzando un'interfaccia JNI) o riscritto del tutto piuttosto che direttamente "trascritto" manualmente.
E, in secondo luogo, in seguito dici:
Ogni caratteristica specifica del linguaggio C ++ (ad esempio: ereditarietà multipla) dovrebbe avere alternative da implementare in Java ....
Questo essenzialmente annulla il punto "converti in Java". Se il software è scritto in C ++ idiomatico e quindi convertito in Java idiomatico, non c'è motivo di aspettarsi che questa conversione sarebbe (o potrebbe!) Essere eseguita applicando un mapping uno-a-uno preciso delle funzionalità C ++ alle funzionalità Java.
Il codice senza funzionalità specifiche C ++ è generalmente più gestibile.
Non è chiaro cosa intendi qui, ma in realtà sono in qualche modo d'accordo con una parte di questo: a meno che tu non sia molto attento e anche quando stai attento, le funzionalità C ++ possono portare a problemi di manutenibilità. Il C ++ FQA Lite (un sito Web critico nei confronti del linguaggio e dei suoi aderenti da parte di qualcuno che almeno sembra effettivamente capirlo abbastanza bene) afferma che
... L'80% degli sviluppatori comprende al massimo il 20% della lingua. Non è lo stesso 20% per persone diverse, quindi non contare su di loro per capire il codice reciproco.
NOTA BENE: se sei un fan del C ++ e arrivi a questo punto nella mia risposta e ti senti propenso a saltare ai commenti per sostenere che l'autore del FQA in realtà non capisce il C ++ o è disonesto nella maggior parte dei suoi argomenti , nota che (1) esattamente due frasi dopo averlo citato, riconosco che la FQA è una fonte molto distorta, e (2) non ha importanza per quello che sto cercando di dire se l'autore della FQA capisce o meno C ++ e non sto provando a bash su C ++ e dovresti leggere il resto del post senza dare per scontato che sono anti-C ++ solo perché ho citato l'FQA. Fine della nota
Allo stesso modo, Linus Torvalds odia il C ++ essenzialmente per questo motivo (attenzione: il collegamento implica molte imprecazioni, in vero stile Linus).
Ovviamente, si tratta di considerazioni molto distorte sulla questione, ma anche i sostenitori del C ++ spesso dicono che non dovresti usare l'intero set di funzionalità del linguaggio (ancora una volta, vedi le linee guida per la codifica di Google; inoltre, Bjarne Stroustrup, il creatore di C ++ , ha dichiarato pubblicamente, "All'interno del C ++, c'è un linguaggio molto più piccolo e più pulito che lotta per uscire").
Quindi penso che ci sia un certo merito all'idea che le funzionalità C ++ potrebbero essere troppo facili da usare in modo improprio, specialmente se si proviene da uno sfondo Java. Inoltre, c'è il merito all'idea di alleviare questi problemi limitandoti ad alcuni sottogruppi della lingua.
Tuttavia, decidere quale sottoinsieme utilizzare in base a un linguaggio diverso non sembra l'approccio giusto, a meno che il "linguaggio diverso" sia C, poiché esiste davvero un sottoinsieme simile al C del linguaggio C ++. (Linus si riferisce a questo nel suo rant sopra, e Scott Meyers si riferisce persino a questo sottoinsieme come un "sotto-linguaggio"). Il paradigma di runtime di Java (raccolta dei rifiuti, in esecuzione su una macchina virtuale) è così sostanzialmente diverso da quello di C ++ che è non è chiaro che ci siano utili lezioni da trarre sull'uso del C ++ da esso, e come notato sopra, provare a trarre lezioni sul C ++ direttamente da Java può portare a un codice molto non idiomatico.
Invece, prova a definire il tuo "sottoinsieme accettabile" della lingua sulla comprensione di come la lingua può essere utilizzata in modo idiomatico. Se si desidera un sottoinsieme abbastanza restrittivo che sfrutta ancora molte delle funzionalità di C ++ oltre a ciò che offre C, la linea guida di codifica di Google di cui sopra potrebbe essere un buon punto di partenza. Certo, otterrai sviluppatori che affermano che "non c'è alcun argomento razionale" per alcune delle restrizioni di Google , ma a meno che tu non stia cercando di assumere Alexandrescu lontano dal suo lavoro sul linguaggio D (che a sua volta dovrebbe dirti qualcosa), questo è probabilmente va bene. È sicuramente meglio che provare a trasformare C ++ in Java.
Un altro buon punto di partenza per una serie di linee guida sul codice è il nuovo C ++ Core Guidelines , un work-in-progress di Bjarne Stroustrup e Herb Sutter.
L'unico altro modo per affrontare le carenze del C ++ è scegliere una lingua diversa. Sembra che tu ti piaccia Java e pensi che alla fine questo progetto possa essere convertito in Java. Come notato in un'altra risposta, potresti semplicemente ... iniziare con Java.
Ci sono due motivi per cui potresti davvero dover usare qualcosa di diverso da Java:
- Hai davvero bisogno delle prestazioni di runtime. In questo caso, trattare C ++ come se fosse Java probabilmente non ti aiuterà, perché tecniche simili a Java come i puntatori condivisi peggiorano le prestazioni di runtime.
- È necessario che il software funzioni su una piattaforma oscura che non supporta ancora JVM. In questo caso, probabilmente sei bloccato con le lingue che hanno frontend GCC o Clang. C e C ++ sono candidati ovvi, ma potresti anche esaminare qualcosa come Rust. (Quick plug: non ho usato Rust in modo estensivo, ma sembra fantastico e sono ansioso di lavorare su un grande progetto Rust appena posso, e penso che tutti coloro che stanno prendendo in considerazione l'avvio di un progetto C ++ dovrebbero considerare Rust come alternativa.)
Ogni caratteristica specifica del linguaggio C ++ (ad esempio: ereditarietà multipla) dovrebbe avere alternative da implementare in Java. In caso contrario, ciò significa che il modello di progettazione o l'architettura del codice è problematico.
L'ho già affrontato in qualche modo, ma ho intenzionalmente escluso la tua seconda frase.
Non sono convinto che qualcosa del genere constexpr
, che non avrebbe alcun senso in un linguaggio parzialmente JIT come Java, sia un'indicazione di architettura non valida. Sono più aperto all'idea che un uso eccessivo della meta-programmazione dei template potrebbe essere più un problema di quanto non valga la pena, specialmente ora che constexpr
esiste per fare la valutazione delle funzioni in fase di compilazione, ma è chiaro dal caso constexpr
che non ci sono difetti di progettazione se si lo stai usando: stai semplicemente assicurando che alcuni calcoli si verifichino anche prima di eseguire il codice, il che è un incredibile miglioramento delle prestazioni (vedi ad esempio questa voce per il problema n-body di The Benchmark Game , che supera ogni altra voce tranne un'altra scritto in C ++,