Porównanie Javy i C++ - Comparison of Java and C++

Jest to porównanie Java i C++ , dwóch znanych języków programowania obiektowego .

Cele projektowe

Różnice między językami programowania C++ i Java można przypisać ich dziedzictwu , ponieważ mają różne cele projektowe.

C++ został zaprojektowany z myślą o programowaniu systemów i aplikacji ( tj. programowaniu infrastruktury), rozszerzając proceduralny język programowania C , który został zaprojektowany z myślą o sprawnym wykonywaniu. Do C, C++ dodano obsługę programowania obiektowego , obsługę wyjątków , zarządzanie zasobami na podstawie czasu życia ( RAII ), programowanie ogólne , metaprogramowanie szablonów i standardową bibliotekę C++, która zawiera ogólne kontenery i algorytmy ( Standardowa biblioteka szablonów lub STL), i wiele innych obiektów ogólnego przeznaczenia.

Java jest uniwersalnym, współbieżnym, opartym na klasach, zorientowanym obiektowo językiem programowania, który został zaprojektowany w celu zminimalizowania zależności implementacyjnych. Opiera się na wirtualnej maszynie Java, aby zapewnić bezpieczeństwo i wysoką przenośność . Jest dołączony do obszernej biblioteki zaprojektowanej w celu zapewnienia pełnej abstrakcji podstawowej platformy. Java to statycznie typowany język obiektowy, który używa składni podobnej do (ale niezgodnej) z C++. Zawiera system dokumentacji o nazwie Javadoc .

Różne cele w rozwoju C++ i Java zaowocowały różnymi zasadami i kompromisami projektowymi między językami. Różnice są następujące:

C++ Jawa
Rozszerza C o programowanie obiektowe i programowanie generyczne . Najodpowiedniejszy jest kod C. Silny wpływ na składnię C++/C.
Kompatybilny z kodem źródłowym C , z wyjątkiem kilku narożnych przypadków . Udostępnia interfejs Java Native Interface, a ostatnio Java Native Access jako sposób bezpośredniego wywoływania kodu C/C++.
Pisz raz, kompiluj w dowolnym miejscu (WOCA). Napisz raz, uruchom wszędzie /everywhere (WORA/WORE).
Umożliwia programowanie proceduralne , programowanie funkcyjne , programowanie obiektowe , programowanie ogólne i szablonu metaprogramowanie . Sprzyja mieszance paradygmatów. Umożliwia programowanie proceduralne , programowanie funkcyjne (od Javy 8) i programowania generycznego (ponieważ Java 5), ale zdecydowanie zachęca obiektowego programowania paradygmatu . Zawiera wsparcie dla tworzenia języków skryptowych .
Działa jako natywny wykonywalny kod maszynowy dla docelowych zestawów instrukcji . Działa na maszynie wirtualnej .
Zawiera typy obiektów i nazwy typów. Umożliwia odbicie za pomocą informacji o typie czasu wykonywania (RTTI). Jest refleksyjny , umożliwiając metaprogramowanie i dynamiczne generowanie kodu w czasie wykonywania.
Ma wiele standardów kompatybilności binarnej (powszechnie Microsoft (dla kompilatora MSVC) i Itanium/GNU (dla prawie wszystkich innych kompilatorów)). Ma jeden standard kompatybilności binarnej, wieloplatformowy dla systemu operacyjnego i kompilatora.
Opcjonalne automatyczne sprawdzanie granic (np. at()metody w vectori stringkontenerach). Wszystkie operacje muszą być sprawdzane przez wszystkie zgodne dystrybucje Java. HotSpot może usunąć sprawdzanie granic.
Natywna obsługa arytmetyki bez znaku . Natywna arytmetyka bez znaku nie jest obsługiwana. Java 8 zmienia niektóre z nich, ale aspekty są niejasne.
Ustandaryzowane minimalne limity dla wszystkich typów liczbowych, ale rzeczywiste rozmiary są zdefiniowane przez implementację. Standardowe typy są dostępne w standardowej bibliotece <cstdint>. Znormalizowane limity i rozmiary wszystkich typów podstawowych na wszystkich platformach.
Wskaźniki, odwołania i przekazywanie przez wartość są obsługiwane dla wszystkich typów (pierwotnych lub zdefiniowanych przez użytkownika). Wszystkie typy (typy pierwotne i typy referencyjne ) są zawsze przekazywane przez wartość.
Zarządzanie pamięcią może odbywać się ręcznie przez new / delete, automatycznie według zakresu lub za pomocą inteligentnych wskaźników. Wspomaga deterministyczne niszczenie obiektów. Odśmiecanie ABI standaryzowane w C++11, chociaż kompilatory nie są wymagane do implementacji odśmiecania. Automatyczne zbieranie śmieci . Obsługuje niedeterministyczną metodę finalize(), której użycie nie jest zalecane.
Zarządzanie zasobami można wykonać ręcznie lub za pomocą automatycznego zarządzania zasobami na podstawie okresu istnienia ( RAII ). Zarządzanie zasobami musi być na ogół wykonywane ręcznie lub automatycznie za pomocą finalizatorów, chociaż generalnie jest to odradzane. Ma try-with-resources do automatycznego zarządzania zasobami w oparciu o zakres (od wersji 7).

Można to również zrobić za pomocą wewnętrznego API, sun.misc.Unsafeale takie użycie jest wysoce odradzane i zostanie zastąpione publicznym API w nadchodzącej wersji Java.

Obsługuje klasy, struktury ( typy pasywnej struktury danych (PDS)) i związki oraz może je alokować na stercie lub stosie . Klasy są alokowane na stercie . Java SE 6 optymalizuje z analizą ucieczki, aby alokować niektóre obiekty na stosie .
Umożliwia jawne zastępowanie typów i niektóre niejawne konwersje zawężające (w celu zapewnienia zgodności z C). Bezpieczeństwo typu sztywnego z wyjątkiem konwersji poszerzających.
C ++ Standardowa biblioteka został zaprojektowany, aby mieć ograniczony zakres i funkcje, ale obejmuje obsługę językową, diagnostyka, narzędzia ogólne, sznurki, lokalizacje, kontenery, algorytmy, iteratory , numeryczne, wejście / wyjście losowe generatory liczb, regularnego analizowania ekspresji, zaplecze gwintów , cechy typu (dla statycznej introspekcji typu) i Standard C Library. Do biblioteki doładowania oferuje więcej funkcji, takich jak sieci I / O.

Istnieje wiele bibliotek innych firm dla GUI i innych funkcji, takich jak: Adaptive Communication Environment (ACE), Crypto++ , różne biblioteki XMPP Instant Messaging (IM), OpenLDAP , Qt , gtkmm .

