Referenz (Programmierung)
Eine Referenz ist ein Verweis auf ein Objekt. Eine Referenz ist damit ein Aliasname für ein bereits bestehendes Objekt.
Definitionen
Zeiger sind die primitivste Art der Referenz. Aufgrund ihrer engen Beziehung zur zugrunde liegenden Hardware sind sie eine der leistungsstärksten und effizientesten Arten von Referenzen. Aufgrund dieser Beziehung erfordern Zeiger jedoch ein starkes Verständnis der Details der Speicherarchitektur durch den Programmierer. Da Zeiger die Speicheradresse anstelle eines Werts direkt speichern, kann eine unangemessene Verwendung von Zeigern zu undefiniertem Verhalten in einem Programm führen, insbesondere aufgrund von baumelnden Zeigern oder Platzhaltern. Intelligente Zeiger sind undurchsichtige Datenstrukturen, die sich wie Zeiger verhalten, auf die jedoch nur mit bestimmten Methoden zugegriffen werden kann.
Ein Handle ist eine abstrakte Referenz und kann auf verschiedene Arten dargestellt werden. Ein häufiges Beispiel sind Datei-Handles, mit denen Dateiinhalte abstrahiert werden. Es repräsentiert normalerweise sowohl die Datei selbst, wie beim Anfordern einer Sperre für die Datei, als auch eine bestimmte Position innerhalb des Dateiinhalts, wie beim Lesen einer Datei.
Bei verteilten Systemen kann die Referenz mehr als eine Speicheradresse oder einen Bezeichner enthalten. Es kann auch eine eingebettete Spezifikation der Netzwerkprotokolle enthalten, die zum Lokalisieren und Zugreifen auf das referenzierte Objekt verwendet werden, sowie die Art und Weise, wie Informationen codiert oder serialisiert werden. So kann beispielsweise eine WSDL-Beschreibung eines Remote-Webservices als Referenzform angesehen werden. Es enthält eine vollständige Spezifikation zum Auffinden und Binden eines bestimmten Webdienstes. Ein Verweis auf ein verteiltes Live-Objekt ist ein weiteres Beispiel: Es handelt sich um eine vollständige Spezifikation zum Erstellen einer kleinen Softwarekomponente, die als Proxy bezeichnet wird und anschließend eine Peer-to-Peer-Interaktion durchführt und über die der lokale Computer möglicherweise Zugriff erhält Daten, die repliziert werden oder nur als schwach konsistenter Nachrichtenstrom existieren. In all diesen Fällen enthält die Referenz den vollständigen Satz von Anweisungen oder ein Rezept für den Zugriff auf die Daten. In diesem Sinne dient es demselben Zweck wie ein Bezeichner oder eine Speicheradresse.
Referenzen in C++
In der Programmiersprache C++ werden Referenzen sehr häufig und für verschiedene Zwecke eingesetzt:
- als (kürzerer oder verständlicherer) Aliasname für ein bereits bestehendes Objekt
- zur Optimierung, um Kopien von Objekten zu vermeiden
- in speziellen Memberfunktionen, wie Copy- & Move-Konstruktoren und Zuweisungsoperatoren
- als sogenannte universelle Referenz (engl.: universal reference), die bei Templates einen beliebigen Parametertyp repräsentiert.
Es gibt in C++ sogenannte Lvalue-Referenzen, die durch ein an den Typ angehängtes &
gekennzeichnet werden, und (seit C++11) zusätzlich noch Rvalue-Referenzen, die durch &&
gekennzeichnet werden.
Codebeispiele
Unterschied von Referenz und Kopie:
int original = 5;
int kopie = original;
int& referenz = original;
kopie = 30; // weist der Kopie den Wert 30 zu. Das Original bleibt unverändert
referenz = 20; // weist der Referenz – und somit auch dem Original – den Wert 20 zu
original = 10; // ändert das Original, womit aber auch die Referenz ihren Wert ändert.
Parameterübergabe als Referenz:
void quadrieren(int& x) {
x = x * x;
}
int main() {
int i = 5;
quadrieren(i); // Funktionsaufruf ändert den Wert von i auf 25
}
Objektreferenzen:
Bank& nBank = Bankenverzeichnis::nachBLZ("76543210"); // eine Referenz auf ein Bankobjekt wird beschafft
Konto& nKonto1 = nBank.kontoZugriff("1234567"); // eine Referenz auf ein bestimmtes Kontoobjekt wird beschafft
Konto& nKonto2 = nBank.kontoZugriff("1111111"); // eine Referenz auf ein weiteres Kontoobjekt wird beschafft
nKonto1.einzahlung(100.00, "EUR", nKonto2); // eine Methode wird auf nKonto1 gerufen
Klassendesign:
class Kunde
{
public:
explicit Kunde(const std::string& name); // 'name' wird aus Effizienzgründen nur als const-Referenz übergeben
explicit Kunde(std::string&& name); // Rvalue-Referenz, erlaubt ein "move" aus dem Namen (seit C++11)
Kunde(const Kunde& other); // Copy-Konstruktor
Kunde(Kunde&& other); // Move-Konstruktor (seit C++11)
const std::string& getName() const; // gibt const-Referenz auf Kundennamen zurück
std::string&& getName() &&; // gibt Rvalue-Referenz zurück, falls Objekt selbst ein RValue ist (ab C++11)
…
};
Beispiel in Pascal
Übergabe by reference (der Wert der übergebenen Variablen wird geändert)
procedure quadriere(var wert: integer);
begin
wert := wert * wert;
end;
Dieser Prozedur kann nur eine Variable übergeben werden, kein Ausdruck. wert
ist der lokale Name der als Referenz übergebenen Variablen. Mit der Zuweisung eines Werts wird direkt der Inhalt der übergebenen Variablen geändert.
Übergabe by value (also nur des Werts, nicht der Variablen selbst; der Wert der übergebenen Variablen wird nicht geändert)
function quadrat(wert: integer): integer;
begin
Result := wert * wert;
end;
Selbst wenn eine Zuweisung an wert
erfolgen würde, würde dies den Inhalt einer etwa übergebenen Variablen nicht ändern: Übergeben wird nur ein Wert. Der Bezeichner wert
steht für eine lokale Variable, die nur innerhalb der Funktion gültig ist.