Czy powinniśmy unikać funkcji językowych, które ma C ++, ale Java nie?

110

Załóżmy, że jestem ograniczony do używania C ++ przez środowisko w projekcie. Czy dobrze jest zapobiegać korzystaniu z niektórych funkcji językowych, które ma C ++, ale Java nie ma (np .: wielokrotne dziedziczenie, przeciążenie operatora)?

Myślę, że powodem są:

  1. Ponieważ Java jest nowsza niż C ++, jeśli Java nie udostępnia funkcji, którą posiada C ++, oznacza to, że ta funkcja nie jest dobra, dlatego powinniśmy jej unikać.
  2. 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.
  3. Możesz zostać poproszony o konwersję kodu na Javę
  4. Kod bez funkcji specyficznych dla C ++ jest zwykle łatwiejszy w utrzymaniu
  5. 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.

Czy to prawda?

grgrr
źródło
7
Jeśli spojrzysz na swoje sugestie, mówisz o stworzeniu standardu kodowania. Fakt, że tworzysz i przestrzegasz standardu, w rzeczywistości zwiększy łatwość konserwacji.
Brandin
63
Czy kod Java powinien być również ograniczony do funkcji, które można również znaleźć w języku C ++? Więc nie używaj na przykład Java volatile, dostępu członków klasy prywatnej pakietu, refleksji / introspekcji, wreszcie bloków, sprawdzonych wyjątków i tak dalej? Całe to pytanie nie ma większego sensu ... C ++ i Java są powierzchownie podobne, ale ostatecznie bardzo różne języki.
hyde
5
Jak ewoluują języki, jeśli ludzie nie chcą korzystać z nowych funkcji? Nowe funkcje mają ułatwić ci życie, rozwiązując typowe problemy. Jeśli użytkownicy nie korzystają z nowych funkcji, nikt nie ma motywacji do ich wdrożenia.
Matthew
72
Jeśli chcesz Java, użyj Java. Jeśli używasz C ++, użyj C ++, a nie jakiejś okropnej, pokręconej imitacji Java ze składnią C ++. Korzystanie z C ++, ale ograniczenie się do zestawu funkcji Javy daje najgorsze z obu światów.
Jerry Coffin
11
Zdziwiłbyś się, jak szybko ugryzą cię różnice (i mocno ). SomeObject a = previousObject;robi bardzo różne rzeczy w Javie i C ++. W Javie kopiuje odwołanie, podczas gdy w C ++ kopiuje obiekt. W Javie modyfikacje awpłynęłyby również na poprzedni obiekt. W C ++ masz dwa oddzielne obiekty.
Clockwork-Muse

Odpowiedzi:

307

Nie. Jest to żałośnie i strasznie wprowadzane w błąd.

  • Funkcje Java nie są w żaden sposób lepsze niż funkcje C ++, szczególnie w próżni.
  • Jeśli programiści nie wiedzą, jak korzystać z funkcji, szkolić lub zatrudniać lepszych programistów; ograniczenie programistów do najgorszego zespołu to szybki i łatwy sposób na utratę dobrych programistów.
  • YAGNI . Rozwiąż swój dzisiejszy problem, a nie ducha jakiegoś przyszłego problemu.
Telastyn
źródło
6
Niedawno pojawiło się pytanie o programistów przeglądających kod w języku, którego zwykle nie piszą. Myślę, że mądrość ma tutaj zastosowanie: dobry programista dostrzeże wiele podstawowych błędów w prawie każdym języku, ale każdy język ma tak wiele gotchy, że maksymalna korzyść zostanie osiągnięta, gdy programiści w języku dokonają przeglądu. Jest to nawet prawdą, jeśli Twój C ++ to „Tylko funkcje Java”.
corsiKa
5
+1 Oprócz twojego drugiego punktu. OP powinien poświęcić trochę czasu na przeczytanie „Najlepszych praktyk w C ++”, aby zdecydować, których funkcji powinny użyć. Moje ostatnie informacje o C ++ są takie, że funkcje przyjaciela i wielokrotne dziedziczenie są uważane za złe praktyki . Rzeczy takie jak szablony i przeciążanie operatora są dobrymi praktykami IMHO, jeśli używasz ich mądrze.
some_coder
4
@some_coder: Wszystko zależy od tego, kiedy i gdzie. Kiedy wykonuję programowanie oparte na zasadach, dziedziczę (prawdopodobnie wiele) klas zasad, aby rozszerzyć strukturę mojej klasy hosta o członków, których te klasy zasad wymagają do działania. Tak to działa. Ponadto, operator<<( ostream &, T const & )jest zazwyczaj realizowane za pośrednictwem friend. Taki jest problem z ogólnymi stwierdzeniami o tym, co jest dobrym językiem, a co złym: są dobrą radą, z wyjątkiem sytuacji, gdy nie są ...
DevSolar 29.01.16
142

To, że na pierwszy rzut oka wydaje się podobna składnia, nie oznacza, że ​​oba języki są kompatybilne.

1, 4 i 5 to tak naprawdę to samo pytanie:

Teraz nie jestem fanem C ++, ale powiedzenie „Kod bez specyficznych funkcji C ++ jest zwykle łatwiejszy w utrzymaniu” jest po prostu śmieszne - czy naprawdę wierzysz, że Java ma wszystko dobrze i wziął wszystkie dobre cechy, ignorując wszystkie złe? Czy naprawdę wierzysz, że istnieje coś, co jest uniwersalną cechą „złą” lub „dobrą”? Jeśli tak, to dlaczego nie mamy jednego języka, który jest czysto dobry? I nie, Java z pewnością nie jest tym językiem. Czy to oznacza, że ​​Java i C ++ są bezużyteczne? Oczywiście nie.

