MSDN Magazin > Home > Ausgaben > 2007 > February >  C++ Arbeitsplatz: Grundprinzipien, Höhepun...
C++ Arbeitsplatz
Grundprinzipien, Höhepunkte und ein Abschied
Paul DiLascia

Diesen Monat werde ich von meinem üblichen Frage-&Antwort-Schema abweichen, um von einem wirklich großartigen Dokument zu erzählen, das ich online entdeckt habe. Vor ein paar Wochen hat mir jemand geschrieben, der fragte, warum er keine const-Funktion in C++/CLI deklarieren könne:
// reference class
ref class A {
   void f() const; // NOT!
};
Ich erwiderte darauf: Es geht einfach nicht, so sind eben die Regeln. Die Gemeinsame Spracheninfrastruktur (CLI) wurde entworfen, um viele Sprachen wie Visual Basic®, Java und sogar COBOL zu unterstützen, die nicht einmal wissen, was const bedeutet. Das CLI weiß nicht, was const-Memberfunktionen sind, deshalb können Sie sie nicht verwenden.
Nachdem ich meine Antwort abgefeuert hatte, habe ich mich vage an etwas erinnert, das weit unten in den Tiefen meiner Erinnerungs-Leerstellen vergraben war, irgendetwas über const, etwas, das mit Compilerhinweisen zu tun hatte, und das von anderen Sprachen ignoriert werden darf. Ich habe meine alten Artikel durchsucht und entdeckt, dass ich schon einmal, im Juli 2004, eine Frage über const beantwortet hatte. Eigentlich lässt C++/CLI doch const-Datenmitglieder und Parameter deklarieren, const-Memberfunktionen aber nicht. Abbildung 1 zeigt ein kleines Programm mit einer Verweisklasse, die ein const-statisches Datenmitglied hat. Wenn Sie dieses Programm kompilieren, dann ILDASM verwenden, um es zu demontieren, werden Sie eine Linie sehen, die so aussieht:
field public static int32 
    modopt([mscorlib]System.Runtime.CompilerServices.IsConst)
        g_private = int32(0x00000001)
////////////////////////////////////////////////////////////////
// To compile type:
//    cl /clr const.cpp
//
#include <stdio.h>

ref class A {
   int m_val;
   // const data member allowed, will generate modopt
   static const int g_private = 1;
public:
   // public const member could be modified by Visual Basic or other
   // programs that don't know const -- so use literal instead.
   literal int g_public = 1;
   A(int i) { m_val = i; }
   void print();  // const;             // NO!--const fn not allowed
};

void A::print()
{
   printf("Val is %d\n",m_val);
}

int main()
{
   A a(17);
   a.print();
}

Modopt (optionaler Modifizierer) ist ein MSIL-Deklarator, der dem CLI-Heimanwender sagen will: Wenn Sie verstehen, was dieses Ding da ist, prima; wenn nicht, können Sie es unbesorgt ignorieren. Umgekehrt besagt modreq (erforderlicher Modifizierer): Wenn Sie dieses Ding nicht verstehen, können Sie diese Funktion nicht verwenden. Temporär ist ein Beispiel für einen modreq. Da ein temporärer Verweis jederzeit von dem OS/Hardware (oder sogar einem anderen Thread) geändert werden kann, sollte ein CLI-Heimanwender besser wissen, was temporär bedeutet, wenn er ein temporäres Objekt verwenden will. Aber const ist optional. Beachten Sie jedoch Folgendes: Zwar würden die Verwalteten Erweiterungen ein C++ const-Objekt in ein CLI-Literal, konvertieren, C++/CLI macht dies aber nicht mehr. Also Vorsicht, wenn Sie ein öffentliches const-Datenmitglied deklarieren: Clients, die in einer Sprache wie Visual Basic geschrieben wurden, könnten seinen Wert ändern. Wenn Sie nicht wollen, dass CLI-Clients den Wert ändern können, sollten Sie Ihr Objekt als Literal deklarieren, wie in Abbildung 1 gezeigt. Aber was ist mit Memberfunktionen, warum sind const-Memberfunktionen nicht möglich?

