Home | Lehre | Videos | Texte | Vorträge | Software | Person | Impressum, Datenschutzerklärung | ![]()
Stand: 2025-04-14, erzeugt von ChatGPT DeepResearch, redigiert/korrigiert/ergänzt von Jörn Loviscach und ChatGPT 4o, überprüft mit Gemini 2.5 Pro Experimental 03-25
| Aspekt | C | C++ | Python |
|---|---|---|---|
| Grundprinzip | C ist eine kompakte, prozedurale, typischerweise kompilierte Sprache ohne Klassen oder Objekte. Variablen müssen vor der Nutzung typisiert und deklariert werden. C ist sehr nahe an der Art, wie der Prozessor die Programme ausführt, was typischerweise zu kleineren, schnelleren und in Rechenleistung und Speicherplatz sparsamen Programmen führt, aber beim Programmieren Komfort kostet. | C++ erweitert C um Objektorientierung (Klassen, Vererbung, Polymorphie). Es ist ebenfalls kompiliert und erlaubt sowohl prozedurales als auch OOP-Paradigma. C++ kann in Ausführungsgeschwindigkeit und Speicherbedarf oft mit C konkurrieren, unterstützt aber wesentlich elegantere Programmierstile. | Python ist eine typischerweise interpretierte, dynamisch typisierte Skriptsprache. (Allerdings wird es je nach Implementierung auch kompiliert.) Variablen sind Namen für Objekte und können verschiedene Typen annehmen, ohne Deklaration. Python unterstützt prozedurales, objektorientiertes und funktionales Programmieren. Python bietet großen Komfort beim Programmieren, benötigt dafür aber viel Rechenleistung und Speicherplatz. Aufwendige Rechnungen (zum Beispiel für KI) verlagert man deshalb in Bibliotheken, die etwa in C geschrieben sind. |
| Typisierung | Statisch und schwach: Variablen haben feste Typen
(z. B. int, char), die der Compiler prüft. In
C gibt es erst seit C99 einen separaten Bool-Typ; Nicht-Null-Werte
gelten als „wahr“. |
Statisch und schwach: Ähnlich wie C (z. B.
int, double). C++ führt einen eigenen
bool-Typ ein (mit Werten
true/false). Die Typprüfung erfolgt zur
Compile-Zeit; implizite Typkonvertierungen sind möglich (z. B. int zu
double). |
Dynamisch und stark: Typen werden erst zur Laufzeit
erkannt; eine Variable kann zunächst eine Zahl und später einen String
halten. Gleichzeitig ist Python stark typisiert: inkompatible Typen
werden nicht stillschweigend umgewandelt, aber 1 + 2.0 ist
erlaubt. Für Wahrheitswerte existiert bool mit
True/False (wobei z. B. leere Listen und
None als False gelten). Type
Hints der Art a: list[int] = [] in Python
ermöglichen es, Typen für Funktionsparameter, Rückgabewerte und
Variablen explizit anzugeben. Diese Hinweise dienen primär der
statischen Code-Analyse und Dokumentation, indem sie Entwickler-Tools
und Linter unterstützen, ohne dabei das Laufzeitverhalten zu verändern.
Sie verbessern die Lesbarkeit und Wartbarkeit von Code, besonders in
größeren Projekten. |
| Syntax & Codeblöcke | Codeblöcke werden durch geschweifte Klammern {}
gruppiert. Jede Anweisung endet mit einem Semikolon ;. Die
Leserlichkeit hängt stark vom Programmierstil ab; Einrückungen sind
nicht zwingend. |
C++ verwendet dieselben Blockstrukturen wie C mit {}
und ;. Zusätzlich bietet C++
namespace-Definitionen, um Namensräume für Gruppen von
Funktionen/Klassen zu schaffen und Namenskollisionen zu vermeiden. |
Python verwendet zur Blockbildung Einrückungen anstelle von Klammern. Jede Code-Einrückungsstufe definiert einen Block. Zeilenenden markieren automatisch das Ende einer Anweisung. Diese erzwungene klare Blockstruktur erhöht die Lesbarkeit deutlich. (Falls unbedingt gewünscht, erlaubt Python auch, mehrere Anweisungen getrennt mit Semikolons in eine einzige Zeile zu schreiben.) |
| Bezeichner & Namenskonventionen | In C dürfen Namen aus Buchstaben, Zahlen und Unterstrichen bestehen,
dürfen aber nicht mit einer Zahl beginnen. Groß- und Kleinschreibung
wird unterschieden. Gültige Namen: sum,
my_var, MAX_VALUE. Häufig wird
snake_case verwendet, in Makros dagegen
GROSSBUCHSTABEN. Umlaute und Unicode-Zeichen sind nicht
erlaubt. |
In C++ gelten dieselben Regeln wie in C. Für Klassen, Methoden und
Templates ist CamelCase oder PascalCase
üblich, für Variablen oft snake_case. Konventionen
variieren je nach Code-Stil (z. B. Google im Unterschied zu Qt). Unicode
in Bezeichnern ist theoretisch erlaubt, aber selten und
problematisch. |
In Python gelten ähnliche Regeln: Namen dürfen Buchstaben, Ziffern
und Unterstriche enthalten, aber nicht mit einer Ziffer beginnen. Auch
Python unterscheided Groß und Kleinschreibung. Die Konvention (PEP 8)
ist: snake_case für Variablen und Funktionen,
CamelCase für Klassen, und ein führender Unterstrich
(_foo) signalisiert intern. Zwei führende Unterstriche ( __foo) lösen Namens-Mangling aus. Unicode
(allerdings keine Emojis und Satzzeichen) in Namen ist ab Python 3
erlaubt, wird aber aus Lesbarkeitsgründen selten genutzt. |
| Kommentare | In C beginnen einzeilige Kommentare mit //, mehrzeilige
Kommentare stehen zwischen /* und */. |
C++ verwendet dieselben Kommentarzeichen wie C. | In Python beginnt ein Kommentar mit # und gilt bis zum
Ende der Zeile. Mehrzeilige Kommentare schreibt man entweder mit
mehreren #-Zeilen oder als (zweckentfremdete) mehrzeilige
Strings mit ''' ... ''', wobei letztere oft benutzt werden,
um automatisch Dokumentationen zu erzeugen. |
| Einfache Operatoren | Inkrement: C bietet ++ und
-- sowohl als Präfix (++i) als auch als
Postfix (i++) zum Erhöhen/Verringern von Zahlen um 1.
Logisch NICHT: ! negiert boolesche
Ausdrücke. Logisch UND/ODER: &&
und || werten wie üblich aus – mit
Kurzschlussauswertung (wenn
a && b, wird b nicht geprüft, falls
a schon false ist). Exklusives ODER:
^ ist streng genommen kein üblicher logischer Operator,
sondern das bitweise XOR. |
Inkrement: C++ übernimmt
++/--, !, &&
und || von C. Zusätzliche Operatoren: C++
erlaubt Operatorüberladung, so dass man z. B. den
+-Operator für eigene Klassen neu definieren können, um ihn
je nach Zusammenhang anders wirken zu lassen. |
Inkrement: Python hat keine Operatoren
++/--. Stattdessen erhöht man Zahlen z. B. mit
i += 1 um 1. Logisch NICHT:
not negiert logische Ausdrücke. UND/ODER:
and und or sind die entsprechenden
Schlüsselwörter. Sie nutzen ebenfalls Kurzschlussauswertung.
Besonderheit: Anders als in C/C++ liefert
and/or in Python nicht wahr oder falsch als
Ergebnis, sondern einen der Operanden. Zum Beispiel ergibt
[] or 13 deshalb 13. |
| Mathematische Operatoren | Potenzierung: Kein eigener Operator; man verwendet
die Bibliotheksfunktion pow(x, y) aus
<math.h>. ^ bedeutet hier bitweises XOR,
nicht Potenz. Ganzzahldivision: / zwischen
Integern führt ebenfalls Ganzzahldivision aus, d. h. 7/3
ergibt die Ganzzahl 2, aber schon 7.0/3 liefert 2,333… |
Potenzierung: Kein spezieller Operator, stattdessen
die Funktion std::pow(base, exp) aus
<cmath>. Ganzzahldivision: wie in
C. |
Python unterstützt einen Operator Potenzierung
namens **. Zum Beispiel ist 2 ** 3 gleich 8.
Alternativ kann auch pow(2, 3) genutzt werden. Für die
Ganzzahldivision gibt es den eigenen Operator
//, so dass z. B. 7//3 gleich 2 ist, während
7/3 die Gleitkommazahl 2,333… liefert. |
| Standard-Bibliothek & Funktionen | Ein-/Ausgabe: C nutzt Funktionen wie
printf/scanf aus <stdio.h>.
Die Formatierung erfolgt über Format-Strings, z. B.
printf("Wert: %d", x);. Mathe-Funktionen:
In C stellt <math.h> Funktionen wie
sin(), cos(), sqrt() bereit, die
in der Regel mit double-Werten arbeiten. Diese benötigen oft die
Linker-Option -lm (math-Bibliothek). |
Ein-/Ausgabe: C++ bietet den Typ-sicheren IO-Stream
std::cout/std::cin (mit Operator
<< bzw. >>) sowie weiterhin
printf für spezielle Fälle. Beispiel:
std::cout << "Wert: " << x << std::endl;.
Mathe-Bibliothek: <cmath> stellt
dieselben Funktionen wie C zur Verfügung, aber auch überladen für
versch. Typen (float, double, long double). Zudem existiert in C++
<complex> für komplexe Zahlen mit
std::pow usw. in komplexer Arithmetik. |
Ein-/Ausgabe: Die Ausgabe erfolgt über die
eingebaute Funktion print(), die beliebig viele Argumente
nacheinander ausgibt. Sie hängt automatisch einen Zeilenumbruch an, was
sich aber nach der Art print("Hallo", end="") unterdrücken
lässt. Formatierung kann über f-Strings erfolgen, z. B.
print(f"Dies ist der Wert: {x:.2f}"), um die Gleitkommazahl
in x mit zwei Nachkommastellen auszugeben.
Mathe-Bibliothek: Python stellt das
math-Modul bereit (import math), das
Funktionen wie math.sin(x) und math.pow(x, y)
(ähnlich dem ** Operator) enthält. Zusätzlich gibt es
cmath für komplexe Arithmetik. |
| Datenstrukturen | Arrays & Strukturen: C verwendet
Arrays als Sammlung gleichartiger Elemente. Die Größe wird zu
Beginn definiert (z. B. int arr[10];). Strings sind
Char-Arrays, beendet mit '\0'. Strukturen
(struct) fassen verschiedene Datentypen unter einem Namen
zusammen, haben aber keine Methoden. Es gibt keine eingebauten
dynamischen Container – dafür malloc/free (s.
Speicherverwaltung). |
Arrays & Container: C++ bietet den Template-Typ
std::array (feste Größe) und dynamische Container wie
std::vector (Array mit variabler Länge) in
<vector>, sowie std::string Klasse für
Zeichenketten. Strukturen gibt es weiterhin, jedoch meist durch
Klassen ersetzt. Zusätzlich hat C++ assoziative Container wie
std::map (Schlüssel-Wert, ähnlich Python-Dict) und
std::unordered_map in der STL. Diese bieten bereits viele
Methoden (Insert, Find usw.). |
Listen & Dictionaries: Python hat eingebaute
dynamische Listen (list), die wie flexible
Arrays funktionieren (beliebige Länge, heterogene Elemente möglich).
Beispiel: my_list = [1, "Hallo", 3.5]. Außerdem gibt es
Dictionaries (dict) für
Schlüssel-Wert-Paare (vergleichbar mit Maps/Hash-Tabellen). Strings
(str) können wie Tupel behandelt werden, sind aber
unveränderlich. Weitere eingebaute Strukturen: tuple
(unveränderliche Listen), set (Mengen). All diese
Datentypen sind Teil der Sprache und benötigen keine spezielle
Bibliothek. |
| Speicherverwaltung | Manuell: C verlangt vom Programmierer, Speicher
selbst zu verwalten. Speicher wird mit
malloc/calloc allokiert und muss mit
free wieder freigegeben werden. Fehlende Freigabe führt zu
Speicherleck, doppelte Freigabe zu undefiniertem Verhalten. Speicher von
lokalen Variablen wird automatisch verwaltet. Es gibt keine
automatische Garbage Collection. |
Manuell/automatisch: C++ unterstützt weiterhin
C-Mechanismen (new/delete als Entsprechung zu
malloc/free). Darüber hinaus erleichtert RAII (Resource Acquisition Is
Initialization) die Verwaltung: Destruktoren von Objekten können
automatisch Speicher freigeben (z. B. std::unique_ptr in
<memory> räumt im Destruktor auf). C++ hat ebenfalls
keine Garbage Collection, aber mit Smart Pointern und Containern (z. B.
std::vector) sinkt die Gefahr von Speicherlecks. |
Automatisch (Garbage Collection): Python verwaltet den Speicher automatisch: Objekte werden freigegeben, wenn keine Referenz mehr darauf zeigt. Falls doch in seltenen Fällen nötig, lässt sich dieses Verhalten durch das Programm steuern. |
| Variablen & Referenzen | Werte und Zeiger: Variablen der Grundtypen und
struct enthalten direkt Werte (z. B. ein int
enthält den Wert 5). Zusätzlich existieren Zeiger, die
Speicheradressen halten und auf andere Variablen oder allokierten
Speicher zeigen (z. B. int *p = &x;). C unterscheidet
streng zwischen Wert und Adresse; Funktionen können per Wert oder per
Zeiger Parameter bekommen; in letzterem Fall verändern sie die
Originaldaten. |
Referenzen und Zeiger: Neben Zeigern (wie in C)
gibt es in C++ Referenzen (Deklaration mit &,
z. B. int &ref = x;), die als weiterer Name (Alias) für
eine vorhandene Variable dienen. Funktionen können Referenzen als
Parameter annehmen, um Objekte zu modifizieren, ohne ausdrücklich Zeiger
zu nutzen, die NULL werden könnten. Grundtypen verhalten
sich wie in C, aber Klassen-/Objekttypen können steuern, was bei einer
Zuweisung passiert. |
Alles sind Objekte: In Python sind alle Variablen
lediglich Referenzen auf Objekte. Eine Zuweisung a = b
kopiert keine Werte, sondern lässt a auf dasselbe Objekt
zeigen wie b. Es gibt kein Äquivalent zu C-Zeigern, aber
Listen undDictionarys verhalten sich beim Zuweisen wie Referenzen
(Änderungen in b = a; b.append(1) wirken auch in
a). Primitive Typen wie Zahlen und Strings sind in Python
unveränderlich: So ändert c = c + 1 nicht den Wert des
Zahlenobjekts, auf das c referenziert, sondern schreibt
eine Referenz auf ein anderes, um 1 höheres Zahlenobjekt in
c. Die Übergabe an Funktionen erfolgt immer per
Objektreferenz (ähnlich Call-by-reference der Werte, aber bei
Mutables können Inhalte geändert werden, bei Immutables nicht). |
| Null-Zeiger/Null-Referenz | In C steht NULL für einen Null-Zeiger, d. h. einen
Zeiger, der auf nichts zeigt. Der Versuch, von dort zu lesen oder
dorthin zu schreiben, führt zu einem Absturz (Segmentation Fault). |
In C++ existiert ebenfalls NULL, seit C++11 gibt es
zusätzlich nullptr, einen typsicheren Nullzeiger, der
explizit nur als Zeiger verwendet werden kann. |
In Python gibt es None als spezielles Objekt für
„nichts“. Es ist kein Zeiger, sondern ein eigenes Objekt, das z. B. als
Rückgabewert dient, wenn eine Funktion eigentlich nichts zurückliefert.
Vergleiche erfolgen mit is None und
is not None. |
| Enums (Aufzählungen) | C kennt Aufzählungstypen per enum. Diese werden als
Ganzzahlen umgesetzt. Beispiel:
enum Farbe {ROT, GRUEN, BLAU}; Dabei ist ROT=0, GRUEN=1
etc., sofern man keine anderen Werte zuweist. Enums in C sind eher
einfache Konstantenlisten ohne Typsicherheit (ein int kann
jeden enum-Wert aufnehmen). |
C++ übernimmt enum von C, aber C++11 führte enum
class ein. Ein enum class ist streng typisiert und die
Werte konvertieren nicht implizit zu int, was Typfehler vermeidet.
Beispiel: enum class Farbe {ROT, GRUEN, BLAU}; erfordert
Farbe::ROT beim Zugriff und verhindert die Nutzung
außerhalb dieses Typs ohne Cast. |
Python unterstützt seit Version 3.4 Aufzählungen über das Modul
enum. Man definiert Enums mittels Klassen: z. B.
from enum import Enum; class Farbe(Enum): ROT = 1; GRUEN = 2.
Die Enum-Mitglieder (wie Farbe.ROT) sind Instanzen der
Enum-Klasse und haben Eigenschaften wie name und
value. Python-Enums sind Objekte und können verglichen oder
in Schleifen verwendet werden, dienen aber hauptsächlich der besseren
Lesbarkeit von konstanten Werten. |
| Strings & Zeichen | Zeichenketten: In C gibt es keinen eigenen
String-Datentyp. Strings sind Char-Arrays, die mit '\0'
(Null-Byte) abgeschlossen werden. Man benutzt Funktionen aus
<string.h> wie strcpy,
strlen, strcmp für Operationen. Achtung:
Pufferüberläufe müssen vom Programmierer verhindert werden. Einzelne
Zeichen sind vom Typ char (häufig ASCII oder UTF-8 je nach
System). |
std::string: C++ bietet die Klasse
std::string in <string>. Sie kapselt
char-Arrays und handhabt Größenerweiterungen intern. Strings können mit
+ aneinandergehängt werden (dank Operatorüberladung) und
verfügen über Methoden wie .size() und
.substr(). Ein Ausdruck wie
std::string s = u8"Hallo 🌍"; erzeugt UTF-8. Die Klasse
std::string hat gegenüber den char-Arrays von
C den Vorteil, dass sie die Länge kennt und Funktionen als Methoden
bereitstellt. |
str: In Python sind Strings Objekte vom Typ
str. Sie sind unveränderlich.
Zeichenkettenliterale können in einfachen '...' oder
doppelten "..." Anführungszeichen stehen, Unicode (UTF-8)
ist Standard. Strings können mit + aneinandergehängt
werden. Häufiger aber nutzt man stattdessen formatierte
Strings (f-Strings oder format()-Methode)
Verkettung. Python bietet umfangreiche String-Methoden, z. B.
.lower(), .split(), .find().
Einzelne Zeichen sind ebenfalls str, mit einer Länge von
1. |
| Funktionen & Parameter | Funktionen müssen vor ihrem Aufruf definiert oder zumindest deklariert sein. Parameter werden standardmäßig per Wert übergeben (Kopie des Arguments). Soll eine Funktion eine Variable modifizieren, übergibt man einen Zeiger auf diese (Call-by-pointer). C unterstützt keine Standardparameterwerte: Jeder Funktionsaufruf muss für jeden Parameter ein Argument liefern. Überladene Funktionen (gleicher Name, aber unterschiedliche Parameteranzahl/-typen) gibt es in C nicht. | C++ erlaubt Default-Parameterwerte bei Funktionen,
die im Funktionsprototyp oder der Definition angegeben werden können.
Beispiel: void print(int x, int base=10); – wird
print(42) aufgerufen, nutzt die Funktion intern base=10.
Außerdem unterstützt C++ Funktionsüberladung: Mehrere
Funktionen mit gleichem Namen, aber unterschiedlicher Parameterzahl oder
-typen, können definiert werden (der Compiler wählt anhand des
Aufrufkontexts die passende). Übergabe ist normalerweise per Wert oder
per Referenz (siehe oben). Mit Template-Funktionen können sogar
typgenerische Funktionen erstellt werden. |
In Python können Funktionen Defaultwerte für
Parameter definieren: def greet(name, msg="Hallo"): hat
einen optionalen Parameter msg. Wird
greet("Lisa") aufgerufen, nimmt msg
automatisch den Default Halloan. Alle Standardwerte werden genau einmal beim Definieren der Funktion berechnet und für alle Aufrufe verwendet. (Achtung bei veränderlichen Objekten als Default, denn der nächste Aufruf bekommt das veränderte Objekt!) Python unterstützt auch benannte Argumente: Beim Aufruf kann man greet(msg="Hi", name="Tom") schreiben – die Reihenfolge
spielt dann keine Rolle. Überladene Funktionen im C++-Sinne gibt es
nicht; stattdessen schreibt man Funktionen, die unterschiedlich auf
Argumenttypen reagieren (Duck-Typing) oder man verwendet
optionale/variadische Parameter (*args,
**kwargs). |
| Programmstart & Module | Das Programm startet in der Funktion main(). Man kann
diese mit Parametern int main(int argc, char *argv[])
definieren, um Kommandozeilenargumente zu erhalten. C kennt kein
Modulsystem – jede .c-Datei wird separat kompiliert und am
Ende gelinkt. Gemeinsame Deklarationen stehen in Header-Dateien
(.h), die per #include eingefügt werden.
Globale Variablen/Funktionen: Funktionen und Variablen
außerhalb von Funktionen sind in allen Programmdateien verfügbar, können
aber mit static auf die jeweilige Datei beschränkt werden.
Das Schlüsselwort extern wiederum deklariert, dass eine
Definition in einer anderen Datei erfolgt. (Das Schlüsselwort
static hat eine zweite Bedeutung: So lässt sich in einer
Funktion eine lokale Variablen erzeugen, die ihren Wert zwischen
Aufrufen behält.) |
Auch in C++ beginnt das Programm in main(). C++
unterstützt die Aufteilung in mehrere Dateien ähnlich wie C (Header und
Implementationsdateien). Zusätzlich bietet C++
Namensräume (namespace), um
Funktionen/Klassen in einen logischen Namensraum einzuschließen, so dass
zum Beispiel zwei verschiedene Bibliotheken je eine Funktion
init() haben können, ohne zu kollidieren (Aufruf dann z. B.
LibA::init() vs. LibB::init()). Seit C++20
beherrscht C++ Module, so dass Code nicht mehr über Header und
#include eingebunden werden muss. |
Es gibt in Python keine Startfunktion, aber die gängige Schreibweise
lautet: if __name__ == "__main__": .... Dieser Block wird
nur ausgeführt, wenn das Skript direkt gestartet wird, nicht aber beim
Import als Modul. Damit fungiert er ähnlich wie ein
main()-Block mit einer Testfunktion. Python verfügt über
ein mächtiges Modul- und Paketsystem: Jede
.py-Datei ist ein Modul, das man via
import modulname einbinden kann. Auf Variablen, Funktionen
und Klassen in einem Modul kann nach dem Muster
modulname.bla zugegriffen werden. Es gibt keine direkten
Entsprechungen zu extern oder static –
Sichtbarkeit wird über Namensräume geregelt. Mit Unterstrich-Präfix vor
dem Namen (z. B. _intern) zeigt man an, dass etwas
verborgen sein soll; das ist aber nur ein freundlicher Hinweise, denn
Python verbietet nicht den Zugriff darauf. |
| Fehlerbehandlung | C bietet kein eigenes Exception-Handling. Fehler müssen z. B. über
Rückgabewerte signalisiert werden (etwa liefert
malloc bei Misserfolg NULL oder eine Funktion
gibt -1 zurück und setzt errno). Diese Werte
sind stets manuell zu prüfen. Schwere Fehler, die nicht abgefangen
werden (z. B. Division durch 0 bei Integern oder Segfault bei ungültigem
Zeiger), führen zu undefiniertem Verhalten oder Programmabsturz. |
C++ verfügt über Exceptions: mittels
try { ... } catch(SomeException &e) { ... } können
Fehler aufgefangen werden. Standardbibliothek-Funktionen (wie
std::stoi oder Methoden wie std::vector::at)
werfen bei Problemen Ausnahmen vom Typ std::exception oder
abgeleiteten Klassen. Entwickler können eigene Exceptions definieren
(meist durch Vererbung von std::exception). Allerdings ist
der Einsatz von Exceptions in C++ teils umstritten; viele
Performance-kritische Anwendungen meiden sie und nutzen stattdessen
ebenfalls Fehlercodes oder
std::optional/std::variant für erwartbare
Fehler. |
Python setzt stark auf Exceptions. Bei Fehlern
(z. B. Division durch 0, Zugriff auf nicht vorhandenen Listeneintrag,
Import-Fehler etc.) wirft Python automatisch eine entsprechende Ausnahme
(z. B. ZeroDivisionError, IndexError). Mit
try-except Blöcken kann man diese abfangen:
try: ... except ExceptionType as e: .... Es ist in Python
üblich, Exceptions für den Programmfluss zu nutzen, z. B. eine Schleife
oder eine Suche mittels Exception zu beenden, was in anderen Sprachen
eher unüblich ist. Eigene Exceptions werden durch Subclassing von
Exception erstellt. Unbehandelte Exceptions führen zum
Abbruch des Programms mit einer Fehlermeldung. |
| Objektorientierung (OOP) | C selbst unterstützt keine Klassen oder Objekte. Man kann zwar strukturiert programmieren und mittels Strukturen und Funktionszeigern einfache objektähnliche Konstrukte basteln, doch Konzepte wie Vererbung oder Polymorphie fehlen vollständig. Daher spricht man oft von C als rein prozeduraler Sprache. | C++ ist voll objektorientiert: Es gibt Klassen
(ähnlich wie struct, aber mit Standard-Zugriffsrechten
private für Mitglieder). C++ unterstützt
Vererbung (auch Mehrfachvererbung),
Polymorphie sowie Abstraktion mittels
virtuellen Funktionen und Kapselung (über
Zugriffsmodifier
public/private/protected). Anders
als reine OOP-Sprachen erzwingt aber nicht, alles als Objekt zu sehen:
Man kann weiterhin im C-Stil prozedural programmieren. Zusätzliche
OOP-Features: Operatorüberladung (z. B.
operator+ für eigene Klassen definieren),
Templates (für Generizität statt nur Klassen-basiertem
Polymorphismus), Destruktoren (für Aufräumlogik). |
Python ist ebenfalls objektorientiert, aber auf etwas andere Weise.
Alles in Python ist ein Objekt, auch einfache Typen wie
Zahlen oder Funktionen. Klassen definiert man mit
class-Syntax; sie unterstützen
Mehrfachvererbung, allerdings verwendet man meit nur
kleine Klassen (Mixins) als zusätzliche Elternklassen.
Polymorphie ergibt sich automatisch, denn jede
Methode/Attribut-Aufruf hängt vom Objekttyp zur Laufzeit ab; es gibt
keine Deklaration, dass eine Methode der Kindklasse eine Methode einer
Mutterklasse überschreibt. Python kennt private
Attribute nur eingschränkt: ein Prefix __
(Doppel-Unterstrich) löst Name-Mangling aus, was einen gewissen Schutz
bietet, aber echte Zugriffsbeschränkungen existieren nicht. Anders als
C++ hat Python keine Schnittstellen oder abstrakten Klassen im
Sprachkern (man nutzt dafür ABCs aus abc-Modul).
Operatorüberladung erfolgt durch spezielle Methoden
(z. B. __add__ für +) in Klassen, wodurch man
definieren kann, wie Objekte auf Operatoren reagieren. Eine
Besonderheit: Python erlaubt dynamisches Hinzufügen von
Attributen zu Objekten und Klassen während der Laufzeit. |
| Parallelität & Threading | C selbst definiert in der Sprache keine Threads. Man greift auf
Betriebssystem-APIs (z. B. POSIX-Threads unter Unix) oder Bibliotheken
zurück. Seit C11 gibt es in <threads.h> grundlegende
Thread-Funktionen. |
C++ erhielt mit C++11 einen plattformunabhängigen
Thread-Support <thread> in der Standardbibliothek.
Zum Beispiel startet std::thread t(func); einen neuen
Thread, der func() ausführt. Synchronisations-Primitive wie
std::mutex, std::lock_guard,
std::condition_variable sind ebenfalls Teil davon. |
Python unterstützt Multithreading auf Sprachebene
(Modul threading), aber die Ausführung ist in der
Standard-Implementierung CPython durch den GIL (Global Interpreter Lock)
beschränkt: Dort kann stets nur ein Thread zur gleichen Zeit
Python-Bytecode ausführen. Daher bringen Threads in Python bei
rechenintensiven Aufgaben keine Geschwindigkeitssteigerung, sondern
entzerren das Warten z. B. auf mehrere gleichzeitige
Netzwerk-Operationen. Für Parallelisierung nutzt man typischerweise
Multiprocessing (statt mehrerer Threads mehrere
komplette Prozesse). Allerdings bindet Python auf einfache Art
C/C++-Module ein, die intern echte Parallelität nutzen können;
rechenintensive Aufgaben etwa für KI werden oft an solche ausgelagert.
Eine Neuerung: Die übliche Implementierung CPython erlaubt ab Python
3.13 experimentell, den GIL abzuschalten und echtes Multithreading zu
betreiben; dies dürfte in Zukunft Standard werden. |