Meine Werkzeuge
Namensräume
Varianten

CSharp Zu CPP Referenzen

Aus indiedev
Wechseln zu: Navigation, Suche
Umstieg von C# nach C++
Referenzen
Autor Roland "Glatzemann" Rosenkranz
Programmier­sprache C#, C++
Kategorie C#-Tutorials, C++-Tutorials
Diskussion Thread im Forum
Lizenz indiedev article license
C# ist eine moderne, bequeme und einfache Sprache, die viele Schwierigkeiten vor uns verbirgt und uns das Leben in vielen Situationen sehr einfach macht. Manchmal werden dabei jedoch wichtige Konzepte vor uns verborgen die für ein solides Verständnis wichtig wären. Einer dieser Punkte sind die Referenzen und ich möchte in diesem kurzen Artikel ein paar Worte darüber verlieren, was ein Referenzdatentyp überhaupt ist und wie sich dieser sowohl in C#, als auch in C++ verhält.

Dies soll weder ein C# noch ein C++ Programmierkurs sein, sondern lediglich kurz die Gemeinsamkeiten und das Verhalten in beiden Sprachen beleuchten um es dem Entwickler zu erleichtern sich in beide Sprachen einzuarbeiten. Da ich in der nächsten Zeit häufiger etwas über C++ und DirectX schreiben werde sind solche Grundlagenartikel sicherlich hilfreich für das Verständnis und sollen dem geneigten Umsteiger das Leben etwas vereinfachen.

Verweis- bzw. Referenztypen in C# sind Datentypen, bei denen eine Referenz auf ein Objekt gespeichert wird. Dabei wird das eigentliche Objekt (meist eine Klasse) im Arbeitsspeicher abgelegt und die Referenzvariable enthält eine Referenz auf dieses Objekt.

Ich möchte dies nun an einem kleinen und einfachen Beispiel verdeutlichen. Dazu erzeugen wir zunächst eine neue Klasse in einem leeren C#-Projekt. Eine Konsolenanwendung eignet sich dafür ganz gut.

Wir erzeugen nun mit dem folgenden Code in einer neuen Klassendatei einen Referenzdatentyp MyReferenceDataType.


public class MyReferenceDataType
{
  public int SomeValue
  {
    get;
    set;
  }
}

Kein besonders komplizierter Code und auch Einsteiger sollten diesen Code verstehen, ist die Klasse doch eines der Grundkonzepte von C#. Etwas besonderes macht diese Klasse auch nicht. Sie kann lediglich einen Integer-Wert SomeValue speichern und zurückgeben.

Nun erzeugen wir eine Instanz dieses Wertes im Speicher. Bekanntlich erfolgt dies mit dem new Befehl.


MyReferenceDataType reference = new MyReferenceDataType();
reference.SomeValue = 42;
Console.WriteLine(reference.SomeValue);