Biblioteka standardowa rosła z każdym wydaniem. W wersji 1.6 biblioteka zawierała obsługę ustawień regionalnych, logowania, kontenerów i iteratorów, algorytmów, programowania GUI (ale bez korzystania z GUI systemu), grafiki, wielowątkowości, sieci, bezpieczeństwa platformy, introspekcji, dynamicznego ładowania klas, blokowania i nie -blokowanie we/wy. Dostarcza interfejsy lub klasy wsparcia dla XML , XSLT , MIDI , łączności z bazami danych, usług nazewnictwa (np. LDAP ), kryptografii, usług bezpieczeństwa (np. Kerberos ), usług drukowania i usług internetowych. SWT oferował abstrakcję dla GUI specyficznych dla platformy, ale został zastąpiony przez JavaFX w najnowszych wydaniach; pozwalając na akcelerację grafiki i interfejsy użytkownika z motywami CSS. Chociaż nie obsługuje żadnego rodzaju obsługi „natywnego wyglądu platformy”.
Przeciążenie operatora dla większości operatorów. Zaleca się zachowanie znaczenia (semantyki). Operatorów nie można nadpisać. Język zastępuje + i += dla klasy String.
Pojedyncze i wielokrotne dziedziczenie klas, w tym dziedziczenie wirtualne. Obsługuje tylko pojedyncze dziedziczenie klas.
Szablony czasu kompilacji. Pozwala na kompletne metaprogramowanie Turinga . Generics są używane do osiągnięcia podstawowej parametryzacji typu, ale nie tłumaczą z kodu źródłowego na kod bajtowy z powodu użycia wymazywania typu przez kompilator.
Wskaźniki funkcji, obiekty funkcji, lambdy (w C++11 ) i interfejsy. Odwołania do funkcji, obiekty funkcyjne i wyrażenia lambda zostały dodane w Javie 8 . Klasy (i interfejsy, które są klasami) mogą być również przekazywane jako referencje poprzez SomeClass.classi someObject.getClass().
Brak standardowego mechanizmu dokumentacji wbudowanej. Istnieje oprogramowanie innych firm (np. Doxygen ). Obszerny standard dokumentacji Javadoc dla wszystkich klas i metod systemowych.
constsłowo kluczowe do definiowania niezmiennych zmiennych i funkcji składowych, które nie zmieniają obiektu. Const-ness jest propagowany jako środek do wymuszenia, w czasie kompilacji, poprawności kodu w odniesieniu do zmienności obiektów (patrz const-correctness ). finaludostępnia wersję const, równoważną type* constwskaźnikom do obiektów i consttypów pierwotnych. Niezmienność członków obiektów osiągnięta za pomocą interfejsów tylko do odczytu i enkapsulacji obiektów.
Popiera gotostwierdzenie. Obsługuje etykiety z pętlami i blokami instrukcji. gotojest zastrzeżonym słowem kluczowym, ale w specyfikacji Java jest oznaczone jako „nieużywane” .
Kod źródłowy można napisać tak, aby był wieloplatformowy (może być skompilowany dla systemów Windows , BSD , Linux , macOS , Solaris , itp. bez modyfikacji) i napisany w celu użycia funkcji specyficznych dla platformy. Zazwyczaj kompilowany do natywnego kodu maszynowego, musi zostać ponownie skompilowany dla każdej platformy docelowej. Skompilowany do kodu bajtowego Java dla JVM . Kod bajtowy jest zależny od platformy Java, ale zazwyczaj jest niezależny od funkcji specyficznych dla systemu operacyjnego .

Funkcje językowe

Składnia

  • Składnia Java ma gramatykę bezkontekstową, którą można przeanalizować za pomocą prostego parsera LALR . Parsowanie C++ jest bardziej skomplikowane. Na przykład Foo<1>(3);jest sekwencją porównań, jeśli Foo jest zmienną, ale tworzy obiekt, jeśli Foo jest nazwą szablonu klasy.
  • C++ zezwala na stałe, zmienne i funkcje na poziomie przestrzeni nazw. W Javie takie encje muszą należeć do określonego typu i dlatego muszą być zdefiniowane wewnątrz definicji typu, klasy lub interfejsu .
  • W C++ obiekty są wartościami, podczas gdy w Javie nie są. C++ domyślnie używa semantyki wartości, podczas gdy Java zawsze używa semantyki referencyjnej . Aby wybrać semantykę odniesienia w C++, można użyć wskaźnika lub odwołania.
C++ Jawa
class Foo {          // Declares class Foo
    int x = 0;       //  Private Member variable. It will
                     // be initialized to 0, if the
                     // constructor would not set it.
                     // (from C++11)
    public:
      Foo() : x(0)     //  Constructor for Foo; initializes
      {}               //  x to 0. If the initializer were
                     //  omitted, the variable would
                     //  be initialized to the value that
                     // has been given at declaration of x.

      int bar(int i) { // Member function bar()
          return 3*i + x;
      }
};
class Foo {               // Defines class Foo
    private int x;        // Member variable, normally declared
                          // as private to enforce encapsulation
                          // initialized to 0 by default

    public Foo() {        // Constructor for Foo
    }                     // no-arg constructor supplied by default

    public int bar(int i) {        // Member method bar()
        return 3*i + x;
    }
}
Foo a;
// declares a to be a Foo object value,
// initialized using the default constructor.

// Another constructor can be used as
Foo a(args);
// or (C++11):
Foo a{args};
Foo a = new Foo();
// declares a to be a reference to a new Foo object
// initialized using the default constructor

// Another constructor can be used as
Foo a = new Foo(args);
Foo b = a;
// copies the contents of a to a new Foo object b;
// alternative syntax is "Foo b(a)"
// Foo b = a;
// would declare b to be reference to the object pointed to by a
Foo b = a.clone();
// copies the contents of the object pointed to by a 
//     to a new Foo object;
// sets the reference b to point to this new object;
// the Foo class must implement the Cloneable interface
//     for this code to compile
a.x = 5; // modifies the object a
a.x = 5; // modifies the object referenced by a
std::cout << b.x << std::endl;
// outputs 0, because b is
// some object other than a
System.out.println(b.x);
// outputs 0, because b points to
// some object other than a
Foo *c;
// declares c to be a pointer to a
// Foo object (initially
// undefined; could point anywhere)
Foo c;
// declares c to be a reference to a Foo
// object (initially null if c is a class member;
// it is necessary to initialize c before use
// if it is a local variable)
c = new Foo;
// c is set to the value of the address of the Foo object created by operator new
c = new Foo();
// binds c to reference a new Foo object
Foo &d = *c;
// binds d to reference the same object to which c points
Foo d = c;
// binds d to reference the same object as c
c->x = 5;
// modifies the object pointed to by c
c.x = 5;
// modifies the object referenced by c
d.bar(5);  // invokes Foo::bar() for a
c->bar(5); // invokes Foo::bar() for *c
d.bar(5); // invokes Foo.bar() for a
c.bar(5); // invokes Foo.bar() for c
std::cout << d.x << std::endl;
// outputs 5, because d references the
// same object to which c points
System.out.println(d.x);
// outputs 5, because d references the
// same object as c
  • W C++ można zadeklarować wskaźnik lub referencję do obiektu const , aby uniemożliwić modyfikację kodu klienta. Funkcje i metody mogą również zagwarantować, że nie będą modyfikować obiektu wskazywanego przez wskaźnik za pomocą słowa kluczowego „const”. To wymusza poprawność const .
  • W Javie w większości przypadków poprawność const musi opierać się na semantyce interfejsu klasy, tj. nie jest silnie wymuszana, z wyjątkiem publicznych elementów danych, które są oznaczone etykietą final.
