L-Wert-Referenzen (C++)
Nach oben zu C++-Spezifikation - Index
In der Programmiersprache C können Argumente nur per Wert übergeben werden. In C++ lassen sich Argumente per Wert oder per Referenz übergeben. Die C++-Referenztypen sind den Zeigertypen sehr ähnlich. Sie erzeugen Aliasnamen für Objekte.
Hinweis: C++-spezifische Zeigerreferenzierung und -dereferenzierung wird unter Referenzierungs-/Dereferenzierungsoperatoren behandelt.
L-Wert-Referenzen werden mit dem Operator & erstellt:
int i = 0;
int &ir = i; /* ir ist ein Alias für i */
ir = 2; /* dieselbe Wirkung wie i = 2 */
Im Beispiel wird der L-Wert ir
als Alias für i
erstellt, wobei der Initialisierer denselben Typ wie die Referenz haben muss. Alle Operationen mit ir
haben dieselben Wirkung wie Operationen mit i
. So weist ir = 2
beispielsweise i
den Wert 2 zu, und &ir
liefert die Adresse von i
zurück.
Referenzen als Argumente
Mit dem Referenzdeklarator können auch Referenztypparameter in einer Funktion deklariert werden:
void func1 (int i);
void func2 (int &ir); // ir hat den Typ "Referenz auf int"
// ...
int sum = 3;
func1(sum); // sum wird als Wert übergeben
func2(sum); // sum wird als Referenz übergeben
Das als Referenz übergebene Argument sum
kann von der Funktion func2
direkt geändert werden. Dagegen erhält func1
nur eine Kopie des Arguments sum
(als Wert übergeben) und kann so sum
selbst nicht ändern.
Wird ein Argument x
als Wert übergeben, erhält der entsprechende formale Parameter in der Funktion eine Kopie von x
. Eine Änderung dieser Kopie in dem Funktionsrumpf hat keine Auswirkung auf den Wert von x
außerhalb des Gültigkeitsbereichs der Funktion. Natürlich kann die Funktion einen Wert zurückgeben, der später zur Änderung von x
benutzt werden kann. Die Funktion kann einen per Wert übergebenen Parameter allerdings nicht direkt ändern.
In C erfordert das Ändern des Wertes eines Funktionsparameters außerhalb des Gültigkeitsbereichs der Funktion, dass die Adresse des Parameters übergeben wird. Die Adresse wird als Wert übergeben, so dass die Änderung des Inhalts der Adresse sich auf den Wert des Parameters außerhalb des Gültigkeitsbereichs der Funktion auswirkt.
Selbst wenn der Wert des Parameters von der Funktion nicht geändert werden muss, ist es oft nützlich, die Adresse (oder eine Referenz) an eine Funktion zu übergeben. Dies gilt insbesondere dann, wenn der Parameter eine große Datenstruktur oder ein großes Objekt ist. Wenn ein Objekt direkt an eine Funktion übergeben wird, muss das gesamte Objekt kopiert werden.
Vergleichen Sie die drei folgenden Implementierungen der Funktion treble
:
#1 | #2 | #3 |
int treble_1(int n)
{
return 3 * n;
}
// ...
int x, i = 4;
x = treble_1(i);
/* x ist jetzt 12, i = 4 */
|
void treble_2(int* np)
{
*np = (*np) * 3;
}
// ...
treble_2(&i);
/* i ist jetzt 2 */
|
void treble_3(int &n/* n ist ein Referenztyp */)
{
n = n * 3;
}
// ...
treble_3(i);
/* i ist jetzt 36 */
|
Die formale Argumentdeklaration type& t
definiert t
als Typ "Referenz auf Typ". Wird demnach treble_3
mit dem realen Argument i
aufgerufen, dient i
zur Initialisierung des formalen Referenzarguments n
. n
dient somit als Alias für i
, so dass die Zuweisung n = n*3
gleichbedeutend mit der Zuweisung 3 * i
zu i
ist.
Ist der Initialisierer eine Konstante oder ein Objekt mit einem anderen Typ als der Referenztyp, dann wird ein temporäres Objekt erzeugt, für das die Referenz als Alias dient:
int& ir = 6; /* temporäres Integerobjekt erzeugt, ir als Alias, erhält Wert 6 */
float f;
int& ir2 = f; /* erzeugt das temporäre Integerobjekt mit ir2 als Alias;
f converted before assignment */
ir2 = 2.0; /* ir2 ist nun 2, f bleibt unverändert *
Die automatische Erzeugung von temporären Objekten ermöglicht die Konvertierung von Referenztypen, wenn die formalen und tatsächlichen Argumente verschiedene (aber zuweisungskompatible) Typen haben. Bei der Wertübergabe gibt es weniger Konvertierungsprobleme, da die Kopie des aktuellen Arguments physikalisch geändert werden kann, bevor sie dem formalen Argument zugewiesen wird.