Co się stanie, jeśli Twoi liderzy zdecydują się na przeniesienie do C #, a nie Java? C # nie tylko obsługuje nadpisywanie operatorów, ale jest także domyślny - jeśli chcesz, aby ludzie używali np. obj.Equals(obj2)Zamiast obj == obj2, ludzie będą popełniać błędy przez cały czas. Nawet jeśli trzymasz się tylko wspólnych cech tych dwóch języków, są inne oczekiwania , inna kultura. Jeśli zrobisz coś if (myField == null)w C ++, ludzie zobaczą, że jesteś nowicjuszem. Jeśli używasz if (null == myField)w C #, ludzie zobaczą, że tak naprawdę nie jesteś jeszcze natywny w C # - powody, dla których programiści C nauczyli się korzystać z wariantu „odwróconego”, nie istnieją już w C #.

Korzystając z Twojej logiki, powinniśmy utknąć w kodzie maszynowym lub asemblerze, lub w języku COBOL, ponieważ dlaczego kiedykolwiek miałbyś zmienić się na coś takiego jak Pascal, gdy tylko dodaje on nowe funkcje, których Twoi programiści będą musieli się nauczyć? Dlaczego mielibyśmy używać czegoś takiego jak SQL, skoro nie ma nawet pętli ? Dlaczego mielibyśmy używać czegoś innego niż SQL, skoro SQL nie ma pętli, a X ma?

Kod C ++ z pewnością nie może być utrzymywany przez programistów Java. Nie rozumiem, skąd wziął się ten pomysł - co dokładnie pozostaje, gdy ograniczysz C ++ do funkcji, które działają dokładnie tak samo jak w Javie? Nie dostaniesz nawet wywołań metod - nawet wywołań funkcji . Ponownie, tylko dlatego, że obie języki używają nawiasów klamrowych, nie oznacza, że ​​języki są w żaden sposób zamienne.

Konwersja kodu C ++ podobnego do języka Java będzie bardzo podatna na błędy bez względu na to, co robisz. Jest po prostu zbyt wiele różnic. Jeśli zależy ci na przepisaniu aplikacji w innym języku, pomyśl o rozsądnych sposobach modularyzacji wszystkiego, abyś mógł wymienić części bez zepsucia całości. Ale w końcu YAGNI - bez względu na to, co robisz, przygotowanie kodu do konwersji na Javę będzie wiązało się ze znacznymi kosztami. To czas, który najprawdopodobniej lepiej spędzić na dodawaniu lub ulepszaniu swoich funkcji.

Używamy różnych języków, ponieważ dają nam inny zestaw narzędzi do rozwiązywania problemów. Jeśli potrzebujesz plików wykonywalnych, które działają „wszędzie”, skorzystaj z Java. Jeśli potrzebujesz kodu, który kompiluje się „wszędzie”, C ++ działa dobrze. Jeśli chcesz kodu łatwego do zrozumienia i przeanalizowania, skorzystaj z LISP lub cokolwiek innego. Ale mogę ci powiedzieć jedno - pisanie kodu w jednym języku tak, jakbyś pisał go w innym, jest zawsze błędem i będziesz cierpieć. Nie wspominając już o tym, że kiedy faktycznie zatrudnisz faceta w C ++, on uruchomi sekundę, kiedy zobaczy kod „kompatybilny z Javą”. I ... facet z Javy zrobi to samo. Wiesz, nawet „znając” zarówno C ++, jak i Javę, bym działał jak diabli :)

Właściwie musiałem pracować nad (zwykłym) kodem C napisanym przez programistę Pascal, który wydawał się myśleć tak jak ty. Użył #defines, aby przedefiniować C, aby wyglądać bardziej jak Pascal, wraz z takimi rzeczami, jak „POCZĄTEK przekłada się na {”. Rezultat był raczej przewidywalny - kod, którego ani C, ani programiści Pascal nie mogą zrozumieć, i pełen błędów, które były wynikiem przeciekającej „abstrakcji” Pascala nad C. A Pascal i C są prawie identyczne z dzisiejszego punktu widzenia. Nawet przejście na C <-> C ++ jest znacznie bardziej zróżnicowane, a to wciąż orzeszki dla czegoś takiego jak C ++ <-> Java.

