Veröffentlicht: Dezember 2009
Von Richard Kaiser und Alexander Kaiser
Visual C++ verwendet in Windows Forms-Anwendungen eine Erweiterung von Standard-C++, die als C++/CLI bezeichnet wird. Die C++/CLI-Erweiterungen integrieren einige C#-Konzepte in C++ und ermöglichen die Nutzung der.NET Bibliothek unter C++. Im Folgenden werden einige dieser C++/CLI-Erweiterungen vorgestellt.
Dieser Artikel ist ein kurzer Auszug aus dem Buch „C++ mit Microsoft Visual C++ 2008“ (ISBN 978-3540238690), das C++ mitsamt den Visual C++-Erweiterungen (C++/CLI) umfassend darstellt. Der Verfasser dieses Buches ist ein erfahrener C++- und C#-Trainer, der auch für Firmenschulungen zur Verfügung steht.
Eine Verweisklasse
wird mit
ref
class oder ref
struct
definiert und
unterscheidet sich von einer nativen Klasse (die nur mit class
oder struct definiert wird) vor allem dadurch, dass sie die
CLI-Besonderheiten (insbesondere garbage collection) nutzen kann. So ist zum
Beispiel
C++
ref class Punkt{ // eine Verweisklasse
int x,y;
public:
Punkt(int x_, int y_):x(x_),y(y_) {}
};
eine
Verweisklasse, während
C++
class Punkt_n { // eine native Klasse
int x,y;
public:
Punkt_n(int x_, int y_):x(x_),y(y_){}
};
eine native Klasse
ist. Die Definition dieser Klassen unterscheidet sich nur durch das „ref“ am
Anfang.
Verweisklassen
gehören zu den sogenannten „verwalteten Typen“, da Objekte (Instanzen) dieser
Typen auf dem Garbage Collected Heap angelegt werden und der von ihnen belegte
Speicher vom Garbage Collector wieder freigegeben wird, wenn kein Verweis mehr
auf das Objekt existiert. Ein solches Objekt wird über einen Zeiger
angesprochen, der mit dem Symbol ^ definiert wird im Unterschied zum Symbol *
bei einem Zeiger auf den gewöhnlichen Heap. Das Objekt wird dann mit gcnew angelegt:
C++
Punkt^ p=gcnew Punkt(17,18);
Ein Objekt einer
nativen Klasse kann dagegen auf dem Stack oder mit new definiert werden:
C++
Punkt_n p1(18,19);
Punkt_n* p2=new Punkt_n(19,20);
Während der
Speicher für ein mit new angelegtes
Objekt mit delete wieder freigegeben
werden muss, ist das für ein mit gcnew
angelegtes Objekt nicht notwendig. Das ist zwar möglich
C++
delete p;
und oft auch
sinnvoll. Falls das aber unterlassen wird, gibt der Garbage Collector den
Speicher irgendwann einmal wieder frei, wenn kein Verweis mehr auf das Objekt
existiert.
Alle
Verweisklassen werden von der Basisklasse Object
abgeleitet, auch ohne dass bei ihrer Definition eine Basisklasse angegeben
wird. Da die Klasse Object eine
virtuelle Methode
virtual String^ ToString()
hat, steht diese in jeder Verweisklasse zur
Verfügung:
C++
String^ s=p->ToString();
Da diese Methode
virtuell ist, kann sie überschrieben werden:
C++
ref class Punkt {
int x,y;
public:
virtual String^ ToString() override
{
return
String::Format("Punkt({0},{1})",x,y);
}
};
Mit dem Objekt p
von oben erhält man dann durch
C++
String^ s=p->ToString(); //
"Punkt(17,18)"
den als Kommentar
angegebenen Text.
Alle .NET-Klassen
sind Verweisklassen. Deshalb müssen alle Verweise auf Objekte dieser Klassen
mit dem Symbol ^ definiert und die Objekte mit gcnew angelegt werden. So erzeugt zum Beispiel die Funktion makeTextBox
eine TextBox und fügt diese mit Controls->Add
dem als Argument übergebenen Formular hinzu:
C++
TextBox^ makeTextBox(Form^ f, int
x, int y, int w, int h)
{
TextBox^ t = gcnew TextBox();
t->Location =
System::Drawing::Point(x, y);
t->Size =
System::Drawing::Size(w, h);
t->Multiline = true;
t->Name =
L"makeTextBox1";
f->Controls->Add(t);
return t;
};
Diese Funktion kann
dann in einer Elementfunktion eines Formulars so aufgerufen werden:
C++
TextBox^
t=makeTextBox(this,10,10,20,50);
t->AppendText("bla bla
bla");
Verweisklassen
unterscheiden sich von nativen Klassen auch dadurch, dass sie andere Arten von
Elementen wie z.B. Properties (Eigenschaften) enthalten können. Wir
haben Properties bereits bei der ersten Begegnung
mit dem Eigenschaftenfenster kennengelernt und wie Variablen benutzt: Einer property
wurde ein Wert zugewiesen, und eine property wurde wie eine Variable
in einem Ausdruck verwendet.
Eine property
ist allerdings mehr als eine Variable: Mit einer property können
Methoden und Datenelemente zum Lesen bzw. Schreiben verbunden sein. Diese
Methoden müssen bei der Definition der property angegeben werden und
get und set heißen. Die Funktion get ist dann die
Lesefunktion und set die Schreibfunktion. Wenn eine property
– eine Funktion mit dem Namen get hat, muss
das eine Funktion ohne Parameter sein. Ihr Rückgabetyp muss derselbe Datentyp
wie der Datentyp der Property sein.
Wenn die property
in einem Ausdruck verwendet (gelesen) wird, wird diese Funktion aufgerufen. Ihr
Rückgabewert ist dann der Wert der property.
– eine Funktion mit dem Namen set hat,
muss das eine Funktion mit dem Rückgabetyp void und einem einzigen
Werte- oder Konstantenparameter sein, der denselben Datentyp hat wie die property.
Bei einer Zuweisung an die property
wird dann diese Funktion mit dem Argument aufgerufen, das zugewiesen wird.
Für die Eigenschaft x des
Datentyps T müssen die Lese- und Schreibmethoden die folgenden Funktionstypen
haben:
C++
typedef int T;
ref class C {
T fx;
public:
property T x {
T get()
{
return fx;
}
void set(T
x_)
{
fx=x_*x_;
};
};
};
Die Klasse C kann
folgendermaßen verwendet werden:
C++
C^ c=gcnew C;
c->x=2;
int
y=c->x; // y==4
Für einen
Entwickler sieht eine Property wie ein „gewöhnliches Datenelement“ aus.
Sie unterscheidet sich von einem solchen Datenelement aber dadurch, dass der
Zugriff auf eine Property (wenn sie gelesen oder beschrieben wird) mit Anweisungen
verbunden werden kann.
Das Konzept der Properties
ist eng mit der visuellen Programmierung verbunden. Da mit einer
Zuweisung an eine Property Anweisungen ausgeführt werden können, lässt sich mit
der Änderung einer Eigenschaft direkt die visuelle Darstellung der Komponente
ändern. Wird zum Beispiel die Eigenschaft Top einer visuellen Komponente
verändert, ändert sich nicht nur der Wert des zugehörigen Datenelements,
sondern außerdem die grafische Darstellung dieser Komponente: Sie wird an der
alten Position entfernt und an der neuen Position neu gezeichnet.
Zurück: Einschränkungen bei der
Kombination von nativen und verwalteten Klassen | Weiter: .NET-Klassen in C++ Windows Forms-Anwendungen