Bei virtuellen Methoden wird der Typ des Objekts, auf dem die Methode aufgerufen wird, zur Laufzeit bestimmt. Dies ermöglich einerseits eine große Flexibilität, verursacht aber andererseits gewisse Kosten in Speicher und Performance. Der Compiler erzeugt einmalig für jede Klasse, die mindestens eine virtuelle Methode besitzt, eine so genannte v-Table, in der im Wesentlichen Zeiger auf die virtuellen Methoden der Klasse gespeichert sind. Zusätzlich enthält jede Instanz der Klasse einen Zeiger auf diese Tabelle, v-Pointer genannt. Ein Nachteil virtueller Methoden besteht darin, dass sie (fast) immer gelinkt werden, auch wenn sie aus dem Programm heraus nicht aufgerufen werden. Das liegt daran, dass die Methode auch über ein Objekt einer Basisklasse aufgerufen werden kann und es für den Compiler sehr schwierig ist, solche Vorhersagen zu treffen. Einen nicht-virtuellen Methodenaufruf setzt der Compiler direkt in einen Sprungbefehl mit entsprechender Parameterübergabe um. Wird eine virtuelle Methode über eine Referenz oder einen Pointer auf ein Objekt aufgerufen, kann der Typ des Objekts erst zur Laufzeit bestimmt werden. Um das Ziel des Sprungbefehls zu bestimmen, ist eine Indirektion über die v-Table des Objekts notwendig. Ab einer Methodenlänge von einigen Befehlen ist dieser Mehraufwand von wenigen Assembler-Befehlen vernachlässigbar. In vielen „Real World“-Applikationen ersetzt der Aufruf einer virtuellen Funktion typischerweise ein switch-Statement. Damit ist ein solcher Aufruf meistens sogar effizienter als sein von Hand programmiertes Gegenstück. |
Folgender Code zeigt zwei mögliche Implementierungen zur Berechnung des Maximums zweier Zahlen: //C int a = 6, b = 5, c; int a = 6, b = 5, c; |
Nützliche Eigenschaften
Weitere Eigenschaften von C++ erhöhen die Les- und Wartbarkeit des Codes. So sind als Typ ausgeführte Konstanten auf jeden Fall den in C weit verbreiteten #defines vorzuziehen. U.a. wird so symbolisches Debuggen möglich. Der Einsatz von Inline-Funktionen ist bei mindestens gleicher Effizienz ebenfalls deutlich robuster als Makros in C.
Cast-Operatoren
Die vier neuen Cast-Operatoren in C++ sind dem klassischen C-Cast vorzuziehen, der den Programmierer so ziemlich alles zu allem umwandeln lässt. Fehler bei Cast-Operationen sind außerdem schwer zu finden. Die C++-Casts differenzieren zwischen sehr unterschiedlichen Anwendungsgebieten und geben dem Entwickler die Möglichkeit, genau auszudrücken, was er mit einem Cast bewirken will. So wird die Lesbarkeit des Code erhöht und der Compiler kann zudem überprüfen, ob der Cast in diesem speziellen Fall erlaubt ist.
Namensräume und Überladen
Namensräume sind ein Mittel zur besseren Strukturierung gerade größerer Projekte. Um Konflikte bei der Namensgebung zu vermeiden, werden Klassen oder Funktionen in Namensräume aufgeteilt. Dieses Sprachmerkmal bedeutet keinerlei Laufzeit-Over-head; die Vorteile gegenüber der verbreiteten_underscore_präfix_taktik liegen auf der Hand. Das Überladen von Methoden, also die Verwendung desselben Namens mit unterschiedlichen Parametern, hat ebenfalls keine Auswirkung auf die Laufzeit des Programms. Die Lesbarkeit des Code kann so erhöht werden.
Referenzen
In C++ können Objekte als Referenzen übergeben werden. Referenzen sind als Alias auf ein Objekt zu verstehen und können anders als Zeiger niemals NULL sein. Eine weitere Überprüfung ist somit nicht notwendig. Die Verwendung von Referenzen ist ein wichtiger Bestandteil bei der Erstellung robuster Software.