C++ Jawa
const Foo *a; // it is not possible to modify the object
              // pointed to by a through a
final Foo a; // a declaration of a "final" reference:
             // it is possible to modify the object, 
             // but the reference will constantly point 
             // to the first object assigned to it
a = new Foo();
a = new Foo(); // Only in constructor
a->x = 5;
// ILLEGAL
a.x = 5;
// LEGAL, the object's members can still be modified 
// unless explicitly declared final in the declaring class
Foo *const b = new Foo();
// a declaration of a "const" pointer
// it is possible to modify the object,
// but the pointer will constantly point
// to the object assigned to it here
final Foo b = new Foo();
// a declaration of a "final" reference
b = new Foo();
// ILLEGAL, it is not allowed to re-bind it
b = new Foo();
// ILLEGAL, it is not allowed to re-bind it
b->x = 5;
// LEGAL, the object can still be modified
b.x = 5;
// LEGAL, the object can still be modified
  • C++ obsługuje gotoinstrukcje, które mogą prowadzić do programowania kodu spaghetti . Z wyjątkiem instrukcji goto (która jest bardzo rzadko widywana w prawdziwym kodzie i bardzo odradzana), zarówno Java, jak i C++ mają w zasadzie te same struktury przepływu sterowania , zaprojektowane w celu wymuszenia ustrukturyzowanego przepływu sterowania i opierają się na instrukcjach break i continue w celu zapewnienia pewnych gotopodobne funkcje. Niektórzy komentatorzy wskazują, że te oznaczone etykietami instrukcje sterowania przepływem łamią właściwość pojedynczego punktu wyjścia programowania strukturalnego.
  • C++ zapewnia funkcje niskopoziomowe, których w Javie w większości brakuje (jednym godnym uwagi wyjątkiem jest sun.misc.UnsafeAPI do bezpośredniego dostępu do pamięci i manipulacji). W C++ wskaźniki mogą być używane do manipulowania określonymi lokalizacjami pamięci, co jest zadaniem niezbędnym do pisania niskopoziomowych komponentów systemu operacyjnego . Podobnie wiele kompilatorów C++ obsługuje asembler wbudowany . Kod języka asemblera można zaimportować do programu w C i na odwrót. Dzięki temu język C jest jeszcze szybszy. W Javie taki kod musi znajdować się w zewnętrznych bibliotekach i można uzyskać do niego dostęp tylko za pośrednictwem Java Native Interface , ze znacznym obciążeniem dla każdego wywołania.