Luaan
źródło
9
„Jeśli chcesz kodu łatwego do zrozumienia i analizy, skorzystaj z LISP lub cokolwiek innego.” Nie zgodziłbym się z tym. Lisp jest trywialny do przeanalizowania, ale właśnie z tego powodu - ponieważ został stworzony w czasach, gdy wiedza o parserach i zasadach ich skutecznego budowania była jeszcze w powijakach, więc obijali się i szli za najbardziej absurdalnie uproszczoną rzeczą które mogłyby zadziałać - nie masz wielu korzyści składniowych współczesnych języków. Jest więc łatwy do przeanalizowania, ale wcale nie jest łatwy do zrozumienia . Jest powód, dla którego ludzie nazywają to „Zagubionymi w zbędnych nawiasach”.
Mason Wheeler,
9
@MasonWheeler To kwestia gustu - programiści C tak to nazwali, a nie LISPers: P. Policz nawiasy - jest ich tyle, ile w typowym programie C ++. Prawdziwą różnicą jest ich pozycja (w myFunc()porównaniu (myFunc)), i to ma bardzo dobry powód. Języki oparte na LISP są nadal bardzo popularne, szczególnie wśród ludzi matematyki / fizyki. Najważniejsze jest to, że języki LISPy są bardzo nieznane współczesnym programistom w stylu C - ale to nie jest powód, aby je ignorować. Schemat, Clojure oraz w pewnym stopniu języki oparte na ML (OCaml, F # ...) są naprawdę bardzo LISPy.
Luaan
4
@Luaan Mogę powiedzieć z całą pewnością, że LISP NIE jest popularny w fizyce. Dwa dominujące języki w tej dziedzinie to FORTRAN i C ++. FORTRAN jest „popularny”, ponieważ napisano w nim tyle starych kodów, ale prawie wszystkie nowe programy są napisane w C ++. Jako fizyk badawczy nie spotkałem ani nawet nie słyszałem o programie LISP. Nie mówiąc już, że nie istnieją, ale języki zdecydowanie nie są popularne .
James Matta
4
@Luaan Możemy potrzebować więcej programistów. Zdecydowanie nie potrzebujemy więcej absolwentów CS. To tak, jakby powiedzieć „potrzebujemy więcej inżynierów budownictwa, więc potrzebujemy więcej absolwentów fizyki teoretycznej”.
Miles Rout
4
@ user1717828 Ma to na celu uniknięcie zachwycających efektów błędnego wpisania if (myField == null)jako if (myField = null), który skompiluje dobrze C / C ++, ale prawdopodobnie nie zrobi tego, co zamierzałeś. Z drugiej strony if (null = myField)wyrzuci błąd, ponieważ nie można przypisać stałej.
Wlerin
94

Odpowiem na twoje pytania po kolei.

  1. Jeśli Java nie udostępnia funkcji, którą posiada C ++, oznacza to, że ta funkcja nie jest dobra, dlatego powinniśmy jej unikać.

Tak, każda funkcja nieobecna w Javie jest przekleństwem na dysku twardym. Musi zostać wypalony z bazy kodu. Ci, którzy nie będą posłuszni, będą prześladowani, a ich dusze będą wykorzystywane do uspokajania bogów RAID.

  1. 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.

W razie wątpliwości napisz kod dla najmniej kompetentnego członka zespołu. Kod jest odczytywany znacznie częściej niż jest napisany, a kod, który jest tak sprytny, jak potrafisz pisać, jest zbyt sprytny, aby go czytać. Recenzje kodu, których nie rozumieją pracownicy recepcji, należy odrzucić. Aby pomóc, naucz ich programowania w języku Visual Basic 2.0 przez weekend, a następnie naśladuj styl kodowania w dowolnym języku, którego używasz.

  1. Możesz zostać poproszony o konwersję kodu na Javę

Prawdziwe! Ale po co zatrzymywać się na Javie? Możesz zostać poproszony o konwersję kodu na podstawowy, asembler i / lub perl jeden dzień. Ponieważ istnieją interpretery Perla w każdym języku, po prostu napisz swój program jako długi ciąg perla i wgraj w niego argumenty w wybranym języku.

Teraz, gdy musisz zmienić język, po prostu przepisz kod zawijający łańcuch perla.

  1. Kod bez funkcji specyficznych dla C ++ jest zwykle łatwiejszy w utrzymaniu

Prawdą jest, że kod, który wykorzystuje mniej funkcji, jest łatwiejszy w utrzymaniu. A ponieważ wszystkie języki są równoważne Maszynie Turinga, a Maszyna Turinga ma najmniej funkcji w jakimkolwiek języku programowania, powyższy interpreter perla faktycznie uruchamia Maszynę Turinga (taśma i wszystkie), która rozwiązuje twój problem.

  1. 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.

Funkcje specyficzne dla języka C ++ mają cenne zastosowanie. Ponieważ nie są Javą, są przekleństwem, a ci, którzy z niej korzystają, mogą być markowymi heretykami. Gdyby C ++ nie miał tych funkcji językowych, nie byłbyś w stanie znaleźć tych, które musisz poświęcić. Funkcje języka C ++ rozwiązują problemy!


Look, C ++ i Java mają inny zestaw możliwości. Programowanie na przecięciu C ++ i Java skutkuje kodem, który odrzucił większość zalet obu języków.

Java została opracowana częściowo w reakcji na pewne nadużycie funkcji C ++. Nie oznacza to, że reakcja była uzasadniona, zwłaszcza lata później, kiedy cechy już dojrzały.

Możesz robić okropne rzeczy z przeciążeniem operatora; ale żaden język nie może zapobiec napisaniu okropnego kodu w tym języku, chyba że powstrzyma to napisanie całego kodu w tym języku.

Możesz także robić bardzo eleganckie rzeczy z przeciążeniem operatora. Proste rzeczy, takie jak liczba zespolona lub klasa macierzy, która działa jak liczba zespolona lub macierz.

Należy zachować ostrożność przy korzystaniu z funkcji C ++ niedostępnych w Javie. To, że obecny zestaw programistów na ich obecnym poziomie umiejętności nie rozumie funkcji, nie oznacza, że ​​nigdy nie należy jej używać; jednocześnie, tylko dlatego, że możesz użyć funkcji, nie oznacza, że ​​powinieneś. Jednak w sklepie z dużą ilością Java szanse na opór będą silniejsze niż powinny w stosunku do funkcji innych niż Java.

Konwersja kodu między językami najlepiej jest przerobić, bez względu na to, jak strukturalnie są one podobne. Każda próba zrobienia tego bez takiego przepisywania zakończy się niepowodzeniem.

Wiele funkcji specyficznych dla C ++ to cuda w utrzymaniu. Usuwanie typu (jak std::function) pozwala rozdzielić hierarchie, co zmniejsza zależności. Inteligentne wskaźniki i deterministyczne czasy życia oraz RAII zmniejszają niespodzianki w czasie wykonywania i usuwają podstawową zasób zasobów. Ciężkie, statyczne kontrole typu oznaczają, że kod nie kompiluje się, a nie działa. Wtyczki zmniejszają powielanie kodu. ADL pozwala na niezależne ad-hoc rozszerzanie interfejsów między hierarchiami typów. Lambda pozwala pisać kod obok miejsca, w którym jest używany. Przekazywanie i przenoszenie zmniejsza liczbę kopii i sprawia, że ​​programowanie w stylu funkcjonalnym (bez efektów ubocznych) jest wydajne. Przeciążenie operatora zmniejsza szum linii i sprawia, że ​​kod wygląda bardziej jak matematyka, którą modeluje.

Uważaj na dół Turinga Tar. Możesz zaimplementować wszystko w dowolnym języku (w tym surową maszynę Turinga z taśmą), ale to nie znaczy, że powinieneś . Emulowanie funkcji C ++ przy użyciu konstrukcji języka Java w C ++ jest okropnym pomysłem; spowoduje to niemożliwy do utrzymania kod, którego nikt nie będzie w stanie odczytać ani zrozumieć.

Możesz czerpać inspirację z projektów Java i przenieść je do C ++. Jestem wielkim fanem przyjmowania funkcji języka Python i implementowania ich w C ++, ponieważ podoba mi się składnia. Ale to nie znaczy, że piszę metody klas jako metody statyczne, biorąc jawne „ja”, a następnie piszę opakowanie, które przekazuje do niego wywołanie metody niestatycznej.

Nowoczesne C ++ nie jest tak bardzo podobne do języka emulowanego i odrzucanego przez Javę. Nie daj się zablokować funkcjom jednego języka; nie ma „jednego prawdziwego języka”. Dowiedz się o nowych językach i ich funkcjach oraz chłonąć ich odrębność.

Jak
źródło
1
-1, długo rozwinięty i niejasny.
djechlin
4
-1 argumentacyjny, argument słomiany
użytkownik949300
28
+1, właściwa dekonstrukcja zadawanych pytań i się śmiałam :)
kot
11
+1. Zabawne, ale dotrzymuje kroku. Bardzo jasne dla osób, które to czytają.
Luis Masuelli
14
„Programowanie na przecięciu C ++ i Java skutkuje kodem, który odrzucił większość zalet obu języków.” Trafić w sedno! +1
Ajedi32
56