Das Grundprinzip
Nun, im Verlauf meiner Recherchen für die Antwort bin ich auf ein wirklich gutes Whitepaper mit dem Titel „A Design Rationale for C++/CLI“ von Herb Sutter von Microsoft gestoßen. Herb war einer der Architekten von C++/CLI. Sie können das Dokument, das ich im Folgenden kurz „das Grundprinzip“ (dt. für „Rationale“) nennen werde, von Herbs Blog abrufen (die URL ist eine lange hässliche Zeichenfolge; suchen Sie einfach im Internet nach „C++/CLI Rationale“, und Sie werden es finden). Wie der Titel vermuten lässt, erklärt das Grundprinzip, warum die meisten Dinge in C++/CLI so und nicht anders sind. Es beantwortet alles von „Warum überhaupt C++ erweitern?“ bis zu meiner eigenen Abfrage über const-Funktionen. Ich meine, das Grundprinzip ist Pflichtlektüre für jeden, der die Logik hinter C++/CLI verstehen will. Und da so Vieles im Grundprinzip gar nicht häufig genug wiederholt werden kann, will ich hier einige Höhepunkte präsentieren.
Gleich zu Beginn die wichtigste Frage, nämlich:„Warum überhaupt C++ erweitern?“ Die einfache und offensichtliche Antwort ist: Um C++ zu einem erstklassigen CLI-Element zu machen. Das Microsoft® .NET Framework ist die Zukunft der Windows ®-Entwicklung. Na, und was soll man sagen – sogar COBOL unterstützt das CLI. C++/CLI wurde also entworfen, um C++ den fortgesetzten Erfolg zu sichern.
Aber warum an C++ herumbasteln? Warum die Sprache mit so fiesen neuen Begriffen wie ^ und % und neuen Schlüsselwörtern wie ref, value und Eigenschaft erweitern? Nun, gibt es keine andere Möglichkeit. Das Grundprinzip zitiert dazu keinen Geringeren als Bjarne Stroustrup: „Klassen können fast alle Begriffe darstellen, die wir brauchen. Nur, wenn die Bibliotheksroute tatsächlich nicht gangbar ist, sollte die Sprachenerweiterungsroute verfolgt werden“ (sinngemäße Übersetzung).
Für einfachen C++-Code, ist das Abzielen auf CLI wie das Schreiben eines Compilers für einen anderen Prozessor: kein Problem. Aber CLI führt neue Begriffe ein, die besondere Codegenerierung erfordern und in C++ einfach nicht ausgedrückt werden können. Eigenschaften erfordern z. B. besondere Metadaten. Eigenschaften können mit einer Bibliothek oder Vorlage nicht implementiert werden. Das Grundprinzip erörtert einige der alternativen Syntaxen, die für Eigenschaften (und andere CLI-Funktionen) gedacht waren, und warum sie abgelehnt wurden.