Semantyka

  • C++ zezwala na wartości domyślne dla argumentów funkcji/metody. Java nie. Jednak przeciążanie metod może być użyte do uzyskania podobnych wyników w Javie, ale wygenerowania nadmiarowego kodu pośredniczącego.
  • Minimum kodu potrzebnego do skompilowania dla C++ to funkcja, dla Javy to klasa.
  • C++ umożliwia szereg niejawnych konwersji między typami natywnymi (w tym niektóre konwersje zawężające), a także umożliwia definiowanie niejawnych konwersji obejmujących typy zdefiniowane przez użytkownika. W Javie tylko konwersje rozszerzające między typami natywnymi są niejawne; inne konwersje wymagają jawnej składni rzutowania.
    • Wynikiem tego jest to, że choć warunki pętli ( if, whilea stan zjazd w for) w Java i C ++ zarówno spodziewać logiczną wyrażenia, kod, na przykład if(a = 5)spowoduje błąd kompilacji w Javie, ponieważ nie istnieje niejawna konwersja zwężenie z int na Boolean, ale skompiluje się w C++. Jest to przydatne, jeśli kod był literówką i if(a == 5)był zamierzony. Jednak obecne kompilatory C++ zwykle generują ostrzeżenie, gdy takie przypisanie jest wykonywane w wyrażeniu warunkowym. Podobnie samodzielne zestawienia porównawcze, np. a==5;bez skutków ubocznych, zwykle prowadzą do ostrzeżenia.
  • W przypadku przekazywania parametrów do funkcji C++ obsługuje zarówno przekazywanie przez odwołanie, jak i przekazywanie przez wartość . W Javie parametry pierwotne są zawsze przekazywane przez wartość. Typy klas, typy interfejsów i typy tablic są zbiorczo nazywane typami referencyjnymi w Javie i zawsze są przekazywane przez wartość.
  • Wbudowane typy Java mają określony rozmiar i zakres zdefiniowany przez specyfikację języka. W C++ zdefiniowano minimalny zakres wartości dla typów wbudowanych, ale dokładną reprezentację (liczbę bitów) można odwzorować na dowolne typy natywne preferowane na danej platformie.
    • Na przykład znaki Java to 16-bitowe znaki Unicode , a łańcuchy składają się z sekwencji takich znaków. C++ oferuje zarówno wąskie, jak i szerokie znaki, ale rzeczywisty rozmiar każdego z nich jest zależny od platformy, podobnie jak używany zestaw znaków. Ciągi mogą być utworzone z dowolnego typu.
    • Oznacza to również, że kompilatory C++ mogą automatycznie wybrać najbardziej wydajną reprezentację dla platformy docelowej (tj. 64-bitowe liczby całkowite dla platformy 64-bitowej), podczas gdy reprezentacja jest ustalona w Javie, co oznacza, że ​​wartości mogą być przechowywane w mniej -Efektywny rozmiar lub musi uzupełnić pozostałe bity i dodać kod, aby emulować zachowanie zmniejszonej szerokości.
  • Zaokrąglanie i precyzja wartości i operacji zmiennoprzecinkowych w C++ jest zdefiniowana przez implementację (chociaż tylko bardzo egzotyczne lub stare platformy odbiegają od standardu IEEE 754 ). Java udostępnia opcjonalny ścisły model zmiennoprzecinkowy ( strictfp ), który gwarantuje bardziej spójne wyniki na różnych platformach, jednak kosztem możliwej wolniejszej wydajności w czasie wykonywania. Jednak Java nie jest ściśle zgodna ze standardem IEEE 754. Większość kompilatorów C++ domyślnie jest częściowo zgodna ze standardem IEEE 754 (zwykle wyłączając ścisłe reguły zaokrąglania i zgłaszając wyjątki dotyczące wyników NaN), ale zapewnia opcje zgodności o różnej rygorystyczności, aby umożliwić pewną optymalizację. Jeśli oznaczymy te opcje od najmniej zgodnych do najbardziej zgodnych jako szybkie , spójne ( strictfp w Javie ), prawie-IEEE i strict-IEEE , możemy powiedzieć, że większość implementacji C++ domyślnie jest zbliżona do IEEE , z opcjami przełączania na fast lub strict -IEEE , podczas gdy Java domyślnie jest szybka z opcją przełączenia na spójne .
  • W C++ wskaźnikami można manipulować bezpośrednio jako wartościami adresów pamięci. Odwołania do Javy są wskaźnikami do obiektów. Odwołania do Javy nie pozwalają na bezpośredni dostęp do adresów pamięci ani na manipulowanie adresami pamięci za pomocą arytmetyki wskaźników. W C++ można konstruować wskaźniki do wskaźników, wskaźniki do ints i doubles oraz wskaźniki do dowolnych lokalizacji w pamięci. Odwołania Java mają dostęp tylko do obiektów, nigdy do prymitywów, innych odwołań lub dowolnych lokalizacji pamięci. W Javie pamięć może być odczytywana i zapisywana przez dowolne wartości za pomocą sun.misc.UnsafeAPI, jednak jest to przestarzałe i niezalecane.
  • W języku C++ wskaźniki mogą wskazywać na funkcje lub funkcje członkowskie ( wskaźniki funkcji ). Równoważny mechanizm w Javie wykorzystuje odwołania do obiektów lub interfejsów.
  • Za pośrednictwem obiektów alokowanych na stosie C++ obsługuje zarządzanie zasobami w zakresie , technikę stosowaną do automatycznego zarządzania pamięcią i innymi zasobami systemowymi, która obsługuje deterministyczne niszczenie obiektów. Chociaż nie można zagwarantować zarządzania zasobami w zakresie w C++ (nawet obiekty z odpowiednimi destruktorami można przydzielić za pomocą newi pozostawić nieusunięte), zapewnia skuteczny sposób zarządzania zasobami. Współdzielonymi zasobami można zarządzać za pomocą shared_ptr, wraz z weak_ptrprzerwaniem cyklicznych odwołań. Java obsługuje automatyczne zarządzanie pamięcią za pomocą wyrzucania elementów bezużytecznych, które mogą uwolnić nieosiągalne obiekty nawet w obecności cyklicznych odniesień, ale inne zasoby systemowe (pliki, strumienie, okna, porty komunikacyjne, wątki itp.) muszą być jawnie zwolnione, ponieważ wyrzucanie elementów bezużytecznych nie jest gwarantowane wystąpić natychmiast po opuszczeniu ostatniego odwołania do obiektu.
  • C++ oferuje przeciążanie operatorów zdefiniowanych przez użytkownika . Przeciążanie operatorów umożliwia typom zdefiniowanym przez użytkownika obsługę operatorów (arytmetycznych, porównań itp.), takich jak typy pierwotne, za pośrednictwem implementacji zdefiniowanych przez użytkownika dla tych operatorów. Ogólnie zaleca się zachowanie semantyki operatorów. Java nie obsługuje żadnej formy przeciążania operatorów (chociaż jej biblioteka używa operatora dodawania do łączenia ciągów).
  • Java oferuje obsługę standardowego interfejsu programowania aplikacji (API) do odbicia i dynamicznego ładowania dowolnego nowego kodu.
  • C++ obsługuje statyczne i dynamiczne łączenie plików binarnych.
  • Java ma generyki , których głównym celem jest dostarczanie kontenerów bezpiecznych dla typów. C++ ma szablony czasu kompilacji , które zapewniają bardziej rozbudowaną obsługę programowania ogólnego i metaprogramowania. Java posiada adnotacje , które umożliwiają dodawanie dowolnych niestandardowych metadanych do klas i metaprogramowanie za pomocą narzędzia do przetwarzania adnotacji .
  • Zarówno Java, jak i C++ rozróżniają typy natywne (nazywane również typami podstawowymi lub wbudowanymi ) i typy zdefiniowane przez użytkownika (nazywane również typami złożonymi ). W Javie typy natywne mają tylko semantykę wartości, a typy złożone mają tylko semantykę referencyjną. W C++ wszystkie typy mają semantykę wartości, ale można utworzyć referencję do dowolnego typu, co pozwoli na manipulowanie obiektem za pomocą semantyki referencji.
  • C++ obsługuje wielokrotne dziedziczenie dowolnych klas. W Javie klasa może wywodzić się tylko z jednej klasy, ale klasa może implementować wiele interfejsów (innymi słowy, obsługuje wielokrotne dziedziczenie typów, ale tylko pojedyncze dziedziczenie implementacji).
  • Java wyraźnie rozróżnia interfejsy i klasy. W C++ dziedziczenie wielokrotne i czysto wirtualne funkcje umożliwiają definiowanie klas, które działają prawie tak samo jak interfejsy Java, z kilkoma małymi różnicami.
  • Java obsługuje zarówno język, jak i standardowe biblioteki dla wielowątkowości . Słowo synchronized kluczowe w Javie zapewnia proste i bezpieczne blokady mutex do obsługi aplikacji wielowątkowych. Java zapewnia również solidne i złożone biblioteki do bardziej zaawansowanej synchronizacji wielowątkowej. Dopiero od C++11 istnieje zdefiniowany model pamięci dla wielowątkowości w C++ oraz obsługa bibliotek do tworzenia wątków i wielu prymitywów synchronizacji. Istnieje również wiele bibliotek innych firm do tego celu.
  • Funkcje składowe języka C++ mogą być deklarowane jako funkcje wirtualne , co oznacza, że ​​metoda, która ma zostać wywołana, jest określona przez typ obiektu w czasie wykonywania (czyli dynamiczne rozsyłanie). Domyślnie metody w C++ nie są wirtualne (tzn. opt-in virtual ). W Javie metody są domyślnie wirtualne, ale można je uczynić niewirtualnymi za pomocą finalsłowa kluczowego (tzn. opt-out virtual ).
  • Wyliczenia C++ są typami pierwotnymi i obsługują niejawną konwersję na typy całkowite (ale nie z typów całkowitych). Wyliczenia Java mogą być public static enum{enumName1,enumName2}i są używane jak klasy. Innym sposobem jest stworzenie innej klasy, która rozszerza java.lang.Enum<E>) i dlatego może definiować konstruktory, pola i metody jak każdą inną klasę. Począwszy od C++11 , C++ obsługuje również silnie wpisane wyliczenia, które zapewniają większe bezpieczeństwo typów i jawną specyfikację typu magazynu.
  • Operatory jednoargumentowe '++' i '--': w C++ "Operand powinien być modyfikowalną lwartością . [pominięty] Wynikiem jest zaktualizowany operand; jest to lwartość...", ale w Javie "dwójkowa promocja liczbowa wspomniane powyżej mogą obejmować konwersję rozpakowywania i konwersję zestawu wartości. Jeśli to konieczne, konwersja zestawu wartości {i/lub [...] konwersja z opakowania} jest stosowana do sumy przed jej zapisaniem w zmiennej.", tj. w Javie, po inicjalizacja "Integer i=2;", "++i;" zmienia referencję i poprzez przypisanie nowego obiektu, podczas gdy w C++ obiekt jest nadal taki sam.