Odpowiem tylko na twoje powody:

  1. Nie rozumiem, jak doszedłeś do tego wniosku. Różne języki mają różne funkcje. Zależy od zakresu, architektury języka, czasem preferencji twórców i wielu innych powodów. Niektóre funkcje języka mogą być złe, ale ogólne uogólnienie jest błędne IMHO.
  2. Pisanie C ++ tak jak Java może prowadzić do gorszego kodu. Np. Obecnie w C ++ 11 unikam używania nowego / usuwania, ale używam wskaźników wspólnych. W twoim scenariuszu polegałbym tylko na nowym / usuń. Jeśli programiści rozumieją tylko Javę, przećwicz ją lub zatrudnij lepszych.
  3. Czy to się prawdopodobnie wydarzy? Dlaczego nie piszesz w Javie? Myślę, że przepisywanie programów od zera w nowym języku jest generalnie złym pomysłem i potrzebujesz naprawdę dobrego uzasadnienia takiego ryzyka.
  4. To tylko założenie.
  5. Zależy wysoce IMHO od twojego scenariusza lub przypadku użycia.
Szymon
źródło
27
Programiści Java też by tego nie używali delete.
Paŭlo Ebermann
8
Musiałem naprawić wycieki pamięci spowodowane przez programistów Java, którzy nie wiedzą o tym delete. Z tego co pamiętam, w co najmniej jednym z tych przypadków dynamiczna alokacja ( new) również nie była potrzebna.
Ethan Kamiński
16
@EthanKaminski Tak, w ten sposób możesz łatwo dostrzec początkującego C ++, szczególnie kogoś, kto pochodzi z języka Java lub podobnego. Przestań używać nowego do wszystkiego, do cholery!
Luaan
1
@ PaŭloEbermann Tak, jeszcze gorzej.
Simon
1
„W twoim scenariuszu polegałbym tylko na new / delete” - zabawne, pomyślałbym, że można używać wyłącznie idiomu C ++ „tylko dla języka Java” make_shared.
Kyle Strand
26

Java ma funkcje, których C ++ nie ma, takie jak wbudowany, szybki i niezawodny moduł wyrzucania elementów bezużytecznych, hierarchia obiektów z jednym katalogiem głównym i potężna introspekcja.

Inne funkcje Javy są zaprojektowane tak, aby współpracowały z funkcjami wyłącznymi dla Javy, a wiele pominiętych przez Javy funkcji C ++ jest możliwych, ponieważ nowe funkcje nadrabiają brak. Na przykład Java nie ma obiektów alokowanych na stosie z deterministycznymi destrukatorami, ale w końcu ma bloki (i try-with-resources od Java 7) oraz moduł wyrzucający elementy bezużyteczne.

C ++ nie ma w końcu bloków ani wyrzucania elementów bezużytecznych. Jeśli nie używasz destruktorów, ponieważ nie istnieją one w Javie (nie liczę finalizatorów), jesteś na poziomie zarządzania zasobami C (tj. Wszystkie ręcznie), z tym wyjątkiem, że nie możesz nawet pogrupować swojego czyszczenia do bloku czyszczenia, do którego musisz przejść, ponieważ Java też go nie ma. Czy naprawdę uważasz, że poprawia to łatwość konserwacji?

Java ma nadrzędną hierarchię obiektów, w której każda klasa ostatecznie wywodzi się z Object, a kilka prymitywnych typów można również automatycznie umieszczać w takich klasach. Umożliwia to jednokrotne pisanie pojemników z obiektami w celu przechowywania wskaźników do obiektu. Java 5 wprowadziła generyczne, które pozbywają się rzutów, których wymagają takie kontenery, ale nadal kompilują się do prawie tego samego kodu.

C ++ nie ma takiej hierarchii. Aby ułatwić pisanie kontenerów, które działają dla wielu typów, korzystasz z szablonów, które są schematami tworzonymi przez kompilator w razie potrzeby dla różnych typów. Czy zabronisz używania szablonów (i makr) i pójdziesz drogą C, pisząc ciągle ten sam kod kontenera dla różnych typów, lub używając pustych wskaźników? (Czekaj, Java nie ma pustych wskaźników!) Czy jesteś pewien, że zwiększy to łatwość konserwacji?

Przyzwoity język ma wiele funkcji zaprojektowanych do współpracy. Zabraniając funkcji z języka A, ponieważ język B ich nie ma, kalekujesz język A, ponieważ nie dodajesz jednocześnie funkcji z B, które sprawiają, że B jest spójną całością.

Nie oznacza to, że nie wolno ograniczać dozwolonych funkcji C ++. C ++ jest dużym, historycznie rozwijanym językiem, który kładzie nacisk na umożliwienie programiście robienia tego, co chce, nad bezpieczeństwem i łatwością użycia, i nie wszystkie jego funkcje w całej ich elastyczności są niezbędne do tworzenia dobrych programów. Istnieje wiele standardów kodowania, które ograniczają korzystanie z niektórych funkcji; na przykład wytyczne Google w większości zabraniają wielokrotnego dziedziczenia, złożonych szablonów i wyjątków (choć ten ostatni jest z przyczyn historycznych). Ale żadna funkcja nie jest zabroniona „ponieważ Java jej nie ma”; funkcje są rozważane w ramach samego C ++.