Entfernen der Verwalteten Erweiterungen
Das Grundprinzip erklärt auch, warum Microsoft sich entschieden hat, sich der Verwalteten Erweiterungen zu entledigen. Die Verwendung von * durch Verwaltete Erweiterungen für verwaltete wie für systemeigene Objekte war ein raffinierter und tapferer Versuch, C++ und CLI zu vereinigen, ohne die Sprache zu ändern, aber er verschleiert die wichtigen Unterschiede zwischen Verweisobjekten und systemeigenen Objekten. Die zwei Zeigerarten sehen gleich aus, aber benehmen sich unterschiedlich. Zerstörungssemantiken, Kopiekonstruktoren und virtuelle Aufrufe innerhalb Konstruktoren/Destruktoren benehmen sich z. B. alle unterschiedlich, je nachdem, auf welche Art Objekt der Zeiger wirklich weist. Gar nicht gut! Wie es im Grundprinzip heißt: „Es ist nicht nur wichtig, unnötige Unterschiede auszublenden, sondern auch, wesentliche Unterschiede anzuzeigen“, und zitiert wieder Bjarne: „Ich versuche, bedeutende Vorgänge sehr sichtbar zu machen“. Systemeigene und verwaltete Klassen sind grundlegend verschiedene Dinge. Besser also den Unterschied hervorheben, als ihn zu übertünchen. Verschiedene Mechanismen wurden bedacht und abgelehnt, und das C++/CLI-Team einigte sich schließlich auf gcnew, ^ (Handle) und % (Tracking Reference). Verwaltete und systemeigene Klassen so zu trennen hat unerwartete positive Nebeneffekte. So eröffnet z. B. die Verwendung eines eigenen gcnew-Operators, um verwaltete Objekten zuzuordnen, die Möglichkeit, eines Tages vielleicht systemeigene Klassen vom verwalteten Heap zuordnen zu können und auch umgekehrt!
Haben Sie sich je gefragt, warum die Verwalteten Erweiterungen all diese hässlichen Unterstrich-Schlüsselwörter haben, wie __gc und __value? Weil die Verwalteten Erweiterungen gewissenhaft dem C++-Standard folgen, der da besagt: „Wenn Du wirklich neue Schlüsselwörter einführen musst, so sollst du sie mit einem Namen benennen und dieser beginne mit doppeltem Unterstrich“! Aber raten Sie, was passiert ist: Als Microsoft __gc, __value und Sonstige eingeführt hat, erhielten die Microsoft-Leute in Redmond „unerwartet vehemente“ Klagen von Programmierern. Na klar! Programmierer aller Länder vereinigt euch! Ihr habt nichts zu verlieren als eure Unterstriche. Unterstriche lassen den Code scheußlich aussehen, wie eine Art Assemblersprachenprogramm oder so etwas. Deshalb hat C++/CLI ref und value, ohne Unterstriche. Das bedeutete, neue Schlüsselwörter zu C++ hinzuzufügen, aber was soll's? Wie Bjarne sagt, „Meine Erfahrung ist, dass die Menschen nach Schlüsselwörtern zum Einführen von Begriffen geradezu süchtig sind, bis zu dem Punkt, dass ein Begriff, der kein eigenes Schlüsselwort hat, erstaunlich schwer zu lehren ist. Diese Wirkung ist bedeutender und tiefer verwurzelt als die verbal ausgedrückte Abneigung der Menschen gegen neue Schlüsselwörter“. (Wie wahr, wie wahr. Herrlich, wie Bjarne die Psychologie des Programmierens beschreibt). Also hat C++/CLI die Unterstriche entfernt. Indem sie Positionsschlüsselwörter statt reservierter Schlüsselwörter werden, können sie sich mit Programmen, die diese Wörter vielleicht bereits als veränderliche oder Funktionsnamen verwenden, nicht widersprechen.
Neugierige Leser könnten sich fragen: Wieso hat sich gc in ref verwandelt, als es seine Unterstriche verlor? Wie das Grundprinzip erklärt, ist es für verwaltete Klassen nicht so wichtig, dass sie auf dem verwalteten Heap (Sammlung veralteter Objekte) existieren. Wichtig sind ihre Verweissemantiken. Handles (^) benehmen sich wie Verweise, nicht wie Zeiger, verstehen Sie? Wenn Sie das Grundprinzip lesen, ist alles logisch.
Während einerseits das Anzeigen wesentlicher Unterschiede wichtig ist, so gilt das auch für das Ausblenden oberflächlicher Unterschiede. Das ganze Überladen des Operators z. B. „funktioniert einfach“ so, wie es jeder C++-Programmierer erwarten würde, ob das Objekt systemeigen, ref oder value ist. Als ein weiteres Beispiel, wo C++/CLI einen Unterschied überdeckt, hier diesen Ausschnitt:
// ref class R as local variable
void f()
{ 
   R r; // ref class on stack???
   r.DoSomething();
   ...
}
Hier sieht r aus wie ein Stapelobjekt, aber sogar Ihre Oma weiß, dass verwaltete Klassen nicht physisch dem Stapel zugeordnet werden können, sondern vom verwalteten Heap aus zugeordnet werden müssen. Was heißt das also? Der Compiler kann diesen Ausschnitt dazu bringen, wie erwartet zu funktionieren, indem er den Gegenwert hiervon generiert:
// how the compiler sees it.
void f()
{ 
   R^ r = gcnew R; // allocate on gc heap
   try
   {
      r->DoSomething();
      ...
   }
   finally
   {
      delete r;
   }
}
Das Objekt existiert nicht auf dem physischen Stapel, aber wen kümmert's? Wichtig ist, dass die lokale veränderliche Syntax sich so benimmt, wie jeder C++-Programmierer erwarten würde. Vor allem wird der Destruktor von r vor dem Verlassen von f aufgerufen. Und da gerade von Destruktoren die Rede ist: Die gleiche Logik erklärt, warum C++/CLI deterministische Zerstörung wiederhergestellt hat: So folgt Zerstörung den gleichen Semantiken, die jeder C++-Programmierer kennen und lieben gelernt hat. Juhu! Nondeterministisch war Zerstörung einer der schlimmsten Albträume bei Verwalteten Erweiterungen. C++/CLI ordnet dem Destruktor Dispose zu, und führt eine besondere !-Syntax für Finalizers ein. Der Speicher, der von Verweisobjekten verwendet wird, wird erst dann regeneriert, wenn die Freispeichersammlung zu ihm kommt, aber das ist keine große Sache. C++-Programmierer kümmern sich nicht weiter darum, dass der Speicher in dem Moment regeneriert wird, in dem ein Objekt zerstört ist. Worauf es wirklich ankommt, ist, dass der Destruktor arbeitet, wenn es erwartet wird. C++-Programmierer verwenden oft das Erstellen-/Zerstören-Muster, um Nicht-Speicherressourcen, wie Dateihandles, Datenbanksperren und so weiter, zu initialisieren/veröffentlichen. Mit C++/CLI, arbeitet das vertraute Erstellen-/Zerstören-Muster, wie erwartet, und zwar für Referenz- sowie für systemeigene Klassen. Die Programmierer in Redmond verdienen Anerkennung für ihr Eingeständnis der Probleme mit den Verwalteten Erweiterungen und dafür, dass sie diese behoben haben.