Zarządzanie zasobami

  • Java oferuje automatyczne usuwanie śmieci , które w określonych okolicznościach można ominąć za pomocą specyfikacji Java w czasie rzeczywistym . Zarządzanie pamięcią w C++ odbywa się zwykle za pomocą konstruktorów, destruktorów i inteligentnych wskaźników . Standard C++ zezwala na wyrzucanie śmieci, ale tego nie wymaga. W praktyce wywóz śmieci jest rzadko stosowany.
  • C++ może przydzielać dowolne bloki pamięci. Java alokuje pamięć tylko poprzez tworzenie instancji obiektu. Dowolne bloki pamięci mogą być alokowane w Javie jako tablica bajtów.
  • Java i C++ używają różnych idiomów do zarządzania zasobami. Java opiera się głównie na zbieraniu śmieci, które mogą odzyskiwać pamięć, podczas gdy C++ opiera się głównie na idiomie Resource Acquisition Is Initialization (RAII). Znajduje to odzwierciedlenie w kilku różnicach między tymi dwoma językami:
    • W C++ powszechne jest alokowanie obiektów typu złożonego jako lokalnych zmiennych związanych ze stosem, które są niszczone, gdy wychodzą poza zakres. W Javie typy złożone są zawsze alokowane na stercie i zbierane przez garbage collector (z wyjątkiem maszyn wirtualnych, które używają analizy ucieczki do konwersji alokacji sterty na alokacje stosu).
    • C++ ma destruktory, podczas gdy Java ma finalizatory . Oba są wywoływane przed cofnięciem alokacji obiektu, ale znacznie się różnią. Destruktor obiektu C++ musi być wywoływany niejawnie (w przypadku zmiennych powiązanych ze stosem) lub jawnie, aby zwolnić obiekt. Destruktor wykonuje się synchronicznie tuż przed punktem programu, w którym obiekt jest zwalniany. Synchroniczne, skoordynowane deinicjowanie i cofanie alokacji w C++ spełniają zatem idiom RAII. W Javie cofanie alokacji obiektów jest niejawnie obsługiwane przez garbage collector. Finalizator obiektu Java jest wywoływany asynchronicznie jakiś czas po ostatnim dostępie i przed cofnięciem alokacji. Bardzo niewiele obiektów potrzebuje finalizatorów. Finalizator jest potrzebny tylko obiektom, które muszą gwarantować pewne oczyszczenie stanu obiektu przed cofnięciem alokacji, zazwyczaj zwalniając zasoby zewnętrzne względem JVM. Ponadto finalizatory wiążą się z poważnymi karami za wydajność i znacznie wydłużają czas potrzebny na cofnięcie alokacji obiektów, więc ich użycie jest odradzane i przestarzałe w Javie 9.
    • W przypadku RAII w C++ jeden typ zasobu jest zwykle opakowany w małą klasę, która alokuje zasób podczas budowy i zwalnia go po zniszczeniu oraz zapewnia dostęp do zasobu pomiędzy tymi punktami. Każda klasa, która zawiera tylko takie obiekty RAII, nie musi definiować destruktora, ponieważ destruktory obiektów RAII są wywoływane automatycznie, gdy obiekt tej klasy jest niszczony. W Javie bezpieczne synchroniczne cofanie alokacji zasobów można wykonać deterministycznie za pomocą konstrukcji try/catch/finally.
    • W C++ można mieć nieaktualny wskaźnik , przestarzałe odwołanie do obiektu, który został już cofnięty. Próba użycia wiszącego wskaźnika zwykle kończy się niepowodzeniem programu. W Javie garbage collector nie zniszczy obiektu, do którego się odwołuje.
    • W C++ możliwe jest posiadanie niezainicjowanych obiektów pierwotnych. Java wymusza inicjalizację domyślną.
    • W C++ możliwe jest posiadanie przydzielonego obiektu, do którego nie ma prawidłowego odniesienia. Taki nieosiągalny obiekt nie może zostać zniszczony (zwolniony) i powoduje wyciek pamięci . W przeciwieństwie do tego, w Javie obiekt nie zostanie cofnięty przez garbage collector, dopóki nie stanie się niedostępny (przez program użytkownika). ( Obsługiwane są słabe referencje , które współpracują z modułem odśmiecania pamięci Java, aby umożliwić różne mocne strony osiągalności.) Odśmiecanie w Javie zapobiega wielu wyciekom pamięci, ale przecieki są nadal możliwe w pewnych okolicznościach.

Biblioteki

  • C++ zapewnia wieloplatformowy dostęp do wielu funkcji zwykle dostępnych w bibliotekach specyficznych dla platformy. Bezpośredni dostęp z języka Java do natywnego systemu operacyjnego i funkcji sprzętowych wymaga użycia interfejsu Java Native Interface .

Czas pracy