Sebastian Redl
źródło
27
Doświadczeni weterani C ++ zwykle odrzucają wytyczne Google dotyczące kodowania. Współczesne C ++ jest znacznie lepsze właśnie dlatego, że wykorzystuje te funkcje. Tak, czyni to jeszcze bardziej innym.
Jan Hudec
17
Zauważ, że C ++ nie ma ostatecznie bloków, ale ma RAII, co jest znacznie lepsze w większości przypadków. I znowu inaczej.
Jan Hudec
7
Java Objectjest prawie void*do większości zastosowań - wciąż, fuj.
Quentin,
1
Poza wyborem funkcji jest kwestia stylu i idiomu. Programy są ogólnie łatwiejsze do odczytania i utrzymania, jeśli używają normalnych idiomów dla języka, w którym zostały napisane. Nawet jeśli ktoś mógłby napisać część programu C ++ przy użyciu tylko funkcji podobnych do Javy, rezultatem byłby dziwny, stilowany C ++.
Patricia Shanahan
2
Poparłbym tę odpowiedź za to, że jestem na dobrej drodze („nie rób tego”), ale nie mogę znieść podstawowej przesłanki, że Java jest w jakiś sposób „bardziej zaawansowana” niż C ++. C ++ nie potrzebuje modułu wyrzucania elementów bezużytecznych lub hierarchii obiektów z jednym katalogiem głównym, w ten sam sposób, w jaki Java nie potrzebuje ... Eee ... przepraszam, nie wiem jak dokończyć zdanie, ponieważ brakuje mi deterministycznych destruktorów w Javie, i finallynie zastępuje ich. Te dwa języki są zasadniczo różne.
DevSolar
25

Zastanawiałem się, czy nie zawracać sobie głowy publikowaniem kolejnej odpowiedzi, gdy już masz numer, który wydaje się całkowicie rozsądnymi wnioskami: że twój pomysł jest w zasadzie katastrofą, która czeka na nadejście. Myślę jednak, że nie podali oni bardzo istotnych powodów takiego wniosku.

Różnice między Javą a C ++ sięgają znacznie głębiej niż szczegóły, na których wydajesz się skupiać.

Na przykład mówisz o zakazie wielokrotnego dziedziczenia w C ++. Po pierwsze, zwrócę uwagę, że po prostu tego nie rozumiem. Java definiuje „interfejsy” jako oddzielne rzeczy od „klas”. Jedna klasa dziedziczy po tylko jednej innej klasie, ale może implementować dowolną liczbę interfejsów.

C ++ nie rozdziela w ten sposób dwóch pojęć. Najbliższy analogowe C ++ zapewnia interfejs do wdrożenia w Javie jest dziedziczenie z innej klasy. W związku z tym, aby utrzymać dwa wyrównane w miarę dobrze, prawdopodobnie musisz użyć wielokrotnego dziedziczenia w C ++, ale chcesz ograniczyć niektóre z tych klas podstawowych w mniej więcej taki sam sposób, w jaki Java ogranicza interfejs w porównaniu do klasy (tj. Zasadniczo że określa podpisy funkcji, ale przynajmniej nie implementacje).

To jednak ledwo zarysowuje rzeczywiste różnice między nimi. W rzeczywistości, gdzie kod Java prawdopodobnie definiuje interfejsy i klasy, które implementują te interfejsy, kod C ++ jest znacznie bardziej prawdopodobne, aby zdefiniować niektóre szablony, które będą działać z dowolną klasą, która spełnia jej wymagania (nie tylko te zdefiniowane specjalnie do implementacji interfejsu (s) określa).

Jeśli naprawdę chcesz kodu, który jest w zasadzie „Javą używającą składni C ++”, prawie na pewno będziesz musiał zabronić czegokolwiek i wszystkiego podobnego do tego ostatniego. Musisz ograniczyć korzystanie z szablonów do z grubsza poziomu „kontenera T”, który obsługuje generyczne Java. Niestety, zrobienie tego spowoduje kod C ++, który jest takim bałaganem, że nikt nie jest w stanie utrzymać go tak, jak jest teraz, nie wspominając o długoterminowej możliwości przetłumaczenia go na inny język programowania.

Jeśli naprawdę chcesz kodu, który można w przyszłości przekonwertować na inny język, postaraj się, aby był on jak najbardziej czysty i czytelny. Idealne jest, aby napisać pseudo-kod i nadal go uruchamiać. Dobrze napisane nowoczesne podejście do C ++ idealnie pasuje do tego znacznie bliżej niż sugerowany przez ciebie podzbiór. Bez względu na to, jak go napiszesz, jeśli kiedykolwiek tłumaczysz na Javę, będziesz musiał faktycznie przetłumaczyć kod, a nie tylko składnię poszczególnych instrukcji.