Zukünftiger Spaß
Einer der besonders fesselnden Abschnitte im Grundprinzip ist der mit dem Titel „Zukünftige Vereinigungen“. Er gibt einige verlockende Hinweise, wohin es mit C++/CLI in Zukunft gehen könnte. Derzeit können z. B. keine systemeigenen Klassen von verwalteten abgeleitet werden oder umgekehrt. Aber die gleiche Wirkung könnte durch Implementieren einer Problemumgehung erreicht werden: Beziehen Sie die Basisklasse als ein Datenmitglied ein und schreiben dann Passthrough-Wrapper, die nichts machen, als die enthaltene Instanz aufzurufen. Nun, das hört sich recht formelhaft an, warum könnte es dann der Compiler nicht machen? Der Compiler könnte gemischte Objekte als ein zweiteiliges Objekt mit einem CLI Objekt darstellen, das alle CLI-Teile, und einem C++-Objekt, das alle C++-Teile enthält.
Und hier berichtet Sutter eine interessante Anekdote: Als er Bjarne Stroustrup diese Gemischtklassenidee zum ersten Mal zeigte, ist Bjarne zum Bücherbord gegangen „und hat ein Buch geöffnet, um zu zeigen, wo er, trotz Kritik, immer darauf bestanden hatte, dass C++ nicht verlangen darf, dass Objekte zusammenhängend in einem einzigen Speicherblock angelegt werden“. Niemand hat zu der Zeit irgendeinen Vorteil bei nicht zusammenhängenden Objekten gesehen, aber schließlich hätte niemand jemals .NET und CLI erwarten können. Bjarnes Beharren darauf, die Tür zu nicht zusammenhängenden Objekten offen zu lassen, macht gemischte Objekte möglich. Seien Sie also nicht überrascht, wenn Sie sie in einer zukünftigen Version von C++/CLI sehen. Und die Moral von der Geschicht': Wenn Sie eine neue Sprache oder ein kompliziertes Programm entwerfen, von denen Sie erwarten, dass sie ewig leben und auf unerwartete Weise wachsen, machen Sie keine unnötigen Annahmen, nur, weil es Ihnen das Leben leicht macht!
Das Grundprinzip bietet noch einen anderen interessanten historischen Leckerbissen: Der ursprüngliche interne Name der Leute in Redmond für C++/CLI war MC^2. Wie in M(anaged)C(++), mit einem zum Gruß an Albert Einstein gelüfteten Hut(^). Aber, wie Sutter sagt, das war einfach „zu putzig“. Dem stimme ich zu. Oder glauben Sie, dass sich jemand C++/CLI zu eigen machen wollte, wenn es MC^2 hieße? Bei der Entscheidung, es C++/CLI zu nennen, sind die Architekten wieder in Bjarnes Fußstapfen getreten. „Ich habe C++ gewählt, weil es kurz war, nette Interpretationen hatte und nicht nach der Form ‚Adjektiv C‘ war,“ sagt Bjarne. C++/CLI deutet an, dass C++ zuerst kommt, und vermeidet auch bewusst die Form „Adjektiv C++”.
Das Grundprinzip rechtfertigt weitere C++/CLI-Erweiterungen wie Eigenschaft, gcnew, generisch und const, und schließt mit einem nützlichen Abschnitt „Häufig gestellte Fragen (FAQs)“. Weitere Details finden Sie, wenn Sie das Grundprinzip herunterladen und selbst lesen. Und da gerade von const die Rede ist, was ist mit meiner ursprünglichen Frage: Warum ermöglicht C++/CLI const-Daten, aber keine const-Funktionen? Die kurze Antwort ist, dass CLI keinen modopt/modreq direkt auf eine Funktion bringen lässt (obwohl die CLI eigentlich doch einen Weg hat, diese Informationen in den Metadaten zu codieren. Er ist nur nicht getestet). Jedenfalls noch nicht, wie es im Grundprinzip vorsichtigerweise heißt, was impliziert, dass diese Funktion eines Tages hinzugefügt werden kann.

Die Entwicklung der Programmierung
C++/CLI macht C++ zu einem erstklassigen CLI-Element. Mehr noch, wenn Sie das Grundprinzip lesen, werden Sie erkennen, dass es das mit einer geringen Störung von C++ macht. Und C++ ist noch die beste Sprache für Systemprogrammierung, weil es direkteren Zugriff auf CLI bietet als jede andere Sprache, und weil man immer noch auf C zurückgreifen kann, wenn der gute, alte Win32® API aufgerufen werden soll; der wird uns noch eine Weile erhalten bleiben, da bin ich sicher.
Um zu verstehen, wie wichtig C++/CLI ist, und was es darstellt, muss in Betracht gezogen werden, wo die Entwicklung der Programmierung steht. Davon will ich hier auf meine Art einen kurzen Abriss geben. In der guten alten Zeit haben Programmierer Kippschalter verwendet, um ihre Programme zu schreiben. Lochstreifen waren dem gegenüber eine Verbesserung, aber jeder Computer hatte noch seine eigene „Maschinen“-Sprache. Als Computer sich vermehrten, mussten Programmierer ihre Programme für jeden neuen Computer wieder neu schreiben. Ja, das war ziemlich leidig, deshalb haben Programmierer höhere Sprachen wie FORTRAN, BASIC und C erfunden, die etwas verwendeten, das „Compiler“ hieß, um die höhere Sprache in Maschinenanweisungen für jeden Computer zu übersetzen. Abbildung 2 stellt dies dar. Jetzt brauchte das Programm nur einmal geschrieben und für verschiedene Computer kompiliert zu werden. Cool! C wurde die Sprache der Wahl für Systemprogrammierung, weil es „die am weitesten untergeordnete höhere Sprache“ war. Das bedeutet, dass sie den geringsten Ballast zwischen sich und den Computer einbrachte. Die meisten heute verwendeten Betriebssysteme sind in C geschrieben, vielleicht mit ein paar leistungskritischen oder Hardwareschnittstellenabschnitten, die in Assemblersprache programmiert sind.
Viele Jahre später hat C++ C übertroffen, indem es die Sprache objektorientierter machte, und das macht einfach mehr Spaß. Um Bjarne wieder zu zitieren: „C++ wurde entworfen, damit der Autor und seine Freunde nicht in Assembler, C, oder verschiedenen modernen höheren Sprachen programmieren mussten. Sein Hauptzweck ist, das Schreiben guter Programme leichter und angenehmer für den einzelnen Programmierer zu machen“. C++ war großartig, aber höhere Sprachen konnten nicht sehr gut miteinander kommunizieren. Wenn ein Code in C++ geschrieben war, konnte er in BASIC nicht verwendet werden oder umgekehrt (zumindest nicht ohne große Schwierigkeit). Jede Sprache hat innerhalb ihrer eigenen privaten Welt funktioniert. Das war in Ordnung für eigenständige Anwendungen, aber als Anwendungen komplexer wurden und die Umgebung dezentralisierter, wurde die Notwendigkeit, Code freizugeben, immer essentieller. Schon von der ersten Unterroutine an haben Programmierer nach völlig eingekapselten, wieder verwendbaren Komponenten als Endziel gesucht: kleine Softwarebausteine, die Programmierer assemblieren können, um Anwendungen zu erstellen. Und warum sollten all diese Stücke in der gleichen Sprache geschrieben werden müssen?
Im Verlauf der Jahre haben sich verschiedene Lösungen für das Problem systemfreier Komponenten entwickelt. Von Anfang an gehörten Bibliotheken zu den Sprachen (man denke an C runtime und printf). In der Windows-Welt sorgten DLLs für verzögertes Laden (das Dynamische in DLL), um Speicher zu sparen. DLLS haben sich auch Interoperabilität geleistet, weil Sprachen wie Visual Basic und COBOL DLLs aufrufen konnten, indem sie Importanweisungen einführten, die ihre Compilers anleiteten, die richtigen C-Verbindungsaufrufe in die DLL auszusenden. Aber die Verbindung zwischen Anwendungen und DLLs ist zu dicht, zu spröde und zu anfällig für Unterbrechungen. Jede Anwendung muss die Namen und die Signaturen eines jeden Zugangs in der DLL kennen. Auch Aufrufe in umgekehrter Richtung (von DLL zu Anwendung) sind mühselig, da Funktionenzeiger als Rückrufe durchlaufen müssen. So haben Programmierer VBX erfunden, das zu OCX wurde, das wiederum COM wurde. Zum Glück ist COM sprachneutral: Es hat „Typenbibliotheken“, sodass die Sprachen Funktionen nicht in Linkzeit kennen müssen. Sie können den typelib zur Laufzeit abfragen. COM ist ganz schön cool, aber dafür berüchtigt, schwer programmierbar zu sein. (Ironischerweise ist COM am schwierigsten in C++ zu programmieren, der Sprache, in der es erdacht und implementiert wurde!) COM hat noch andere Probleme: Es ist zu untergeordnet und behandelt nicht solche Dinge wie Sicherheit oder Speicherverwaltung.