C++ Jawa
C++ jest kompilowany bezpośrednio do kodu maszynowego, który jest następnie wykonywany bezpośrednio przez jednostkę centralną . Java jest kompilowana do kodu bajtowego, który wirtualna maszyna Java (JVM) interpretuje w czasie wykonywania. Rzeczywiste implementacje Java dokonują kompilacji just-in-time do natywnego kodu maszynowego. Alternatywnie, GNU Compiler for Java może skompilować się bezpośrednio do kodu maszynowego.
  • Ze względu na nieograniczoną ekspresyjność, cechy języka C++ niskiego poziomu (np. niesprawdzony dostęp do tablicy, surowe wskaźniki, typ punning ) nie mogą być wiarygodnie sprawdzone w czasie kompilacji lub bez narzutu w czasie wykonywania. Powiązane błędy programowania mogą prowadzić do przepełnień bufora niskiego poziomu i błędów segmentacji . Standard Template Library zapewnia abstrakcje RAII wyższego poziomu (jak wektor, listy i mapy), aby uniknąć takich błędów. W Javie błędy niskiego poziomu albo nie mogą wystąpić, albo są wykrywane przez wirtualną maszynę Javy (JVM) i zgłaszane do aplikacji w postaci wyjątku .
  • Język Java wymaga określonego zachowania w przypadku dostępu do tablicy poza granicami, co zazwyczaj wymaga sprawdzania granic dostępu do tablicy. Eliminuje to potencjalne źródło niestabilności, ale zwykle kosztem spowolnienia wykonania. W niektórych przypadkach, zwłaszcza od wersji Java 7, analiza kompilatora może udowodnić, że kontrola granic nie jest potrzebna i ją wyeliminować. C++ nie ma wymaganego zachowania w przypadku dostępu poza granice tablic natywnych, dlatego nie wymaga sprawdzania granic dla tablic natywnych. Kolekcje bibliotek standardowych C++, takie jak std::vector, oferują jednak opcjonalne sprawdzanie granic. Podsumowując, tablice Javy są „zazwyczaj bezpieczne; nieznacznie ograniczone; często mają narzuty”, podczas gdy tablice natywne C++ „mają opcjonalne narzuty; są nieco nieograniczone; są prawdopodobnie niebezpieczne”.

Szablony a generyki

Zarówno C++, jak i Java zapewniają narzędzia do programowania generycznego , szablonów i szablonów generycznych . Chociaż zostały stworzone do rozwiązywania podobnych problemów i mają podobną składnię, są zupełnie inne.

Szablony C++ Generyki Java
Klasy, funkcje, aliasy i zmienne mogą być szablonowane. Klasy i metody można uogólniać.
Parametry mogą być zmienne, dowolnego typu, wartości całkowitej, literału znakowego lub szablonu klasy. Parametry mogą być dowolnymi typami referencyjnymi, w tym typami podstawowymi w ramkach (np. Integer, Boolean...).
Podczas kompilacji dla każdego zestawu parametrów zostaną wygenerowane oddzielne wystąpienia klasy lub funkcji. W przypadku szablonów klas zostaną utworzone tylko funkcje składowe, które są używane. Jedna wersja klasy lub funkcji jest kompilowana, działa dla wszystkich parametrów typu (poprzez wymazanie typu).
Obiekty szablonu klasy utworzone z różnymi parametrami będą miały różne typy w czasie wykonywania (tj. odrębne instancje szablonu są odrębnymi klasami). Parametry typu są usuwane podczas kompilacji; obiekty klasy o różnych parametrach typu są tego samego typu w czasie wykonywania. Powoduje to inny konstruktor. Z powodu tego typu wymazywania nie jest możliwe przeciążenie metod przy użyciu różnych wystąpień klasy ogólnej.
Implementacja szablonu klasy lub funkcji musi być widoczna w jednostce tłumaczeniowej, aby można było z niej korzystać. Zwykle oznacza to posiadanie definicji w plikach nagłówkowych lub zawartych w pliku nagłówkowym. Od C++11 możliwe jest użycie szablonów zewnętrznych do oddzielnego kompilowania niektórych instancji. Aby z niej skorzystać, wystarczy sygnatura klasy lub funkcji ze skompilowanego pliku klasy.
Szablony mogą być wyspecjalizowane — dla konkretnego parametru szablonu można zapewnić oddzielną implementację. Generyki nie mogą być wyspecjalizowane.
Parametry szablonu mogą mieć argumenty domyślne . Przed C++11 było to dozwolone tylko dla klas szablonów, a nie funkcji. Parametry typu ogólnego nie mogą mieć argumentów domyślnych.
Nieobsługiwane symbole wieloznaczne. Zamiast tego zwracane typy są często dostępne jako zagnieżdżone typedefs . (Ponadto dodano słowo kluczowe C++11auto , które działa jako symbol wieloznaczny dla dowolnego typu, który można określić w czasie kompilacji). Symbole wieloznaczne obsługiwane jako parametr typu.
Brak bezpośredniej obsługi ograniczania parametrów typu, ale zapewnia to metaprogramowanie Obsługuje ograniczanie parametrów typu za pomocą „extends” i „super” odpowiednio dla górnych i dolnych granic; umożliwia wymuszanie relacji między parametrami typu.
Umożliwia tworzenie instancji obiektu o typie typu parametru. Wyklucza tworzenie instancji obiektu z typem typu parametru (oprócz odbicia).
Parametr typu szablonu klasy może być używany dla metod i zmiennych statycznych. Parametr typu klasy generycznej nie może być używany dla metod i zmiennych statycznych.
Zmienne statyczne niewspółdzielone między klasami i funkcjami o różnych typach parametrów. Zmienne statyczne współdzielone przez instancje klas o różnych typach parametrów.
Szablony klas i funkcji nie wymuszają relacji typu dla parametrów typu w ich deklaracji. Użycie nieprawidłowego parametru typu powoduje niepowodzenie kompilacji, często generując komunikat o błędzie w kodzie szablonu, a nie w kodzie użytkownika, który go wywołuje. Właściwe wykorzystanie szablonowych klas i funkcji jest uzależnione od odpowiedniej dokumentacji. Metaprogramowanie zapewnia te funkcje kosztem dodatkowego wysiłku. Pojawiła się propozycja rozwiązania tego problemu w C++11 , tzw. Concepts , planowane jest w kolejnym standardzie. Klasy ogólne i funkcje mogą wymuszać relacje typów dla parametrów typu w ich deklaracji. Użycie nieprawidłowego parametru typu powoduje błąd typu w kodzie, który go używa. Operacje na typach sparametryzowanych w kodzie generycznym są dozwolone tylko w sposób, który można zagwarantować za pomocą deklaracji. Skutkuje to większym bezpieczeństwem typu kosztem elastyczności.
Szablony są kompletne pod względem Turinga (zobacz metaprogramowanie szablonów ). Generyki są również kompletne pod względem Turinga

