it-swarm.dev

Wie unterscheidet sich C von C ++?

Viele Leute haben gesagt, dass C++ eine völlig andere Sprache als C ist, aber Bjarne selbst hat gesagt, dass C++ eine Sprache ist, die von C erweitert wird, daher ist dort das ++ kommt von. Warum sagen alle immer wieder, dass C und C++ völlig unterschiedliche Sprachen sind? Inwiefern unterscheidet sich C von C++ von den erweiterten Funktionen in C++?

21
Joshua Partogi

In den 1980er Jahren, als die C++ - Entwicklung gerade erst begann, war C++ fast eine richtige Obermenge von C. So fing alles an.
Im Laufe der Zeit haben sich jedoch sowohl C als auch C++ weiterentwickelt und sind voneinander abgewichen, obwohl die Kompatibilität zwischen den Sprachen immer als wichtig angesehen wurde.

Darüber hinaus haben die technischen Unterschiede zwischen C und C++ dazu geführt, dass die typischen Redewendungen in diesen Sprachen und das, was als "gute Praxis" angesehen wird, noch mehr voneinander abweichen.

Dies ist der treibende Faktor hinter Menschen, die Dinge wie "Es gibt keine Sprache wie C/C++" oder "C und C++ sind zwei verschiedene Sprachen" sagen. Obwohl es möglich ist, Programme zu schreiben, die sowohl für einen C- als auch für einen C++ - Compiler akzeptabel sind, wird der Code im Allgemeinen weder als Beispiel für guten C-Code noch als Beispiel für guten C++ - Code angesehen.

Stroustrup selbst antwortet darauf in seine FAQ :

C++ ist ein direkter Nachkomme von C, der fast das gesamte C als Teilmenge beibehält. C++ bietet eine stärkere Typprüfung als C und unterstützt direkt einen größeren Bereich von Programmierstilen als C. C++ ist "ein besseres C" in dem Sinne, dass es die mit C durchgeführten Programmierstile mit besserer Typprüfung und mehr Unterstützung für Notationen (ohne Verlust) unterstützt der Effizienz). Im gleichen Sinne ist ANSI C ein besseres C als K & R C. Darüber hinaus unterstützt C++ Datenabstraktion, objektorientierte Programmierung und generische Programmierung.

Es ist die Unterstützung für objektorientierte Programmierung und generische Programmierung, die C++ "völlig anders" macht als C. Sie können fast reines C schreiben und es dann mit a kompilieren C++ - Compiler (solange Sie sich um die strengere Typprüfung kümmern). Aber dann schreiben Sie immer noch C - Sie schreiben nicht C++.

Wenn Sie C++ schreiben, nutzen Sie die objektorientierten Funktionen und Vorlagenfunktionen, und das entspricht nicht dem, was Sie in C sehen würden.

20
Dean Harding

Einfach ausgedrückt ist das, was in C als idiomatisch angesehen wird, in C++ definitiv nicht idiomatisch.

C und C++ sind in der Praxis sehr unterschiedliche Sprachen, da sie von Menschen verwendet werden. C zielt auf Minimalismus ab, wobei C++ eine sehr komplexe Sprache mit vielen Funktionen ist.

Es gibt auch einige praktische Unterschiede: C kann leicht aus nahezu jeder Sprache aufgerufen werden und definiert häufig den ABI einer Plattform, während C++ in anderen Bibliotheken nur schwer zu verwenden ist. Die meisten Sprachen haben ein FFI oder eine Schnittstelle in C, sogar Sprachen, die in C++ implementiert sind (z. B. Java).

13

Abgesehen von der offensichtlichen Tatsache, dass C++ objektorientierte Programmierung unterstützt, haben Sie hier Ihre Antwort: http://en.wikipedia.org/wiki/Compatibility_of_C_and_C++

Dieser Artikel enthält Codebeispiele, die Dinge zeigen, die in C in Ordnung sind, aber nicht in C++. Zum Beispiel:

int *j = malloc(sizeof(int) * 5); /* Implicit conversion from void* to int* */

Das Portieren eines C-Programms nach C++ ist häufig unkompliziert und besteht hauptsächlich aus der Behebung von Kompilierungsfehlern (Hinzufügen von Casts, neuen Schlüsselwörtern usw.).

4
Martin Wickman

