W innych odpowiedziach jest już kilka dobrych punktów, ale chciałbym udzielić bardziej kompletnej odpowiedzi, odpowiadając indywidualnie na pytania i wypowiedzi.
Jeśli Java nie udostępnia funkcji, którą posiada C ++, oznacza to, że ta funkcja nie jest dobra, dlatego powinniśmy jej unikać.
Odpowiedzi na to dość dobrze: Java nie jest „dobrą częścią” C ++, ani nie ma powodu, aby tak sądzić.
W szczególności, chociaż zalety każdej indywidualnej funkcji C ++ są dyskusyjne, wiele funkcji C ++ 11 / C ++ 14, które nie są częścią Javy, niekoniecznie jest wykluczonych, ponieważ projektanci Javy uznali, że to zły pomysł. Przykładowo, do wersji 8 Java nie miała lambd, ale zostały wprowadzone do C ++ w standardzie C ++ 11. Przed wersją Java 8 twoje założenie, że brakuje funkcji C ++ w Javie z założenia, ponieważ „nie są one dobre”, sugerowałoby, że lambdy jako funkcje językowe są „nie dobre” (ku przerażeniu LISPerów na całym świecie, chociaż są prawdopodobnie wystarczająco przerażony, by usłyszeć, że podobno naprawdę lubisz Javę). Ale teraz projektanci Java umieścili swój znaczek zatwierdzenia (TM) na lambdas, więc teraz są dobrą rzeczą.
Aby zagłębić się nieco głębiej, nawet w Javie 8, lambdas-as-closures nie są tak elastyczne jak lambd C ++ 14, ale może to wynikać raczej z ograniczeń architektury JVM niż świadomej decyzji, że bardziej elastyczne podejście jest złe perspektywa projektowania języka.
Kod C ++ z funkcjami specyficznymi dla C ++ (np. Funkcje znajomych, wielokrotne dziedziczenie) może być utrzymywany lub sprawdzany tylko przez programistów C ++, ale jeśli po prostu piszemy C ++ jak Java (bez funkcji specyficznej dla języka C ++), kod może być utrzymywany lub sprawdzany przez oba Programiści C ++ i Java.
To jest główna rzecz, na którą chciałem odpowiedzieć.
Ogólnie rzecz biorąc, uzyskiwanie recenzji kodu od programistów, którzy nie są w pełni zaznajomieni z używanym językiem, może mieć pewną wartość. Mogą udzielać cennych informacji zwrotnych na temat przejrzystości nazw i komentarzy funkcji / metod oraz (jak prawidłowo sugeruje twoje pytanie), jeśli język jest podobny do jednego lub więcej języków, które już znają, mogą być w stanie śledzić podstawowy przebieg programu i potencjalnie wyłapać błędy logiczne.
Jednak to nie przypadek, że tego rodzaju przeglądu nigdy nie będzie „tak dobre jak” lub „równoważne” test z programistów, którzy rzeczywiście znają język, którego używasz. Zasadniczo dzieje się tak dlatego, że sprawienie, by jeden język wyglądał jak inny, zwykle ukrywa subtelne różnice, podczas gdy sprawienie, aby jeden język zachowywał się tak, jak inny (szczególnie w przypadku C ++ i Java), może być nie-idiomatyczny dla języka i / lub może być zbyt mylący dla recenzentów.
Najpierw zastanówmy się, co to znaczy, że C ++ „wygląda jak” Java. W prostym przypadku możesz użyć new
do tworzenia instancji obiektów, tak jak w Javie:
Foo foo = new Foo();
Ale obiekty instancja ten sposób wykorzystania ->
zamiast .
do wywołania metody, więc jeśli chcesz metoda nazywa się wyglądać jak Java, należy zamiast pisać:
Foo& foo = *new Foo();
Ale to nie jest idiomatyczne; w szczególności pamięć musi zostać później wyczyszczona za pomocą delete &foo
, czego niektórzy doświadczeni deweloperzy C ++ mogą nawet nie zdawać sobie sprawy, że jest to legalny kod . Tak czy inaczej, są śmieszne symbole non-Java-jak posypane przez cały czas, więc nie możemy dość uczynić język „wyglądać” Java. (Możesz wyeliminować, *new
używając #define New *new
, lub, co gorsza, #define new *new
ale wtedy prosisz innych programistów, żeby cię nienawidzili.) I, jak wspomniano powyżej, delete
nie istnieje w Javie, więc w każdym razie (jak wspomniano w innej odpowiedzi ), tak naprawdę nigdy nie można sprawić, aby użycie obiektu „wyglądało” tak jak w Javie bez wycieków pamięci.
Ale współczesne C ++ zawiera inteligentne wskaźniki wspólne, które zachowują się podobnie do zarządzanych pamięci Java zmiennych. Wszędzie w Javie, gdzie można pisać Foo foo = new Foo();
, można zamiast tego napisać:
std::shared_ptr<Foo> foo = std::make_shared<Foo>();
Teraz używasz funkcji językowej, która w rzeczywistości przypomina Java pod maską. Ale nagle masz wiele do wyjaśnienia recenzentom spoza C ++: co to jest shared_ptr
? Jakie są subtelne, skomplikowane „gotchas” make_shared
? (Wykorzystuje doskonałe przekazywanie, które ma pewne przypadki awarii i może prowadzić do wywołania „niewłaściwego” konstruktora.) Dlaczego metody muszą być wywoływane za pomocą ->
, ale .
kompilator zezwala na używanie z niektórymi metodami? ( shared_ptr
ma swoje własne metody.) Jeśli metoda Foo::reset(void)
istnieje, nieostrożny programista może spróbować ją wywołać foo.reset()
, co (jeśli istnieje tylko jeden wspólny wskaźnik wskazujący na to wystąpienie Foo
momentu wywołania) spowoduje usunięcie pamięci podstawowej i unieważnienie foo
, oraz Deweloperzy Java raczej nie złapią tego problemu.
Ponadto, C ++ ma wiele z pułapek , które są specyficzne dla języka. Jak mogę najlepiej powiedzieć, większość programistów C ++ uczy się radzić sobie z tymi pułapkami, stopniowo rozwijając swój własny idiom dotyczący „bezpiecznych” praktyk C ++, co często jest w pewnym stopniu unikalne dla nich lub dla ich zespołu programistów (patrz na przykład istniejąca odpowiedź, która wspomina Praktyki kodowania Google i komentarz na ten temat, że „doświadczeni weterani C ++ zwykle odrzucają wytyczne Google dotyczące kodowania”). Wszystkie twierdzenia, że język może być zbyt skomplikowany, jak się wydaje (przynajmniej z mojego doświadczenia), zazwyczaj spotykają się z pewną odmianą „no cóż, przestań go źle używać”. Zdaję sobie sprawę, że jest to bardzo negatywny pogląd na społeczność C ++, a na pewno są doświadczeni programiści chętniej pomagający uczącym się języków, ale tak jest wydają się być pewną obroną przed np. niezdefiniowanym zachowaniem (patrz na przykład większość dyskusji w moim linku „pułapki” powyżej).
Programiści Java po prostu nie będą pomocni w znajdowaniu i korygowaniu tych pułapek poprzez przegląd kodu.
Możesz zostać poproszony o konwersję kodu na Javę.
Jest to całkowicie poprawne - godne pochwały, nawet - próba uwzględnienia tego, co może się stać z twoim kodem w przyszłości, gdy będziesz w fazie projektowania.
Ale po pierwsze, ta szczególna uwaga wydaje się być zdalną możliwością: kod jest zwykle albo ponownie używany, jak jest (na przykład możesz podłączyć część lub całość działającego kodu C ++ do jakiegoś przyszłego oprogramowania Java za pomocą interfejsu JNI) lub przepisać całkowicie niż bezpośrednio „transkrybowane”.
Po drugie, później powiesz:
Każda funkcja specyficzna dla języka C ++ (np. Wielokrotne dziedziczenie) powinna mieć alternatywy do zaimplementowania w Javie ....
To zasadniczo anuluje punkt „konwersji na Javę”. Jeśli oprogramowanie jest napisane w idiomatic C ++, a następnie przekonwertowane na idiomatic Java, nie ma powodu oczekiwać, że ta konwersja zostanie (lub mogłaby!) Zostać wykonana poprzez zastosowanie dokładnego odwzorowania funkcji C ++ w stosunku do funkcji Java.
Kod bez funkcji specyficznych dla C ++ jest zwykle łatwiejszy w utrzymaniu.
Nie jest jasne, co masz na myśli, ale w pewnym stopniu zgadzam się z częścią tego: chyba że jesteś bardzo ostrożny, a nawet jeśli jesteś ostrożny, funkcje C ++ mogą prowadzić do problemów z utrzymaniem. C ++ FQA Lite (strona krytycznie o języku i jego zwolenników od kogoś, kto przynajmniej wydaje się właściwie zrozumieć to dość dobrze) stwierdza, że
... 80% programistów rozumie najwyżej 20% języka. To nie to samo 20% dla różnych osób, więc nie licz na to, że zrozumieją nawzajem swój kod.
UWAGA: Jeśli jesteś fanem C ++ i przejdziesz do tego punktu w mojej odpowiedzi i masz ochotę zeskoczyć do komentarzy, aby argumentować, że autor FQA tak naprawdę nie rozumie C ++ lub jest nieuczciwy w większości swoich argumentów , zauważ, że (1) dokładnie dwa zdania po zacytowaniu go potwierdzam, że FQA jest bardzo stronniczym źródłem i (2) tak naprawdę nie ma znaczenia, co próbuję powiedzieć, czy autor FQA rozumie C ++ , i nie próbuję obalić C ++, i powinieneś przeczytać resztę postu, nie zakładając, że jestem anty-C ++ tylko dlatego, że zacytowałem FQA. Koniec noty.
Podobnie, Linus Torvalds nienawidzi C ++ zasadniczo z tego powodu (ostrzeżenie: link zawiera wiele przekleństw, w prawdziwie niesławnym stylu Linusa).
Oczywiście są to bardzo stronnicze podejście do tej kwestii, ale nawet zwolennicy C ++ często twierdzą, że nie powinieneś używać całego zestawu funkcji językowych (ponownie, przeczytaj wytyczne Google dotyczące kodowania; także Bjarne Stroustrup, twórca C ++ , publicznie stwierdził: „W C ++ istnieje dużo mniejszy i bardziej przejrzysty język, który próbuje się wydostać”).
Sądzę więc, że istnieje pewna zaleta, że funkcje C ++ mogą być zbyt łatwe do niewłaściwego użycia, szczególnie jeśli pochodzisz z języka Java. Ponadto warto zaspokoić te problemy, ograniczając się do niektórych podzbiorów języka.
Jednak decydowanie o tym, który podzbiór ma być użyty w oparciu o inny język, nie wydaje się właściwym podejściem, chyba że „innym językiem” jest C, ponieważ tak naprawdę istnieje podzbiór C języka podobnego do C. (Linus odnosi się do tego w powyższym rantzie, a Scott Meyers nawet odnosi się do tego podzbioru jako „podjęzyka”). Paradygmat czasu wykonywania Javy (odśmiecanie, uruchamianie na maszynie wirtualnej) jest tak zasadniczo odmienny od C ++, że jest to nie jest jasne, że istnieją użyteczne lekcje na temat korzystania z C ++, a jak wspomniano powyżej, próba wyciągnięcia lekcji na temat C ++ bezpośrednio z Javy może prowadzić do bardzo nieidiomatycznego kodu.
Zamiast tego spróbuj zdefiniować „akceptowalny podzbiór” języka, rozumiejąc, jak można go używać idiomatycznie. Jeśli chcesz dość restrykcyjnego podzbioru, który nadal korzysta z wielu funkcji C ++ wykraczających poza to, co oferuje C, wspomniane wyżej wytyczne Google Coding mogą być dobrym miejscem na rozpoczęcie. Jasne, dostaniesz programistów, którzy twierdzą, że nie ma „żadnego racjonalnego argumentu” dla niektórych ograniczeń Google , ale jeśli nie chcesz zatrudnić Alexandrescu z dala od jego pracy nad językiem D (który sam powinien ci coś powiedzieć), to jest to prawdopodobnie dobrze. Jest to z pewnością lepsze niż próba przekształcenia C ++ w Javę.
Innym dobrym punktem wyjścia dla zestawu wytycznych dla kodu są nowe Wytyczne dla C ++ , będące w trakcie opracowywania przez Bjarne Stroustrup i Herb Sutter.
Jedynym innym sposobem radzenia sobie z niedociągnięciami C ++ jest wybór innego języka. Wygląda na to, że lubisz Javę i uważasz, że istnieje szansa, że ten projekt zostanie ostatecznie przekształcony w Javę. Jak zauważono w innej odpowiedzi, możesz po prostu ... zacząć od Javy.
Są dwa powody, dla których naprawdę możesz potrzebować czegoś innego niż Java:
- Naprawdę potrzebujesz wydajności w czasie wykonywania. W takim przypadku traktowanie C ++ tak, jakby to była Java, prawdopodobnie nie pomoże, ponieważ techniki podobne do Java, takie jak wskaźniki współdzielone, obniżają wydajność w czasie wykonywania.
- Potrzebujesz oprogramowania do pracy na niejasnej platformie, która nie obsługuje jeszcze JVM. W tym przypadku prawdopodobnie utknąłeś w językach, które mają nakładki GCC lub Clang. C i C ++ są oczywistymi kandydatami, ale możesz także spojrzeć na coś takiego jak Rust. (Szybka wtyczka: nie używałem zbyt często Rust, ale wygląda niesamowicie i chętnie pracuję nad dużym projektem Rust jak najszybciej, i myślę, że każdy rozważający rozpoczęcie projektu C ++ powinien rozważyć Rust jako alternatywę.)
Każda funkcja specyficzna dla języka C ++ (np. Wielokrotne dziedziczenie) powinna mieć alternatywy do zaimplementowania w Javie. Jeśli nie, oznacza to, że wzór lub architektura kodu jest problematyczna.
Już trochę to rozwiązałem, ale celowo pominąłem twoje drugie zdanie.
Nie jestem przekonany, że coś takiego constexpr
, co nie miałoby sensu w języku częściowo JIT, takim jak Java, wskazuje na nieprawidłową architekturę. Jestem bardziej otwarty na pomysł, że nadmierne korzystanie z meta-programowania szablonów może być większym problemem niż jest to warte, szczególnie teraz, gdy constexpr
istnieje do przeprowadzania oceny funkcji czasu kompilacji, ale wynika z tego, constexpr
że nie ma wady projektowej, jeśli używam go: po prostu upewniasz się, że niektóre obliczenia występują nawet przed uruchomieniem kodu, co jest niesamowitym wzrostem wydajności (zobacz na przykład ten wpis dotyczący problemu n-body w grze Benchmark Game , który przewyższa każdy inny wpis z wyjątkiem innego napisany w C ++,