Jerry Coffin
źródło
Z wielu funkcji C ++ można korzystać na różne sposoby, które ładnie odwzorowują koncepcje Java, i na inne, które tego nie robią. Niektóre części programu będą wymagały czegoś poza nakładającym się podzbiorem funkcjonalności języków, a próba napisania takich części jak „Java przy użyciu składni C ++” doprowadzi do strasznego bałaganu. Z drugiej strony wiele innych części kodu może potrzebować czegokolwiek poza udostępnionym podzbiorem, a próba pozostania w udostępnionym dla tych części kodu, w których nie ma istotnych powodów, aby wyjść na zewnątrz, może być pomocna.
supercat
Prawdopodobnie tam, gdzie mówisz „może potrzebować”, naprawdę masz na myśli: „może nie potrzebować”? Zakładając, że tak, to raczej się zgadzam.
Jerry Coffin
Tak. Jeśli zajdzie konieczność obsługi platformy obsługującej Javę, ale nie C ++, części kodu prawie na pewno będą musiały zostać przepisane od nowa i nie będzie miało znaczenia, czy te części zostały napisane przy użyciu technik przyjaznych dla Java, ponieważ „ I tak zostanie przepisany. Możliwe jest jednak napisanie innych części w sposób, który pozwoliłby na migrację bez pełnego przepisywania, a w niektórych przypadkach dodatkowe koszty wymagane do tego mogą być minimalne.
supercat
4
@ superuper: OTOH, biorąc pod uwagę liczbę platform obsługujących Javę, ale nie C ++, wydaje mi się, że jest to prawie całkowicie rozwiązanie problemu w poszukiwaniu problemu.
Jerry Coffin
Przez pewien czas obsługa przeglądarki dla apletów Java była lepsza niż apletów C ++. Obsługa przeglądarki JavsScript (bez związku z Javą) została jednak poprawiona na tyle, że została w zasadzie przejęta z obu.
supercat
11

Jeśli masz zamiar napisać kod w języku X, poświęć czas na odpowiednią naukę języka i skorzystaj ze wszystkich oferowanych przez niego funkcji, aby pomóc Ci rozwiązać problem. Złe rzeczy dzieją się, gdy próbujesz wykonać tłumaczenie „słowo w słowo” z jednego języka na inny, czy to z japońskiego na angielski, czy z Java na C ++. O wiele lepiej jest zacząć od dobrego zrozumienia problemu i wyrazić rozwiązanie w sposób najbardziej naturalny dla używanego języka.

Wiele lat temu widziałem program w języku C, który nie miał wcięcia, a każda instrukcja zaczynała się w kolumnie 7, ponieważ autorem kodu był programista z Fortranu, który akurat używał C. Inni programiści z Fortranu martwili się tymi nowymi modami zwanymi wskaźnikami. Nie miałem serca wspominać wskaźników do wskaźników, myślę, że zemdlałyby na miejscu.

Wyobraź sobie, że zatrudnisz kogoś, kto utrzyma ten kod w przyszłości. Jeśli jest to dobry kod C ++, będziesz mógł zatrudnić kompetentnego programistę C ++ i powinien on być w stanie znaleźć drogę. Jeśli jest to „Java w C ++”, to ani programiści C ++, ani Java nie będą mieli łatwego zrozumienia kodu.

Tom Penny
źródło
7

Wszystkie twoje powody mogą zostać obalone:

Jeśli Java nie udostępnia funkcji, którą posiada C ++, oznacza to, że ta funkcja nie jest dobra, dlatego powinniśmy jej unikać.

Nie oznacza to, że funkcja nie jest dobra (żadna funkcja nie może być z natury zła). Oznacza to tylko, że funkcja była często niewłaściwie używana (lub niemożliwa do wdrożenia z powodu podstawowych pojęć, takich jak bezpośrednie wskaźniki vs. wyrzucanie elementów bezużytecznych). Java z definicji ma być łatwiejsza i bardziej przyjazna dla programistów, stąd usunięcie funkcji, które okazały się łatwe do nadużyć.

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.

Och, może być? Zobaczmy najprostszy kod C ++:

int len = mystring->size();

Ups, nie używa się funkcji „specyficznych dla języka”, ale jest to już niemożliwe do utrzymania przez programistów Java! Ponieważ w Javie dereferencje dotyczą „.” podczas gdy tutaj jest to „->.

Możesz zostać poproszony o konwersję kodu na Javę

Lub C #. Lub Haskell. Lub Python. Lub Ruby. Lub COBOL (tak, możesz!). Jak możesz powiedzieć o przyszłości?

Kod bez funkcji specyficznych dla C ++ jest zwykle łatwiejszy w utrzymaniu.

Dokładnie odwrotnie. Każda funkcja została wprowadzona w celu ułatwienia programowania, a tym samym łatwiejszej konserwacji. Np .: weź program działający na liczbach zmiennoprzecinkowych. Teraz zaktualizuj go, aby obsługiwał liczby zespolone. Przeciążenie operatora na ratunek!

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.

Ale Java DOES ma wiele dziedziczeń! Nazywa się to „interfejsem”. Implementacja Java jest problematycznym obejściem, aby uniknąć przerażającego diamentu spowodowanego tym, że wszystko pochodzi Object. Odbywa się to poprzez wprowadzenie, interfacektórego jedynym celem jest bycie czymś, co nie pochodzi Object. C ++ nigdy nie miał tego problemu - nie ma obowiązkowej wspólnej podstawy, więc każda klasa może funkcjonować jako interfejs bez przerażającego diamentu.

Uwaga dodatkowa: Java niedawno wprowadziła ... konkretne metody w interfejsach. Dodano funkcję C ++ zawsze musiał rozwiązać problem, którego nigdy nie było.

Wspomniałeś też tylko o kilku „rzeczach, które ma C ++, ale Java nie”. Jedną z największych różnic między C ++ a Javą jest kontrola nad układem pamięci. Możesz utworzyć tablicę wskaźników do obiektów (tak jak w Javie) LUB możesz stworzyć ciągły blok pamięci. Teraz, gdybym się martwił o funkcję C ++, która może wprowadzać w błąd programistów Java, coś tak ukrytego i subtelnego, jak ten, znalazłby się na mojej liście znacznie wyżej niż oczywiste i rozpoznawalne na pierwszy rzut oka rzeczy takie jak wielokrotne dziedziczenie lub przeciążone operatory.

Konkluzja: Czysty kod to czysty kod. Java lub C ++ - ta sama różnica. Po prostu to proste. Niepotrzebne komplikacje są główną przyczyną złego kodu.