Das Endziel
Jetzt ist das Jahr 2007 da, und wir haben das .NET Framework und seine normierte Teilmenge: CLI. CLI löst das Wiederverwendbarkeitsproblem in einer vollständig anderen Art, durch Einfügen einer neuen Schicht der Abstraktion zwischen Programmiersprachen und dem Computer. Statt Maschinenanweisungen generieren Compiler jetzt MSIL-Code, den der virtuelle CLI-Computer/just-in-time(JIT)-Compiler dann im Hintergrund zu Computercode kompiliert. Der virtuelle Computer (VES, oder Virtual Execution System, für die, die Akronyme lieben) stellt eine Ebene der Abstraktion über dem Computer bereit. Virtuelle Computer sind nicht neu. Eigentlich gibt es sie ja schon eine ganze Weile. Sprachen wie Pascal und ZIL (die Zork-Implementierungssprache; sie wird bei Infocom, wo ich früher gearbeitet habe, intern zum Schreiben von Spielen verwendet) arbeiten durch Kompilieren höherer Programme in P-Code (oder Z-Code), der dann von einem virtuellen Computer interpretiert wird. Aber CLI stellt einen gemeinsamen virtuellen Computer (das C in CLI) bereit, den alle Sprachen verwenden können. Das CLI unterstützt grundlegende Begriffe wie Klassen, Eigenschaften, Vererbung, Spiegelung und so weiter. Die VES/VM stellt Dinge bereit wie Speicherverwaltung und Sicherheit. Deshalb müssen sich Programmierer über Pufferüberläufe oder andere Fehler nicht aufregen, die schädlichen Viren die Tür öffnen könnten. Als .NET Framework und CLI populärer wurden, glichen sich höhere Sprachen wie Visual Basic, FORTRAN, COBOL und C# immer mehr einander und an C++ an, weil sie alle die zugrunde liegenden CLI-Begriffsklassen, Vererbung, Memberfunktionen und Sonstige unterstützen müssen. Jede Sprache behält weiterhin ihre Eigenart, deshalb müssen Programmierer nicht umrüsten, um .NET Framework zu verwenden. Sie müssen nur ein paar neue Begriffe lernen.
So können Programmierer jetzt in jeder beliebigen Sprache, die sie auswählen, Klassen schreiben, und andere Programmierer können in jeder beliebigen Sprache, die sie auswählen, die Klassen nutzen. Jeder kann jede Komponente in jeder Sprache programmieren, und alle Komponenten arbeiten mit sehr wenig Programmieraufwand nahtlos zusammen. Sie alle ziehen ihren Vorteil aus Sicherheit, Freispeichersammlung und anderer Infrastruktur (das I in CLI). Und wenn in Redmond morgen neue CLI-Funktionen hinzugefügt werden, dann werden alle Sprachen auch davon profitieren. Mit Windows Vista™ und dem .NET Framework 3.0 (das so etwa 10.000 neue Klassen enthält, die neuen Technologien zugeordnet sind, wie Windows Presentation Foundation, Windows Communication Foundation, Windows Workflow Foundation und Windows CardSpace™), wird Windows selbst zu CLI-Klassen umgeschrieben. Es scheint, dass das Ziel wieder verwendbarer, sprachunabhängiger, systemfreier Komponenten endlich erreicht ist. Dies stellt einen riesigen Paradigmenwechsel dar, und noch dazu einen, der erstaunlicherweise in einer verhältnismäßig allmählichen, evolutionären Weise vor sich gegangen ist. Das ist Grund zur Freude! Programmieren wird jetzt wirklich leichter.
Wenn Sie sich noch einmal zurück versetzen, um all das zu überdenken: Wie konnte sich C++ an dieser Schönen Neuen Welt nicht beteiligen? Hier kommt C++/CLI ins Spiel. Ohne C++/CLI wäre C++ in der einsamen Position, die einzige moderne Programmiersprache zu sein, die nicht verwendet werden kann, um Windows zu programmieren! C++ würde sonst eines langsamen Todes sterben oder mindestens stark marginalisiert werden. C++/CLI stellt sicher, dass das nicht geschieht. Es garantiert, dass Programmierer (wie ich), die C++ lieben, es noch über Generationen weiter verwenden können. Abbildung 2 illustriert den Paradigmenwechsel zu einem virtuellen statt physischen Computer und legt fest, wo „C++“ mit und ohne „/CLI“ hineinpasst.
Abbildung 2 Entwicklung der Programmierung (Klicken Sie zum Vergrößern auf das Bild)

