Computer & Technik
Standard-Software
TURBO-C++
Mit Objekten zukunftsorientiert programmieren
Borlands neuster Streich heißt Turbo-C++. Schneller noch als Erzrivale Microsoft, brachte die Californische Software-Schmiede einen C++-Compiler auf den Markt. Turbo-C++ ist weitgehend kompatibel zur Vorgängerversion 2.0 und entspricht der AT&T Norm 2.0, dem inoffizellen Standard für C++-Compiler.
Objektorientierte Programmierung galt lange als Modeerscheinung und Spielerei von forschungsverliebten Professoren. Doch angesichts der gestiegenen Ansprüche der Anwendergemeinde und der immer komplexer werdenden Oberflächen und Programmstrukturen sehen sich immer mehr Softwarehäuser gezwungen, von der prozeduralen Programmierung auf die moderne objektorientierte Implementierung von Methoden umzusteigen.
Da aber ein Großteil der AT&T-Vorschläge ohnehin inzwischen in die ANSI-Normen aufgenommen und in den Libraries der meisten Compiler verfügbar ist, fällt der Übergang von C nach C++ weniger schwer als allgemein angenommen.
Im Mittelpunkt der objektorientierten Programmierung (OOP) in C++ stehen die sogenannten Klassen. Eine Klasse, die in C++ über das Schlüsselwort "class" definiert wird, ist zunächst nichts anderes als ein neuer Datentyp. Allerdings unterstützt eine Klasse die drei wesentlichen Aspekte der OOP:
- Datenkaspelung
- Vererbung
- Polymorphismus.
Datenkaspelung entspricht einer wesentlichen Forderung der strukturierten Programmierung, ist aber mit normalen Mitteln nur schwer zu erreichen, da sie vom Programmierer leicht zu durchbrechen ist. Nicht so bei C++. Die Klassendefinition ermöglicht die konsequente Unterteilung von Funktionen und Daten, die nur von den klasseninternen Funktionen verändert werden können. Dies erhöht nicht nur die Modularität in Programmen, sondern erleichert auch die Fehlersuche, da auftretende Fehler sehr schnell zu einer einzigen Klasse zurückverfolgt werden können.
Zu den fundamentalen Eigenschaften der objektorientierten Programmierung gehört das Prinzip der Vererbung. Darunter ist zu verstehen, daß Klassen aus bereits bestehenden Klassen entwickelt werden. Dabei übernimmt die neue Klasse alle Datenbereiche und Funktionen der alten Klasse, die automatisch Teil der neuen wird. Im Gegensatz zur konventionellen Strukturdefinition, wo ein hierachischer Aufbau von Datentypen ebenfalls möglich ist, bleibt in der OOP jedoch die volle Datenkapselung erhalten. Mehr noch, die Funktionen behalten ihre Gültigkeit und ermöglichen weiterhin die Bearbeitung der Klassendaten. In konventionellem C wäre hier einige Sprachakrobatik nötig, um mit einer Funktion alle abgeleiteten Datentypen bearbeiten zu können.
Aus der Vererbung ergibt sich zwangsläufig die Polymorphie von Funktionen. Polymorphie ist ein griechisches Wort für "viele Ausdrucksformen" und genau das führt sie in die OOP ein: Die Möglichkeit, einer Funktion einen Namen zu geben, der in der gesamten Objekthierachie gleich verwendet werden kann, wobei aber jedes Objekt in der Hierachie die Funktion in einer für sie angebrachten Art und Weise implementieren kann. So führt die Vererbung zwar zur Übernahme des alten Funktionsnamens, nicht aber zur Übernahme der exakten Implementierung. Diese kann bei Bedarf geändert werden und führt dann zur Überschreibung des vererbten Codes. Andererseits kann die alte Version der Funktion auch bebehalten werden. Der C++-Compiler löst diese komplexen Referenzen zur Laufzeit auf indem die Objekthierachien vom aktuellen Objekt bis hoch zur Wurzel durchlaufen werden, bis eine Implemtierung der benötigten Funktion gefunden wird. Spätestens bei der Wurzel muß diese Funktion vorhandenen sein, da sie sonst nicht hätte vererbt werden können.
Aber nicht alle C++-bedingten Neuerungen haben etwas mit objektorientierter Programmierung zu tun. Auch in konventionellen Bereichen gilt es umzudenken. So ist beispielsweise die Standardbibliothek stdio.h durch stream.h ersetzt. Einzeilige Kommentare können jetzt mittels '//'-Zeichen markiert werden, Funktionsparameter können über den Referenz-Datentyp wahlweise als Wert oder als Adresse übergeben werden und über den Inline-Bezeichner wird eine Funktion vom Compiler durch entsprechenden Maschinencode ersetzt.
Bedingt durch die Einführung von C++ unterstützt Turbo-C jetzt das Rechnen mit komplexen Zahlen und BCD-Arithmetik mit siebzehnstelliger Genauigkeit, wie sie beispielsweise für finanzmathematische Berechnungen nötig ist.
Auffälligste Neuerung ist neben den C++-Befehlen die integrierte Entwicklungsumgebung, die jetzt IDE (für Integrated Development Environment) heißt. Die neue Oberfläche entspricht nun dem SAA-Standard und kann endlich auch mit der Maus bedient werden. Neben so angenehmen Spielereien wie schattierte Fenster mit freier Farbauswahl erfuhr die IDE zahlreiche interne Verbesserungen. So ist jetzt zum Beispiel möglich, mehrere Quelltextfenster gleichzetig zu öffnen und in ihrer Größe zu variiren und verschieben. Ferner lassen sich markierte Textausschnitte über ein Clipboard zwischen den einzelnen Fenstern hin und her kopieren.
Auch der Overlay-Linker, der die bereits aus Quttro-Pro bekannte VROOM-Technik (Virtuell Runtine Object Oriented Memory Management) in C++ zur Verfügung stellt, ist neu.
Anders als herkömmliche Techniken, die einzelne Module bei Bedarf auslagern und dem Programmierer die Verantwortung für die Modulabhängigkeiten auflasten, verwendet VROOM ein sogenanntes "dynamic segment swapping", das als kleinste Einheit Segmente auf Platte, EMS oder Extended Memory auslagert. Die Verwaltung der Abhängigkeiten erfolgt bis auf wenige Ausnahmen (Interrupt-Routinen, etc.) durch den Overlay-Manager.
Ebenfalls neu ist der Profiler, der erstmals in einem Borland-Paket enthalten ist. Ein Profiler ist eine Art Software-Stoppuhr, die über die kritischen Computerressourcen exakt Protokoll führt. Prozessorzeiten, Diskettenzugriffe und Tastatur-, Drucker- und Interruptaktivitäten werden erfaßt und ausgewertet. Auf diese Weise lassen sich Engpässe in Programmen leichter lokalisieren. Dazu dient nicht zuletzt auch die Aufrufstatistik, die für jede Routine und jede Zeile die Anzahl der Aufrufe bzw. Durchläufe enthält. Eine ebenso interessante Information ist die Routinen-Crossrefernz. Sie gibt Auskunft über die Aufrufhierachie des Programms: Von welchen Routinen erfolgten die Aufrufe an die zu untersuchende Routine.
Dieses Profilinig ist nicht zu verwechseln mit der Compilerinternen Optimierung. Der Compiler kann nur zeitaufwendige Konstruktionen gegen weniger zeitintensive Codepassagen austauschen. Die Optimierung der Algorithmen bleibt dem Programmierer überlassen, der mit dem Profiler ein mächtiges Instrument für das Aufspüren schwacher Programmteile zur Hand hat.
Stark verbessert zeigt sich auch der Turbo-Debugger, der nun in der Version 2.0 vorliegt. Neben der jetzt möglichen Mausbedienung macht sich vor allem die verbesserte Speicherausnutzung bemerkbar. Im Hauptspeicher belegt der Debugger nur noch runde 70 KBytes. Der ganze Rest des Debuggers wird samt der umfangreichen Tabellen in das Extended oder Expanded Memory ausgelagert. Der Turbo-Debugger unterstützt natürlich das Arbeiten mit Klassen. In einem speziellen Fenster lassen sich die Klassenhierachien einsehen und schrittweise verfolgen.
Ein völlig neues Feeling ergibt sich beim Debuggen von TSR-Programmen und Gerätetreibern. Diese an sich haarsträubende Angelegenheit ist auf dem zweiten Blick weitaus harmloser als es zunächst den Eindruck hat. Dank der neuen Fähigkeiten ist der Turbo-Debugger nämlich in der Lage, sich selbst in ein TSR-Programm zu verwandeln. Erst dieser Trick macht das ansonsten unmögliche Debuggen von residenten Programmen zur leichtesten Sache der Welt.
Nachdem man sich erst einmal daran gewöhnt hat, aus dem laufenden Debugger heraus ein TSR-Programm zu installieren (wo doch jeder Laie weiß, daß man gerade das eigentlich nie tun sollte), läuft die Debug-Sitzung recht normal ab:
1. Turbo-Debugger laden
2. TSR-Programm installieren
3. Breakpoint bei TSR-Entry-Punkt setzen
4. Turbo-Debugger ebenfalls resident machen
5. TSR-Programm auf DOS-Ebene über Hotkey aktivieren
Sobald das TSR-Programm aktiviert ist, läuft es ganz normal ab, bis es auf den Breakpoint trifft. Exakt an dieser Stelle meldet sich der Turbo-Debugger zu Wort und das Programm läßt sich wie jedes andere Programm debuggen.
Diese unkonventionelle Methode, die ähnlich auch bei Gerätetreibern funktioniert, macht den Turbo-Debugger zum derzeit wohl besten Software-Debugger. Selbst der mit Mircosoft-C 6.0 ausgelieferte CodeView in der Version 3.0 kann Borlands Meisterstück nicht das Wasser reichen.
Neben diesen lauten Paukenschlägen haben die Entwickler des Turbo-Debuggers aber auch stillschweigend mit viel Liebe zum Detail einige interne Verbesserungen vorgenommen. So ist der Turbo-Debugger beispielsweise in der Lage, ein Programm schrittweise rückwärts auszuführen. Ein Kabinettstückchen, das der Tester inzwischen so häufig nutzt, daß man sich fragt, warum solche Methoden nicht schon früher implementiert wurden.
Bei all diesen exotischen Leistungsmerkmalen darf man aber nicht vergessen, daß das A und O eines Compilers die Codeerzeugung ist und bleibt. Doch auch hier braucht sich Turbo-C++ nicht zu verstecken. Obwohl C++ einiges an Overhead erzeugt ist Turbo-C++ immer noch deutlich schneller als Quick-C 2.0 und erreicht Laufzeiten, die stellenweise an MS-C 5.1 heranreichen. Die Codequalität des neuen MS-C 6.0 wird von Turbo-C++ allerdings nicht erreicht. In Sachen Laufzeitoptimierung ist der Microsoft-Compiler derzeit wohl State-of-the-art und nicht zu schlagen.
Glanzpunkt aller Borland-Compiler ist nach wie vor die Grafiklibrary. Hieran hat sch auch unter Turbo-C++ nichts geändert. Das Borland Graphic Interface, kurz BGI genannt, arbeitet mit Treibern, die beliebig um Produkte von Drittanbietern erweiterbar sind. Damit erreicht Turbo-C++ eine Portabilität auf DOS-Grafik-Systemen, die ihresgleichen sucht. Wer will, kann unter Turbo-C problemlos SuperVGA mit 1024x768 Punkte bei 16 und neuerdings sogar 256 Farben für anspruchsvole Applikationen einsetzen.
Dafür fehlen Turbo-C wiederum Libraries für OS/2 und MS-WINDOWS. Trotz aller gegenteiligen Gerüchte ist Borland nicht bereit (oder in der Lage) diese Systeme zu unterstützen. Wer für diese Oberflächen Programme entwickeln oder anpassen muß, ist nach wie vor auf Microsofts Produktpalette angewiesen. Ein Umstand der die ansonsten berechtigte Freude über Turbo-C++ ein wenig dämpft.