Agent_L
źródło
Java oferuje pewne funkcje i gwarancje, które byłyby nieobsługiwane w języku, który oferuje wszystkie funkcje C ++. Język nie może na przykład pozwalać na dynamiczne ładowanie typów i pełny zakres rzutowań zachowujących tożsamość Java, oferując uogólnione formy wielokrotnego dziedziczenia zawarte w C ++.
supercat
@ supercat Nie rozumiem, dlaczego mówisz to tutaj. Pytanie nie dotyczy funkcji Java, których nie można odtworzyć w C ++, chodzi o funkcje C ++ odrzucone przez Javę.
Agent_L
Chodzi mi o to, że niektóre funkcje Java nie są zawarte w C ++, ale raczej niektóre funkcje Java są zasadniczo niekompatybilne z innymi funkcjami zawartymi w C ++, tak że żaden język nie może mieć typów obsługujących oba (języki takie jak C ++ / CLI mają typy obsługujące funkcje C ++ i typy obsługujące funkcje Java, ale skutecznie zamieszkują osobne wszechświaty o ograniczonej interoperacyjności).
supercat
6

Nie, ogólnie nie powinieneś pisać w C ++ tak jak w Javie i zdecydowanie nie powinieneś pomijać funkcji języka C ++, które nie są obecne w Javie.

Po pierwsze, Java jest śmieciami i dlatego nie ma odpowiednika słowa kluczowego „delete” w C ++. W porządku, więc wdrażasz program bez usuwania, ponieważ zgodnie z twoimi regułami jest to niedozwolone.

Gratulacje, masz teraz wyciek pamięci;). To też nie jest teoria - widziałem, że dokładnie taka sytuacja ma miejsce w grze typu open source.

Podobnie Java nie ma żadnych wskaźników podobnych do C ++, co wyklucza wiele typowych konwencji wywołań funkcji.

Istnieją funkcje C ++, których powinieneś unikać (patrz poniżej), ale „nie bycie w Javie” nie jest dobrym testem lakmusowym.


Lepsze wytyczne byłyby następujące:

  1. Napisz kod odpowiedni dla twojego języka, środowiska i narzędzi.
  2. Napisz kod, który Twój zespół może zrozumieć.
  3. Upewnij się, że Twój zespół jest kompetentny w danej dziedzinie.

Pozycja (3) oznacza, że ​​nie powinieneś mieć kodu dla programistów Java w C ++ bez przeszkolenia ich w C ++. Istnieją pewne subtelne, ale bardzo ważne różnice, których mogą się nie nauczyć, jeśli próbują potraktować to jak dziwny dialekt języka Java.

Pozycja (2) oznacza, że ​​jeśli twój zespół jest niewygodny w przypadku wielokrotnego dziedziczenia (na przykład) i jeśli istnieje odpowiednie rozwiązanie, które go nie używa, może być wskazane użycie tego alternatywnego rozwiązania. Zależy to jednak konkretnie od twojego zespołu. Z drugiej strony, jeśli twój zespół jest bardziej niewygodny z tym alternatywnym rozwiązaniem niż z wielokrotnym dziedziczeniem, użyj wielokrotnego dziedziczenia!


Wreszcie istnieją C ++ cechy językowe C ++, których prawdopodobnie należy unikać. Jeśli chcesz wiedzieć, co to jest, zapytaj programistów C ++ , a nie programistów innego języka. Niektóre przykłady na początek to arytmetyka wskaźników (brak uniwersalnego konsensusu) i goto.

Ethan Kamiński
źródło
6

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ć newdo 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ć, *newużywając #define New *new, lub, co gorsza, #define new *newale wtedy prosisz innych programistów, żeby cię nienawidzili.) I, jak wspomniano powyżej, deletenie 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_ptrma 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 Foomomentu 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:

  1. 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.
  2. 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 constexpristnieje 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 ++,

Kyle Strand
źródło
5
Autor FQA zdecydowanie należy do grupy „rozumie co najwyżej 20% języka”. Jest tam sporo odpowiedzi, które są niepoprawne, i cała masa innych, które po prostu mija się z celem, ilustrowane słomianką za słomianą.
Ben Voigt
2
Wiele (prawie wszystkie?) Skarg w C ++ FQA jest nonsensownych. Współczesne języki są ogromne. C ++ jest raczej niewielki w porównaniu do Python, Ruby, Perl i tak, Java. Zadaj podstawowe pytanie w tych językach na temat przepełnienia stosu, a pierwsza odpowiedź prawie nieuchronnie brzmi: „Dlaczego nie zrobiłeś tego import SomeVeryBasicPackagei po prostu to zrobiłeś ?” Zadaj pytanie zaawansowany i pierwsza odpowiedź jest niemal nieuchronnie wzdłuż linii „Dlaczego nie import SomeMagicalPackagei po prostu zrobić to ?”
David Hammen
1
@DavidHammen Myślę, że podział 80/20 odnosi się do podstawowych funkcji języka, a nie tylko standardowych składników biblioteki, w którym to przypadku wspomniane języki, z wyjątkiem Perla, nie wydają się tak duże i skomplikowane jak C ++. W każdym razie była to bardzo mała część mojej odpowiedzi i uznałem, że jest to stronnicze źródło.
Kyle Strand
1
Języki VM / zarządzane są oczywiście znacznie bardziej skomplikowane pod powierzchnią, ale mam na myśli skomplikowane z perspektywy użytkowania.
Kyle Strand
1
Nie mam pojęcia, czy twoja teoria jest poprawna, chociaż w moim przypadku zdecydowanie nauczyłem się C ++ i C osobno, a moja klasa C ++ była bardzo dokładna. Ale pełny cytat o podziale 20/80 jest taki, że każdy programista zna inne 20% języka, czego nie tłumaczy większość programistów uczących się części C języka niezależnie. W każdym razie, jeśli chcesz szczegółowo wyjaśnić, w jaki sposób C ++ pozwala na bardziej niezawodne programowanie (twierdzę, że widziałem już wcześniej, ale nie rozumiem), prawdopodobnie najlepiej zrobilibyśmy to na czacie lub w innym miejscu niż w komentarzach tutaj .
Kyle Strand
5

Załóżmy, że jestem ograniczony do używania C ++ przez środowisko w projekcie. Czy dobrze jest zapobiegać korzystaniu z niektórych funkcji językowych, które ma C ++, ale Java nie ma (np .: wielokrotne dziedziczenie, przesłonięcie operatora)?