Abschied, doch kein Adieu
Und jetzt eine besondere Nachricht. Dies ist das letzte Mal, dass ich meinen Namen an C++ Arbeitsplatz schreiben (tippen?) werde. Meine Artikelreihe verabschiedet sich in den Ruhestand. Mir gefällt der Gedanke, dass es zu Ehren meiner Langlebigkeit geschieht, wissen Sie, so wie Sportmannschaften die Rückennummern großer Sportler einstellen. Mein Weggang spiegelt keinerlei mangelndes Engagement seitens Microsofts oder des MSDN®Magazins gegenüber C++ wider. Es spiegelt vielmehr die einfache Tatsache wider, dass nach 164 Artikeln (dies ist mein 165.) über fast 14 Jahre hinweg Herr DiLascia langsam ein klein wenig müde wird. Und hier noch eine interessante Anekdote: Josh Trupin, der Leitende Redakteur, hat mich kürzlich „den Cal Ripken des MSDN Magazins“ genannt. Na ja, ich bin kein Baseballfan (ich mag lieber Fußball), aber ich weiß immerhin, wer Cal Ripken ist. Trotzdem war ich neugierig: In wie vielen Spielen hat Cal eigentlich gespielt? Ich habe im Internet nach der Antwort gesucht: 2,632. Ich habe auch einen biografischen Überblick gefunden, der so etwas besagte wie „die meisten Fachleute denken, dass Cal ein besserer Spieler gewesen wäre, wenn er eine Pause eingelegt hätte“. Nun, das habe ich als eine Botschaft aufgefasst. Aber keine Angst, das heißt nicht, dass ich nie wieder für MSDN Magazin schreiben werde.
Bevor ich gehe, will ich all meinen treuen Lesern danken, die ihre Fragen geschickt, mir durch das Berichten von Fehlern und Auslassungen offen die Wahrheit gesagt und mein Ego durch das Zusenden von freundlichen Worten des Lobs gesteigert haben. Einige Leser haben mir sogar geholfen, meine Artikel zu schreiben, indem sie Lösungen testeten, bevor ich sie geliefert habe. Ich will auch all den großartigen Leuten beim MSDN Magazin danken, mit denen ich in Vergangenheit und Gegenwart gearbeitet habe, in keiner besonderen Reihenfolge: Steve, Josh, Joanne, Eric, Etya, Terry, Laura, Joan (alle beide), Nancy, Val und Milo. Habe ich jemand ausgelassen? Diese Leute haben mich im Verlauf der Jahre großzügig unterstützt und mir breiten Spielraum gelassen, größtenteils das zu schreiben, was ich auch immer wollte. Besonders will ich Gretchen Bilson danken. Sie hat den Betrieb vor mehreren Jahren verlassen, aber sie war es, die mich damals 1993 eingestellt hat, als MSDN Magazin noch Microsoft Systems Journal war. Danke, Gretchen!
So, das war's, ihr Lieben. Tschüss. Vorerst einmal, nicht für immer. Oder im unverwüstlichen österreichischen Singsang von Arnold Schwarzenegger: Ich komme wieder. Wie immer glückliche Programmierung!
Paul DiLascia ist freiberuflicher Softwareberater und Internet/UI-Designer im Allgemeinen. Er ist der Autor von Windows++: Writing Reusable Windows Code in C++ (Addison-Wesley, 1992). In seiner Freizeit entwickelt Paul PixieLib, eine MFC-Klassenbibliothek, die von seiner Website www.dilascia.com erhältlich ist.
Gak-Haufen: Wie bitte?
Jetzt, da ich mit den Förmlichkeiten durch bin, dachte ich, in humoristischem Ton abzuschließen und Ihnen einige der, ähem, ungewöhnlichsten Fragen, die ich im Lauf der Jahre erhalten habe, zum Besten zu geben. Ich habe diese in einem Ordner namens Gak gesammelt, wie in: „Gak“! Ich habe versucht, sie in Kategorien einzuteilen – z. B. bekomme ich immer eine regelmäßige Ladung sprachlicher Fragen.