C++ fügt C nicht nur neue Funktionen, sondern auch neue Konzepte und neue Redewendungen hinzu. Auch wenn C++ und C eng miteinander verbunden sind, bleibt die Tatsache bestehen, dass Sie im Stil dieser Sprache denken müssen, um effektiv in einer Sprache zu schreiben. Selbst der beste C-Code kann die unterschiedlichen Stärken und Redewendungen von C++ nicht nutzen und ist daher eher als schlecht C++ - Code.

2
Jon Purdy

Die "erweiterten Funktionen" lassen Sie es wie in C++ klingen, sie fügten hinzu, verschiedene Makros oder so und das war's. Die "erweiterten Funktionen" in C++ sind ein vollständige Überarbeitung der Sprache und ersetzen die besten C-Praktiken vollständig, da die neuen C++ - Funktionen so viel besser sind als die ursprünglichen C-Funktionen, dass die ursprünglichen C-Funktionen vollständig und vollständig sind in den allermeisten Fällen völlig überflüssig. Die Annahme, dass C++ lediglich C erweitert, bedeutet, dass ein moderner Kampfpanzer ein Buttermesser erweitert, um Krieg zu führen.

2
DeadMG

Der Unterschied besteht darin, dass Sie in C prozedural und in C++ objektorientiert denken. Die Sprachen sind ziemlich ähnlich, aber der Ansatz ist sehr unterschiedlich.

1
Ant

Während C++ syntaktisch eine Supermenge von C sein kann - d. H. Jedes Konstrukt eines C-Programms kann vom C++ - Compiler kompiliert werden.

Sie schreiben jedoch fast nie ein C++ - Programm so, wie Sie es mit einem C-Programm getan hätten. Die Liste kann endlos sein oder jemand sollte einfach mehr Nachforschungen anstellen, um sie als erschöpfende Berichte zu formulieren. Ich setze jedoch einige Hinweise, die die Hauptunterschiede ausmachen.

Der Punkt des aktuellen Beitrags ist, dass C++ die folgenden Funktionen hat, die ein guter C++ - Programmierer als Best Practices für die Programmierung verwenden muss, obwohl C-Äquivalente kompiliert werden können.

Wie soll es in C++ über C gemacht werden

  1. Klassen & Vererbung. Das sind die wichtigsten Unterschiede, die eine systematische Objektorientierung ermöglichen, die den Programmierausdruck sehr leistungsfähig macht. Ich denke - dieser Punkt bedarf keiner besseren Erklärung. Wenn Sie sich in C++ befinden - fast immer - sollten Sie besser Klassen verwenden.

  2. Privatisierung - Klassen und sogar Strukturen haben private Mitglieder. Dies ermöglicht die Kapselung einer Klasse. Das Äquivalent in C besteht darin, das Objekt als void * für die Anwendung zu typisieren, sodass die Anwendung keinen Zugriff auf interne Variablen hat. In C++ können Sie jedoch Elemente mit öffentlichen und privaten Klassen haben.

  3. Als Referenz übergeben. C++ ermöglicht Änderungen basierend auf Referenzen, für die übergebene Zeiger erforderlich sind. Pass-by-Reference hält den Code sehr sauber und sicherer gegen Zeigergefahren. Sie übergeben auch einen Zeiger im C-Stil und das funktioniert - aber wenn Sie in C++ sind, sind Sie besser dran, solange

  4. neu & löschen gegen malloc und kostenlos. Die Anweisungen new () und delete () weisen nicht nur Speicher zu und weisen die Zuordnung auf, sondern ermöglichen auch die Ausführung von Code als Teil des Zerstörers, der in einer Kette aufgerufen werden soll. Wenn Sie C++ verwenden, ist es eigentlich SCHLECHT, malloc und free zu verwenden.

  5. E/A-Typen und Überladung von Operatoren Durch Überladung von Operatoren wird Code lesbar oder intuitiver, wenn dies gut gemacht wird. Gleiches gilt für << und >> io-Operatoren. Der C-Weg, dies zu tun, wäre die Verwendung von Funktionszeigern - aber es ist chaotisch und nur für fortgeschrittene Programmierer.

  6. Verwenden von "Zeichenfolge". Das Zeichen * von C funktioniert überall. C und C++ sind also ziemlich gleich. Wenn Sie sich jedoch in C++ befinden, ist es immer viel besser (und sicherer), String-Klassen zu verwenden, die Sie vor den Gefahren des Überlaufens von Arrays bewahren, die fast alles sind.