Nie.

Jeśli „w środowisku projektu” jesteś ograniczony do posługiwania się C ++, to nie ma sensu nawet myśleć o jakiejkolwiek innej technologii, bez względu na to, jak bardzo osobiście wolisz / mam nadzieję, że będziesz go używał / ewangelizował.
To, czy „Technologia X” czy „Y” obsługuje jakąkolwiek daną funkcję, nie powinno mieć żadnego wpływu na sposób, w jaki budujesz aplikację C ++.
Jest to aplikacja C ++, prawdopodobnie z jakiegoś „dobrego powodu” (teraz lub w przeszłości), więc powinieneś napisać ją jako aplikację C ++, używając tego, co zapewnia ten „zestaw narzędzi”.

Jeśli i kiedy istnieje potrzeba przeniesienia aplikacji na inną technologię, wtedy (i tylko wtedy) możesz rozważyć funkcje na innych platformach. Nie ma sensu „obcięcie nosa do przekór twarzy” na znikoma szansa, że coś może się wydarzyć. Pamiętaj jednak, że hurtowe przepisywanie jest kosztowną, ryzykowną operacją, której kierownictwo raczej nie podejmie bez uzasadnionego powodu.

Podobna debata („używać lub nie używać”) była kilka lat temu w świecie Visual Basic [.Net], gdzie ktoś miał świetny pomysł, aby pisać aplikacje Visual Basic bez używania żadnego z [podstawowych języków] funkcjonalność zapewniana przez przestrzeń nazw Microsoft.VisualBasic. To byłoby jak próba napisania aplikacji w C ++ bez przestrzeni std :: names; OK, jest to możliwe, ale dlaczego, u licha, ktoś przy zdrowych zmysłach miałby to robić?

Phill W.
źródło
1
Do ostatniego punktu na temat Visual Basic: Problem z takimi bibliotekami dostawców jest taki, że są one zastrzeżone. Korzystanie z nich oznacza powiązanie się z tym sprzedawcą. Dostawcy spodoba się, że będziesz związany łańcuchem, ale na dłuższą metę tego nie zrobisz: nie możesz korzystać z oprogramowania innego dostawcy bez przepisywania wszystkiego, co zależy od jego specyficznych funkcji. Im częściej korzystasz z funkcji specyficznych dla dostawcy, tym wyższy staje się koszt zmiany dostawcy, dzięki czemu Twój sprzedawca może wymusić na tobie zmiany. To jeden z powodów, dla których wolne (jak w wolności!) Oprogramowanie jest tak wielką sprawą.
cmaster
Przestrzeń Microsoft.VisualBasicnazw jest trochę rozciągnięta. Minęło wiele lat, odkąd go ostatnio używałem, ale przynajmniej na początku było to głównie ukierunkowane na wsteczną kompatybilność z VB6 (i / lub aby programiści VB6 czuli się jak w domu); w większości zapewniał funkcjonalność, która była już dostępna w pozostałej części frameworka w bardziej nowoczesnej (i lepiej zintegrowanej) formie, więc w nowych projektach rzadko ma sens używanie go. Przeciwnie, w std::przestrzeni nazw znajduje się cała standardowa biblioteka - unikanie jej byłoby jak unikanie całej BCL w .NET.
Matteo Italia
2

Wszystkie obecne odpowiedzi mówią, że jest to zła rzecz, ponieważ powinieneś skorzystać z używanego języka, a także wyjaśnić, dlaczego funkcja C ++ nie jest „zła” tylko dlatego, że nie jest w jave. Odpowiem na to z innej strony.

Jedną rzeczą jest unikanie złożonej funkcji C ++, takiej jak wielokrotne dziedziczenie, przeciążanie operatora i definiowanie własnego szablonu.

Ale każdy problem, który wykonuje coś więcej niż najprostsze zadanie:

  • przydziela pamięć,
  • łączy te pieniądze z punktami
  • więc buduj struktury danych
  • umożliwia ponowne użycie pamięci, gdy jest to bezpieczne

Nie ma wspólnego podzbioru Java i C ++, który pozwala na powyższe, dlatego nie można zrobić tego, o co pytasz. (Gdybyś pytał o Javę i C #, miałbyś dużo większą szansę, ponieważ obaj używają śmieciarek.)

Jednak może być wymagane napisanie kodu, aby programista Java mógł zrozumieć, co robi (ale nie szczegółowe „jak”), co byłoby rozsądne.

Możesz także zaprojektować własny język, który zaimplementowałeś zarówno w C ++, jak i JAVA .....

Ian
źródło
0

Nikt nie powinien pisać kodu, którego inni koderzy nie rozumieją. Jeśli uważasz, że blokada języka stanowi problem, poczekaj, aż pojawi się blokada programisty. Jedno jest bardziej prawdopodobne, że zatrzyma cię jako zakładnika niż drugie.

Naprawdę nie ma technicznych powodów. Stworzyłeś scenariusz, w którym język był używany z jakiegokolwiek powodu, ale wielu obecnych i prawdopodobnie przyszłych programistów tak naprawdę go nie rozumie.

Domyślam się, że programiści Java mogą pisać C ++ w taki sposób, w jaki piszą w Javie, więc po co ustawiać to jako regułę. Możesz odkryć niektóre funkcje specyficzne dla C ++, które są łatwiejsze do wdrożenia i utrzymania dzięki małej instrukcji / dokumentacji C ++ dla programistów Java niż wielka kula bałaganu Java, z którym w przeciwnym razie utknęliby.

Jest to argument o problemach programistów BASIC przechodzących na języki obiektowe. Nie chodzi o to, że wdrażają praktyki OOP ze szkodą dla nowych deweloperów, którzy ich nie rozumieją, ale że w ogóle tego nie wdrażają. Jeśli tak, zwykle źle to rozumieją. Jeśli coś zrobiono źle, należy je usunąć bez względu na przyczynę.

Poza kimś po prostu ślepo kopiującym i wklejającym kod, zrobią to w wielu obszarach, których i tak nie rozumieją.

JeffO
źródło