Różnorodny

  • Java i C++ używają różnych środków do dzielenia kodu na wiele plików źródłowych. Java używa systemu pakietów, który dyktuje nazwę pliku i ścieżkę dla wszystkich definicji programów. Jego kompilator importuje wykonywalne pliki klas . C++ używa systemu dołączania kodu źródłowego pliku nagłówkowego do współdzielenia deklaracji między plikami źródłowymi.
  • Skompilowane pliki kodu Java są zwykle mniejsze niż pliki kodu w C ++, ponieważ kod bajtowy Java jest zwykle bardziej kompaktowy niż natywny kod maszynowy, a programy Java nigdy nie są statycznie połączone.
  • Kompilacja C++ zawiera dodatkową fazę wstępnego przetwarzania tekstu , podczas gdy Java nie. Dlatego niektórzy użytkownicy dodają fazę przetwarzania wstępnego do swojego procesu kompilacji, aby zapewnić lepszą obsługę kompilacji warunkowej.
  • Operatory dzielenia i modulo w Javie są dobrze zdefiniowane, aby obcinać do zera. C++ (przed C++11 ) nie określa, czy te operatory obcinają do zera, czy "obcinają do nieskończoności". -3/2 zawsze będzie wynosić -1 w Javie i C++11, ale kompilator C++03 może zwrócić -1 lub -2, w zależności od platformy. C99 definiuje dzielenie w taki sam sposób jak Java i C++11. Oba języki gwarantują (gdzie aib są typami całkowitymi), że (a/b)*b + (a%b) == adla wszystkich aib (b != 0). Wersja C++03 będzie czasami szybsza, ponieważ może wybrać dowolny tryb obcinania, który jest natywny dla procesora.
  • Rozmiary typów liczb całkowitych są zdefiniowane w Javie (int to 32-bitowy, long to 64-bitowy), podczas gdy w C++ rozmiar liczb całkowitych i wskaźników jest zależny od kompilatora i interfejsu binarnego aplikacji (ABI) w ramach określonych ograniczeń. W ten sposób program Java będzie zachowywał się spójnie na różnych platformach, podczas gdy program C++ może wymagać dostosowania na niektórych platformach, ale może działać szybciej z bardziej naturalnymi rozmiarami liczb całkowitych dla platformy lokalnej.

Przykład porównujący C++ i Javę istnieje w Wikibooks .

Wydajność

Oprócz uruchamiania skompilowanego programu Java, na komputerach, na których działają aplikacje Java, musi być również uruchomiona wirtualna maszyna Java (JVM), podczas gdy skompilowane programy w języku C++ mogą być uruchamiane bez zewnętrznych aplikacji. Wczesne wersje Javy były znacznie lepsze od statycznie kompilowanych języków, takich jak C++. Dzieje się tak, ponieważ instrukcje programu tych dwóch blisko spokrewnionych języków mogą kompilować się do kilku instrukcji maszynowych za pomocą C++, podczas gdy kompilują się w kilka kodów bajtowych obejmujących kilka instrukcji maszynowych, z których każda jest interpretowana przez JVM. Na przykład:

Instrukcja Java/C++ Wygenerowany kod C++ (x86) Kod bajtowy wygenerowany przez Javę
vector[i]++;
mov edx,[ebp+4h]
mov eax,[ebp+1Ch]
inc dword ptr [edx+eax*4]
aload_1
wczytuję_2
dup2
iaload
iconst_1
Dodaję
iastore

Ponieważ optymalizacja wydajności jest bardzo złożonym zagadnieniem, bardzo trudno jest ogólnie oszacować różnicę wydajności między C++ i Javą, a większość testów jest zawodna i stronnicza. Biorąc pod uwagę bardzo różne natury języków, ostateczne różnice jakościowe są również trudne do narysowania. Krótko mówiąc, w Javie istnieją nieodłączne nieefektywności i twarde ograniczenia optymalizacji, biorąc pod uwagę, że w dużym stopniu opiera się ona na elastycznych abstrakcjach wysokiego poziomu, jednak użycie potężnego kompilatora JIT (jak w nowoczesnych implementacjach JVM) może złagodzić niektóre problemy. W każdym razie, jeśli nieefektywność Javy jest zbyt duża, skompilowany kod C lub C++ można wywołać z Javy za pośrednictwem JNI.

Niektóre nieefektywności, które są nieodłączne od języka Java, obejmują głównie:

  • Wszystkie obiekty są alokowane na stercie. Chociaż alokacja jest niezwykle szybka w nowoczesnych maszynach wirtualnych JVM przy użyciu „alokacji wypukłej”, która działa podobnie do alokacji stosu, na wydajność nadal może mieć negatywny wpływ wywołanie modułu odśmiecania pamięci. Nowoczesne kompilatory JIT łagodzą ten problem w pewnym stopniu dzięki analizie ucieczki lub wykrywaniu ucieczki w celu alokacji niektórych obiektów na stosie, ponieważ Oracle JDK 6.
  • Projekty krytyczne dla wydajności, takie jak wydajne systemy baz danych i biblioteki wiadomości, musiały korzystać z wewnętrznych nieoficjalnych interfejsów API, takich jak sun.misc.Unsafeuzyskanie dostępu do ręcznego zarządzania zasobami i możliwość alokacji stosu; efektywne manipulowanie pseudowskaźnikami.
  • Wymagana duża ilość rzutowania w czasie wykonywania, nawet przy użyciu standardowych kontenerów, powoduje spadek wydajności. Jednak większość z tych rzutowań jest statycznie eliminowana przez kompilator JIT.
  • Gwarancje bezpieczeństwa wiążą się z kosztami czasu pracy. Na przykład kompilator jest zobowiązany do umieszczenia w kodzie odpowiednich kontroli zakresu. Ochrona dostępu do każdej tablicy za pomocą sprawdzania zakresu nie jest wydajna, więc większość kompilatorów JIT spróbuje wyeliminować je statycznie lub przenosząc je z wewnętrznych pętli (chociaż większość kompilatorów natywnych dla C++ zrobi to samo, gdy opcjonalnie zostaną użyte sprawdzanie zakresu).
  • Brak dostępu do szczegółów niskopoziomowych uniemożliwia programiście ulepszenie programu tam, gdzie kompilator nie jest w stanie tego zrobić.
  • Obowiązkowe użycie semantyki referencyjnej dla wszystkich typów zdefiniowanych przez użytkownika w Javie może wprowadzać duże ilości zbędnych pośrednich (lub skoków) pamięci (chyba że kompilator JIT wykluczy je), co może prowadzić do częstych braków w pamięci podręcznej (czyli thrashingu pamięci podręcznej ). Ponadto optymalizacja pamięci podręcznej, zwykle za pomocą struktur danych i algorytmów uwzględniających pamięć podręczną lub nieświadomych pamięci podręcznej , często może prowadzić do poprawy wydajności o rząd wielkości, a także do uniknięcia degeneracji złożoności czasowej, która jest charakterystyczna dla wielu algorytmów pesymizacji pamięci podręcznej i jest dlatego jedna z najważniejszych form optymalizacji; semantyka referencyjna, nakazana w Javie, uniemożliwia realizację takich optymalizacji w praktyce (ani przez programistę, ani kompilator JIT).
  • Garbage collection , ponieważ ta forma automatycznego zarządzania pamięcią wprowadza obciążenie pamięci.