Wo kann ich C++ herunterladen?

Jeder spricht so begeistert von C++, wieso? Was für eine Art von Sachen sind das genau, die man in C++ machen kann, aber nicht auf Visual Basic oder Delphi? Ich habe in diesen beiden gearbeitet, sogar in Visual C++®, und das meiste von allem, was ich je brauchte, habe ich in all diesen Sprachen gefunden. Ist es einfach nur, weil die meisten alten Senior-Programmierer daran gewöhnt sind, so ausgefallen es sich anhört?

Mensch, ich hoffe, dass mit den „alten Senior-Programmierern“ nicht ich gemeint bin. Zeiger sind oft eine Quelle der Verwirrung, wie die nächsten Fragen bestätigen:

Ich konnte Zeiger (var, Objekt, funktional) immer noch nicht verstehen, erklären Sie es mir freundlicherweise, oder senden Sie mir einige Studienmaterialien.

Ich bin neu bei C++ und habe mich gefragt, was Zeiger sind und wofür sie verwendet werden. Viele Bücher, die ich durchgesehen habe, haben dies in einer sehr komplizierten Weise beschrieben. Ich weiß, dass Zeiger auf einen bestimmten Speicherbereich zeigen, aber ich weiß nicht wirklich, warum man sie braucht. Ich habe immer gedacht, dass der Computer den Verlauf von jedem Ort automatisch verfolgt. Bitte antworten Sie bald!

(Ich habe diese letzte Frage an meine Freunde und Mitautoren Matt Pietrek und John Robbins um Rat weitergeleitet. Matt hat diesen Vorschlag gemacht: „Sag ihm, dass er Recht hat. Zeiger sind ein alter, veralteter Begriff. Es ist nicht nötig, sie jetzt zu lernen“. John hat geschrieben: „Ich habe gedacht, dass ein Zeiger oder Pointer eine Art von Hund sei. Willst du damit sagen, es gibt noch mehr Bedeutungen?“)
Im Laufe der Zeit erhalte ich immer die eine oder andere Compilerfrage.

Lieber [sic] Paul, während der Kompilierzeit. Wie kompilieren Link MFC Bibliothek? Manchmal DLL kompilieren. Weil Haken. So weit, ich nicht kompilieren diese Quelle. Bitte. Wie kompilieren oder Quelle senden. Schönen Tag.

Häufiger aber bekomme ich Windows-Fragen:

Ich bin auf Ihr Tastatur/Mausdetektorprogramm gestoßen, es war eine verblüffende Erfahrung für mich. Doch habe ich eine Frage an Sie, jetzt arbeitet Ihr Programm, wenn die „Zeiterfassungstafel“ fokussiert ist, gibt es eine Möglichkeit, es so zu machen, dass das Programm auch dann noch seine Arbeit macht, wenn es nicht auf Fokus ist? Ich habe versucht, dies heraus zu bekommen, aber ich lande in einer Sackgasse, daher schicke ich diese E-Mail, um zu fragen. Vielen Dank, dass Sie sich die Zeit nehmen.

Das Dumme ist, ich bin nicht sicher, welches Tastatur-/Mausdetektorprogramm er meint. Ich kann mich nicht erinnern, je eines geschrieben zu haben. Man sollte annehmen, dass ich mich erinnern würde, wenn es so verblüffend war. Ach, ja.
Hin und wieder bekomme ich eine Mathefrage:

Ich bearbeite ein Programm, das eine bestimmte Sequenz der Vorgänge verwendet, um einen Brief zu „codieren“ und später zu „decodieren“. Ich habe äußerste Schwierigkeiten beim Decodieren, wo ich die umgekehrte Reihenfolge des %-Vorgangs vornehmen muss. Ich weiß, was der Rest ist, und ich weiß, wie man den Prozentsatz ermittelt, aber anscheinend kann ich nicht herausfinden, was die Ausgangszahl ist. Wenn z. B. der Rest vom Vorgang 22 wäre, und der Vorgang wäre (die Zahl) %63, was wäre dann die Zahl? Wenn Sie mir helfen könnten, wäre das prima.

Hm. Ich kann verstehen, warum dieser Bursche „äußerste Schwierigkeiten“ haben könnte, seine Briefe zu decodieren, da es eine unendliche Anzahl der Lösungen für n%a=b gibt, wenn a und b gegeben sind, und n unbekannt. Leider, vermute ich, hätte er in der Klassenarbeit keine Eins dafür bekommen. Da gerade von Klassen die Rede ist, ich bekomme eine regelmäßige Ladung von Fragen, die deutlich in die Kategorie „können Sie meine Hausaufgabe für mich machen?“ fällt.

Ich möchte ein kurzes Programm zu: Geben Sie 20 Zahlen ein, und ordnen Sie diese in aufsteigender Reihenfolge.