Interessant ist jetzt was hinter den Kulissen passiert. reference ist eine sogenannte Referenzvariable und stellt nicht das eigentliche Objekt im Speicher dar, sondern lediglich eine Referenz auf diese Instanz. Im Grunde genommen (wenn wir mal die Garbage Collection etc. von C# ausser Acht lassen) enthält reference einen Zeiger auf die Instanz des Typs MyReferenceDataType das sich irgendwo im Arbeitsspeicher befindet. C# und das .NET-Framework verbergen das aber geschickt vor uns. Mit unsafe Code kann man zwar auch in C# mit Zeigern hantieren, aber das ist eine andere Geschichte.

Greifen wir nun auf SomeValue zu (wie in der zweiten Zeile dargestellt), so holt sich der Rechner also die Adresse die in reference gespeichert ist und greift auf die tatsächliche Instanz zu. Dies führt dazu, dass wir Referenzen schnell und effizient kopieren können, da nicht die eigentlichen Daten im Arbeitsspeicher dupliziert werden müssen, sondern lediglich der Zeiger.


MyReferenceDataType referenceCopy = reference;  // nicht das Objekt wird kopiert, sondern lediglich die Referenz darauf
referenceCopy.SomeValue = 4711;
Console.WriteLine(referenceCopy.SomeValue);
Console.WriteLine(reference.SomeValue);

Der Beweis dafür ist relativ einfach zu erbringen, wie ich im vorherigen Codeblock dargestellt habe. Zunächst kopieren wir die Referenzvariable reference in die neue Referenzvariable referenceCopy. Die "alte" Referenzvariable enthält immer noch 42 in der Eigenschaft SomeValue. Nun weisen wir SomeValue in der Kopie der Referenz einen Wert von 4711 zu. Wenn beide Referenzvariablen also auf die gleiche Instanz von MyReferenceDataType im Arbeitsspeicher zeigen, so müssten danach beide Referenzen den Wert 4711 zurückliefern. Dies überprüfen wir mit den beiden Konsolenausgaben und sehen, dass wir tatsächlich eine Referenz auf ein und dieselbe Instanz vorliegen haben.

Dieses Verhalten sollte jedem C#-Entwickler bekannt sein, denn es ist ein sehr wichtiges Konzept.

In C++ kann man sowas natürlich ebenfalls abbilden und zwar mit Zeigern (also Pointer). Der Syntax ist dabei ähnlich. Wir erzeugen uns dazu zunächst ein leeres C++-Projekt in Visual Studio. Zunächst erzeugen wir wieder unsere Klasse. Dies erfolgt in der Datei MyReferenceDataType.h. Es reicht ein Header aus, da wir lediglich eine öffentliche Variable SomeValue deklariert haben.


#ifndef _MYREFERENCEDATATYPE_H_
#define _MYREFERENCEDATATYPE_H_

class MyReferenceDataType
{
public:
	int SomeValue;
};

#endif

Danach packen wir in die Main-Funktion unserer C++-Konsolenanwendung den "Testcode".


MyReferenceDataType* reference = new MyReferenceDataType();
reference->SomeValue = 42;

std::cout << reference->SomeValue << std::endl;

MyReferenceDataType* referenceCopy = reference;
referenceCopy->SomeValue = 4711;

std::cout << reference->SomeValue << std::endl;
std::cout << referenceCopy->SomeValue << std::endl;

delete reference;

getchar();

Damit dies funktioniert musste ich noch stdio und iostream mittels der Include-Direktive einbinden.

Wenn wir das Programm kompilieren und starten, dann sehen wir, dass es das gleiche Verhalten an den Tag legt wie auch unser C#-Programm. Auch hier speichern wir Referenzen, also Zeiger auf eine Instanz im Speicher und greifen hier mit dem Dereferenzierungs-Operator -> darauf zu.

Da C++ uns mehr Macht verleiht, müssen wir leider auch auf einige Dinge mehr achten. Instanzen werden nicht automatisch freigegeben, so wie wir es von C# gewöhnt sind, da es keinen Garbage-Collector gibt. Wir müssen uns darum selbst kümmern und das macht in diesem Fall die Zeile delete reference. Diese gibt den Speicher frei, den wir zuvor mit new reserviert hatten. Wir dürfen natürlich nur einmal delete verwenden, da wir nur eine Instanz haben. Die Variablen reference und referenceCopy sind lediglich Zeiger auf diesen Speicherbereich. Der Zeiger wird übrigens ungültig sobald delete ausgeführt wurde, daher gehört es in C++ zum guten Stil, wenn man den Zeiger danach durch Zuweisung mit 0 ungültig macht.

Abschluss und Schlusswort

Und schon sind wir am Ende dieses kurzen Artikels angelangt. Wie bereits in den einleitenden Worten geschrieben ist dies kein Programmierkurs und daher habe ich nicht alle Aspekte und Unterschiede von C# und C++ Referenzen und Zeigern aufgezeigt, sondern lediglich eine kurze Einführung gegeben. Für den C#-Entwickler konnte ich vielleicht ein wenig Licht ins Dunkel bringen und aufzeigen, was hinter den Kulissen so passiert. Für den Umsteiger von C# nach C++ habe ich den Umstieg vielleicht ein klein wenig erleichtert und der C++-Entwickler, der sich mit C# beschäftigen möchte weis nun, wie Zeiger in C# abgebildet werden.

Ich hoffe dieser Artikel hat gefallen. Über ein kurzes Feedback würde ich mich wie immer natürlich sehr freuen. Es wäre interessant zu erfahren ob Artikel in dieser Art zukünftig weiterhin gewünscht werden. Themenvorschläge sind natürlich auch immer willkommen.

Navigation
Tutorials und Artikel
Community Project
Werkzeuge