Istnieje jednak szereg korzyści z projektowania Javy, niektóre zdały sobie sprawę, inne tylko teoretyzując:

  • Odśmiecanie Java może mieć lepszą spójność pamięci podręcznej niż zwykłe użycie malloc / new do alokacji pamięci. Niemniej jednak istnieją argumenty, że oba alokatory w równym stopniu fragmentują stertę i żaden z nich nie wykazuje lepszej lokalizacji pamięci podręcznej. Jednak w C++ alokacja pojedynczych obiektów na stercie jest rzadka, a duże ilości pojedynczych obiektów są zwykle alokowane w blokach za pośrednictwem kontenera STL i/lub małego alokatora obiektów.
  • Kompilacja w czasie wykonywania może potencjalnie wykorzystywać informacje o platformie, na której wykonywany jest kod, w celu efektywniejszego ulepszania kodu. Jednak większość najnowocześniejszych kompilatorów natywnych (C, C++ itp.) generuje wiele ścieżek kodu, aby wykorzystać pełne możliwości obliczeniowe danego systemu. Można również wysunąć odwrotny argument, że natywne kompilatory mogą lepiej wykorzystywać optymalizację i zestawy instrukcji specyficzne dla architektury niż wieloplatformowe dystrybucje JVM.
  • Kompilacja w czasie wykonywania pozwala na bardziej agresywne wstawianie funkcji wirtualnych niż jest to możliwe w przypadku kompilatora statycznego, ponieważ kompilator JIT ma więcej informacji o wszystkich możliwych obiektach docelowych wywołań wirtualnych, nawet jeśli znajdują się one w różnych dynamicznie ładowanych modułach. Obecnie dostępne implementacje JVM nie mają problemu z inlineniem większości wywołań monomorficznych, głównie monomorficznych i dimorficznych, a trwają badania nad wywołaniami inline również megamorficznymi, dzięki niedawnym ulepszeniom dynamicznym wywołań dodanym w Javie 7. Inlining może pozwolić na dalszą optymalizację, taką jak wektoryzacja pętli lub rozwijanie pętli , co skutkuje ogromnym ogólnym wzrostem wydajności.
  • W Javie synchronizacja wątków jest wbudowana w język, więc kompilator JIT może potencjalnie, poprzez analizę ucieczki, uniknąć blokad, znacznie poprawić wydajność naiwnego kodu wielowątkowego.

Ponadto w C++ występują pewne problemy z wydajnością:

  • Pozwolenie wskaźnikom na wskazywanie dowolnego adresu może utrudnić optymalizację ze względu na możliwość tworzenia aliasów wskaźników .
  • Ponieważ kod generowany z różnych instancji tego samego szablonu klasy w C++ nie jest współdzielony (jak w przypadku generyków z wymazanymi typami w Javie), nadmierne używanie szablonów może prowadzić do znacznego zwiększenia rozmiaru kodu wykonywalnego ( code bloat ). Jednak ponieważ szablony funkcji są agresywnie wbudowane, mogą czasami zmniejszyć rozmiar kodu, ale co ważniejsze, pozwalają na bardziej agresywną analizę statyczną i optymalizację kodu przez kompilator, częściej czyniąc je bardziej wydajnymi niż kod nieszablonowy. W przeciwieństwie do tego, generyki Javy są z konieczności mniej wydajne niż kod niegenerowany.
  • Ponieważ w tradycyjnym kompilatorze C++ dynamiczne łączenie jest wykonywane po wygenerowaniu i zoptymalizowaniu kodu w C++, wywołania funkcji obejmujące różne moduły dynamiczne nie mogą być wbudowane. Jednak nowoczesne kompilatory C ++, takie jak MSVC i Clang + LLVM, oferują opcje generowania kodu w czasie linkowania, które umożliwiają kompilację modułów do formatów pośrednich, co pozwala na inlining na końcowym etapie linkowania.

Oficjalny standard i odniesienie do języka

Specyfikacja językowa

Język C++ jest zdefiniowany przez ISO/IEC 14882 , standard ISO , który jest publikowany przez komitet ISO/IEC JTC1/SC22/WG21 . Dostępna jest również najnowsza, postandaryzacyjna wersja robocza C++17 .

Język C++ ewoluuje poprzez otwarty komitet sterujący zwany Komitetem Standardów C++. W skład komitetu wchodzą twórca C++ Bjarne Stroustrup , pomysłodawca Herb Sutter i inne wybitne osobistości, w tym wielu przedstawicieli przemysłu i grup użytkowników (tj. interesariuszy). Jako otwarty komitet każdy może dołączyć, uczestniczyć i wnosić propozycje dotyczące nadchodzących wydań standardu i specyfikacji technicznych. Komitet ma obecnie na celu wydawanie nowego standardu co kilka lat, chociaż w przeszłości procesy ścisłego przeglądu i dyskusje oznaczały dłuższe opóźnienia między publikacją nowych standardów (1998, 2003 i 2011).

Język Java jest zdefiniowany w specyfikacji języka Java , książce wydanej przez Oracle.

Język Java nieustannie ewoluuje poprzez proces zwany Java Community Process , a światową społeczność programistów reprezentuje grupa ludzi i organizacji — członkowie Java Community — która jest aktywnie zaangażowana w ulepszanie języka, wysyłając publiczne żądania — Żądania specyfikacji Java — które muszą przejść formalne i publiczne recenzje, zanim zostaną zintegrowane z językiem.

Brak sztywnego standardu dla Javy i nieco bardziej niestabilny charakter jej specyfikacji były stałym źródłem krytyki ze strony interesariuszy, którzy chcą większej stabilności i konserwatyzmu przy dodawaniu nowych funkcji językowych i bibliotecznych. W przeciwieństwie do tego, komisja C++ jest również stale krytykowana z odwrotnego powodu, tj. zbyt surowego i konserwatywnego oraz zbyt długiego wydawania nowych wersji.

Znaki towarowe

„C++” nie jest znakiem towarowym żadnej firmy ani organizacji i nie jest własnością żadnej osoby. „Java” jest znakiem towarowym firmy Oracle Corporation .

Bibliografia

Zewnętrzne linki