Funktionen, von denen ich in C++ immer noch kein Fan wäre 1. Vorlagen - Obwohl ich in vielen Codes keine schweren Vorlagen verwende, kann es sich für Bibliotheken als sehr leistungsfähig herausstellen. In C gibt es fast kein Äquivalent dazu. Aber an einem normalen Tag - besonders wenn Sie mathematisch fehlen.

  1. Intelligente Zeiger - Ja, sie sind sehr intelligent! Und wie die meisten intelligenten Dinge - sie fangen gut an und werden später chaotisch! Ich benutze es nicht so gerne

Dinge, die ich an C mag und in C++ vermisse

  1. Polymorphe Algorithmen unter Verwendung von Funktionszeigern. Wenn Sie in C komplexe Algorithmen ausführen, können Sie manchmal eine Reihe von Funktionszeigern verwenden. Dies macht echten Polymorphismus auf mächtige Weise. Wenn Sie in C++ sind, können Sie [~ # ~] [~ # ~] Funktionszeiger verwenden - aber das ist schlecht. Sie sollten nur Methoden verwenden - sonst sollten Sie darauf vorbereitet sein, chaotisch zu werden. Die einzige Form des Polymorphismus in C++ - Klassen ist das Überladen von Funktionen und Operatoren, aber das ist ziemlich einschränkend.

  2. Einfache Fäden. Wenn Sie Threads erstellen, handelt es sich um Pthreads - dies ist recht einfach und überschaubar. Es wird, wenn Sie Threads erstellen müssen, die für die Klassen "privat" sein sollen (damit sie Zugriff auf private Mitglieder haben). Es gibt Boost-Frameworks - aber nichts in grundlegendem C++.

Dipan.

0
Dipan Mehta

Bestimmte Sprachfunktionen, auch wenn es sich um Ergänzungen handelt, können die Art und Weise ändern, in der die Sprache praktisch verwendet werden muss. Betrachten Sie als ein Beispiel diesen Fall:

lock_mutex(&mutex);

// call some functions
...

unlock_mutex(&mutex);

Wenn dieser obige Code das Aufrufen von in C++ implementierten Funktionen beinhaltet, könnten wir in eine Welt voller Probleme geraten, da jeder dieser Funktionsaufrufe möglicherweise ausgelöst wird und wir den Mutex in diesen außergewöhnlichen Pfaden niemals entsperren werden.

Destruktoren sind nicht mehr praktisch, um Programmierern zu helfen, zu diesem Zeitpunkt nicht zu vergessen, Ressourcen freizugeben/freizugeben. RAII wird zu einer praktischen Anforderung, da es menschlich nicht machbar ist, jede einzelne Codezeile vorwegzunehmen, die nicht triviale Beispiele einbringen kann (ganz zu schweigen davon, dass diese Zeilen möglicherweise nicht jetzt, sondern später mit Änderungen ausgelöst werden). Nehmen Sie ein anderes Beispiel:

void f(const Foo* f1)
{
    Foo f2;
    memcpy(&f2, f1, sizeof f2);
    ...
}

Solcher Code ist in C zwar im Allgemeinen harmlos, in C++ jedoch wie ein Höllenfeuer, da das memcpy über die Bits und Bytes dieser Objekte planiert und Dinge wie Kopierkonstruktoren umgeht. Solche Funktionen wie memset, realloc, memcpy usw., während tägliche Tools unter C-Entwicklern es gewohnt sind, Dinge auf eine ziemlich homogene Weise von Bits und Bytes im Speicher zu betrachten, sind nicht harmonisch mit dem komplexeren und reichhaltigeren Typsystem von C++. C++ fördert eine viel abstraktere Ansicht von benutzerdefinierten Typen.

Diese Art von Dingen erlaubt es C++ also nicht länger, dass jeder, der es richtig verwenden möchte, es als bloße "Obermenge" von C betrachtet. Diese Sprachen erfordern eine ganz andere Denkweise, Disziplin und Denkweise, um am effektivsten zu verwenden .

Ich bin nicht in dem Lager, in dem C++ in jeder Hinsicht besser ist, und tatsächlich sind die meisten meiner Lieblingsbibliotheken von Drittanbietern aus irgendeinem Grund C-Bibliotheken. Ich weiß nicht genau warum, aber C-Bibliotheken sind eher minimalistischer Natur (vielleicht weil sich die Entwickler aufgrund des Fehlens eines so umfangreichen Systems mehr darauf konzentrieren, die erforderliche minimale Funktionalität bereitzustellen, ohne große und vielschichtige Abstraktionen zu erstellen). Obwohl ich oft nur C++ - Wrapper um sie herum lege, um ihre Verwendung für meine Zwecke zu vereinfachen und anzupassen, ist mir diese minimalistische Natur auch dann vorzuziehen. Ich liebe den Minimalismus als attraktives Merkmal einer Bibliothek für diejenigen, die sich die zusätzliche Zeit nehmen, um nach solchen Eigenschaften zu suchen, und vielleicht ermutigt C dies, schon allein aufgrund der Tatsache, dass solch ein großer, vielschichtiger und abstrakter Code ein wäre echte PITA in C. zu entwickeln.

Ich bevorzuge C++ weitaus häufiger als nicht, aber ich muss tatsächlich ziemlich häufig C-APIs verwenden, um die größtmögliche Binärkompatibilität (und FFIs) zu gewährleisten, obwohl ich sie häufig in C++ implementiere, obwohl ich C für die Header verwende. Aber manchmal, wenn Sie wirklich auf niedriger Ebene arbeiten, wie auf der Ebene eines Speicherzuweisers oder einer Datenstruktur auf sehr niedriger Ebene (und ich bin sicher, dass es unter denen, die eingebettete Programmierung betreiben, weitere Beispiele gibt), kann es manchmal hilfreich sein, dies zu tun Sie können davon ausgehen, dass bei den Typen und Daten, mit denen Sie arbeiten, bestimmte Funktionen wie vtables, costructors und destructors fehlen, sodass wir sie als Bits und Bytes behandeln können, um sie zu mischen, zu kopieren, freizugeben und neu zuzuweisen. Bei Problemen auf ganz niedriger Ebene kann es manchmal hilfreich sein, mit einem viel einfacheren Typsystem zu arbeiten, das C bereitstellt, und natürlich neigt es dazu, schneller zu bauen und so weiter.

Eine Klarstellung

Ein interessanter Kommentar hier, auf den ich etwas ausführlicher antworten wollte (ich finde, die Kommentare hier sind so streng in Bezug auf die Zeichenbeschränkung):

memcpy(&f2, f1, sizeof f2); ist in C auch "Höllenfeuer-Chaos", wenn Foo Zeiger besitzt, oder ist noch schlimmer, da Ihnen auch die Werkzeuge fehlen, um damit umzugehen.

Das ist ein fairer Punkt, aber alles, worauf ich mich konzentriere, konzentriert sich hauptsächlich auf das C++ - Typsystem und auch auf RAII. Einer der Gründe, warum solche Arten von Röntgen-Byte-Kopieren memcpy oder qsort in C weniger praktisch sind, ist die Zerstörung von f1 Und f2 Sind explizit (wenn sie überhaupt eine nicht triviale Zerstörung benötigen), während Destruktoren implizit und automatisiert werden, wenn sie sich in das Bild bewegen (oft mit großem Wert für die Entwickler). Das ist nicht einmal ein versteckter Zustand wie vptrs und so weiter, über den solche Funktionen sofort hinwegfallen würden. Wenn f1 Zeiger besitzt und f2 Sie in einem temporären Kontext flach kopiert, ist dies kein Problem, wenn wir nicht versuchen, diese Zeiger ein zweites Mal explizit freizugeben. Mit C++ ist dies etwas, was der Compiler automatisch tun möchte.

Und das wird größer , wenn typischerweise in C, " If Foo hat eigene Zeiger ", weil die für die Ressourcenverwaltung erforderliche explizite Aussage es oft schwieriger macht, etwas zu übersehen, während wir in C++ eine UDT nicht mehr trivial konstruierbar/zerstörbar machen können, indem wir sie lediglich dazu bringen, eine beliebige Mitgliedsvariable zu speichern, die nicht ' t trivial konstruierbar/zerstörbar (auf eine Weise, die im Allgemeinen wiederum sehr hilfreich ist, aber nicht, wenn wir versucht sind, Funktionen wie memcpy oder realloc zu verwenden).

Mein Hauptpunkt ist nicht, zu versuchen, irgendeinen Nutzen dieser expliziten Aussage zu argumentieren (ich würde sagen, wenn es welche gibt, werden sie fast immer durch die Nachteile der damit verbundenen erhöhten Wahrscheinlichkeit menschlicher Fehler belastet), sondern nur zu sagen Funktionen wie memcpy und memmove und qsort und memset und realloc usw. haben in einer Sprache mit so reichen UDTs keinen Platz Funktionen und Fähigkeiten wie C++. Obwohl sie unabhängig davon existieren, wäre es meiner Meinung nach nicht allzu umstritten zu sagen, dass die überwiegende Mehrheit der C++ - Entwickler klug wäre, solche Funktionen wie die Pest zu vermeiden, während dies in C sehr tägliche Arten von Funktionen sind, und ich ' d argumentieren, dass sie in C weniger Probleme aufwerfen, aus dem einfachen Grund, dass sein Typensystem viel grundlegender und vielleicht "dümmer" ist. Das Röntgen von C-Typen und deren Behandlung als Bits und Bytes ist fehleranfällig. Dies in C++ zu tun, ist wohl geradezu falsch, da solche Funktionen gegen sehr grundlegende Merkmale der Sprache und deren Ermutigung durch das Typsystem kämpfen.

Das ist für mich jedoch der größte Reiz von C, insbesondere in Bezug auf die Interoperabilität von Sprachen. Es wäre sehr viel schwieriger, so etwas wie C #s FFI dazu zu bringen, das vollständige Typensystem und die Sprachfunktionen von C++ bis hin zu Konstruktoren, Destruktoren, Ausnahmen, virtuellen Funktionen, Funktions-/Methodenüberladung, Operatorüberladung und all den verschiedenen Arten von zu verstehen Vererbung usw. Mit C ist es eine relativ dümmer Sprache, die in Bezug auf APIs so Standard geworden ist, dass viele verschiedene Sprachen direkt über FFIs oder indirekt über einige C-API-Exportfunktionen in einer gewünschten Form importiert werden können (z. B. Java Native Interface). Und hier bleibt mir meistens keine andere Wahl, als C zu verwenden, da diese Sprachinteroperabilität in unserem Fall eine praktische Voraussetzung ist (obwohl ich oft nur C-Schnittstellen mit dahinter stehenden C++ - Implementierungen schreibe).

Aber weißt du, ich bin ein Pragmatiker (oder zumindest strebe ich danach). Wenn C diese übelste und gottesfürchtigste, fehleranfälligste, böse Sprache wäre, behaupteten einige meiner C++ - Enthusiasten, dies zu sein (und ich würde mich selbst als C++ - Enthusiasten bezeichnen, außer dass dies irgendwie nicht zu einem Hass auf C meinerseits geführt hat (im Gegenteil, es hatte den gegenteiligen Effekt auf mich, dass ich beide Sprachen in ihrer eigenen Hinsicht und in ihren Unterschieden besser schätze), dann würde ich erwarten, dass dies in der realen Welt in Form einiger der fehlerhaftesten und undichtesten und und unzuverlässige Produkte und Bibliotheken werden in C geschrieben. Und das finde ich nicht. Ich mag Linux, ich mag Apache, Lua, zlib, ich finde OpenGL erträglich für sein langes Erbe gegen solche sich verändernden Hardwareanforderungen, Gimp, libpng, Kairo usw. Zumindest scheint die Hürde, die die Sprache aufwirft, keine Sackgassen zu sein Einige coole Bibliotheken und Produkte in kompetenten Händen zu schreiben, und das ist wirklich alles, woran ich interessiert bin. Ich war also noch nie so interessiert an den leidenschaftlichsten Sprachkriegen, außer um einen pragmatischen Appell zu machen und zu sagen: "Hey, da ist es coole Sachen da draußen! Lass uns lernen, wie sie es geschafft haben und vielleicht gibt es coole Lektionen, die nicht so spezifisch für die Redewendung der Sprache sind, dass wir sie auf die Sprache (n) zurückbringen können, die wir verwenden. " :-D

0
Dragon Energy