Könnte ich Hilfe bei diesen zwei Programmen bekommen? Ich brauche sie morgen noch vor Mittag. Bitte helfen Sie mir!
Schreiben Sie ein Programm, das den Ausgangskontostand eines Benutzers anfordert, Abhebungen, mit denen das Konto belastet wird, anfordert, bis der Benutzer eine -1 eingibt, oder der Kontostand des Benutzers unter null geht. Drucken Sie den Ausgangskontostand des Benutzers, den Endkontostand, Gesamtanzahl der ausgestellten Schecks, Gesamtbetrag der ausgestellten Schecks und den Durchschnitt der ausgestellten Schecks.
Schreiben Sie ein Lohnlistenprogramm, und drucken Sie den vierzehntägigen Nettolohn eines Benutzers aus. Stellen Sie sicher, dass der Benutzer die Arbeitsstunden und den Lohntarif angibt. Auch sollten Vorkehrungen für Überstundenbezahlung getroffen werden. Nehmen Sie an, dass alle insgesamt 18 Prozent ihres Bruttosolds an Abzügen zahlen. Drucken Sie den Lohn des Benutzers, den Nettolohn und das jährliche Gehalt.

(Es gibt auch noch eine Nr.3, aber damit verschone ich Sie). Oft bekomme ich auch Fragen, die lange Seiten mit Quellcode enthalten, die ich gewöhnlich lösche, ohne sie zu lesen. Manchmal kommen Fragen zu Themen, die nichts mit meiner Artikelreihe zu tun haben – wie Visual Basic, Microsoft Access™ oder wie Excel® zu programmieren ist. Ich erhalte sogar Fragen von ganz normalen Benutzern, wie „Mein Computer ist abgestürzt – was soll ich machen?“ oder „Wieso muss ich, um meinen Computer herunterzufahren, die Start-Schaltfläche drücken?“ – was ja, wenn man es recht bedenkt, eine sehr vernünftige Frage ist! Ja, warum eigentlich? (Raymond Chen beantwortet diese Frage.) Dann gibt es diejenigen, die sich einer Einordnung entziehen.

Lieber Paul, können Sie mich freundlicherweise zu einer statistischen Site führen, welche die durchschnittliche Anzahl der Zeilen von Visual C++-Code anzeigt, die ein durchschnittlicher Entwickler in einem Tag schreiben kann? Danke für Ihre Hilfe.

Lieber Herr DiLascia, wie kann ich wie Sie sein?

Sehr geehrter Herr, Ich kaufe die MSDN zu so viel, schauen Sie in MSDN nach MFC, fühlt sich so gut an, deshalb stelle Ihnen eine Frage über „Was kann wünschen, für Microsoft zu arbeiten.“ Sehr wie die Programmierung für Visual C++. Ich habe dann Traum, ist, für Microsoft arbeiten, dies ist für Fähigkeit, für Wert, für Traum. Heute kann ich MFC verwenden, schreibt die Multimedia-Programmierung. In der Schule, kann ich sagen, ich bin ganz gut. Aber mein Deutsch ist so lala. Ich kein Freundin zu fünf Jahre für Programmieren. Weil Programmieren so Spaß ist. Vielleicht werden Sie denken, dieser Tunichtgut. Ich kann verstehen. Aber hoffe, Sie können Brief zu mir erwidern. Sagen Sie mir, Was kann wünschen, für Microsoft zu arbeiten, und was kann ich machen. Sehr vielen Dank.

Was mir hier richtig gut gefällt, ist, wie die begeisterte Freak-Persönlichkeit dieses Burschen durchscheint, trotz des „so lala“ Deutsch (das, wie ich Ihnen versichern kann, weitaus besser ist, als mein Hochchinesisch!). Ich versuche gewöhnlich, auf die meisten Fragen zu antworten, selbst dann, wenn alles, was ich sagen kann, nur ein: „Tut mir leid, ich weiß es nicht“ ist. Viele Leser sind überrascht, wenn ich tatsächlich zurück schreibe.

Paul, ich war nicht sicher, dass ein berühmter Autor wie Sie so bereitwillig und unverzüglich einem Fremden helfen würde. Sie sind nicht nur ein sehr kenntnisreicher Experte, sondern auch eine sehr nette Person. Vielen Dank.

Na, Mensch – danke IHNEN, Mike! Und schließlich noch diese Blüte:

Könnte ich bitte erfahren, was ein „psychic window“ in der Windows-Programmierung ist. Ich weiß eigentlich nicht, wie man das schreibt. Mein Freund hat mich das gefragt. Bitte helfen Sie mir

Ich fürchte, darauf weiß ich keine Antwort. Vielleicht sollte er Uri Geller konsultieren. Wenn irgendjemand da draußen weiß, was ein parapsychologisches Fenster ist, lassen Sie mir bitte eine Zeile zukommen – über kosmische Telepathie.


Paul DiLascia ist freiberuflicher Softwareberater und Internet/UI-Designer im Allgemeinen. Er ist der Autor von Windows++: Das Schreiben von wieder verwendbarem Windows-Code in C++ (Addison-Wesley, 1992). In seiner Freizeit entwickelt Paul PixieLib, eine MFC-Klassenbibliothek, die von seiner Website www.dilascia.com erhältlich ist.

Page view tracker