C++ hat nicht die gleiche Semantik wie Java für Werte und Referenzen. Zunächst hat jeder Typ die Möglichkeit, entweder per Kopie oder per Referenz oder per Adresse übergeben zu werden (Sie können jedoch verhindern, dass Typen per Kopie übergeben werden, indem Sie den Kopierkonstruktor ausblenden).
Die Übergabeart, die am engsten mit der "by reference"-Übergabe in Java verwandt ist, ist die Übergabe per Zeiger. Hier ein Beispiel für die drei:
void foo(std::string bar); // by copy
void foo(std::string& bar); // by reference
void foo(std::string* bar); // by address
Nebenbei bemerkt ist die Übergabe per Kopie immer teurer als die Übergabe per Referenz oder Zeiger für Typen, die größer sind als die Größe eines Zeigers. Aus diesem Grund werden Sie oft die Übergabe per const
Referenz, die es Ihnen ermöglicht, ein Objekt zu lesen, ohne es kopieren zu müssen.
void foo(const std::string& bar); // by const reference
Dies ist jedoch alles sehr kompliziert, und Sie müssen die Feinheiten von Java kennen, um richtig zu entscheiden, was Sie in C++ wollen. In Java werden Objekte nicht durch Referenzen übergeben, sondern durch Kopieren. Das heißt, wenn Sie einem Argument ein neues Objekt zuweisen, ändert sich das Objekt des übergeordneten Bereichs nicht. In C++ entspricht dies eher der Übergabe von Objekten per Adresse als per Referenz. Hier ein Beispiel, das zeigt, wie wichtig dies ist:
// Java using "object references":
public static void foo(String bar)
{
bar = "hello world";
}
public static void main(String[] argv)
{
String bar = "goodbye world";
foo(bar);
System.out.println(bar); // prints "goodbye world"
}
// C++ using "references":
void foo(std::string& bar)
{
bar = "hello world";
}
int main()
{
std::string bar = "goodbye world";
foo(bar);
std::cout << bar << std::endl; // prints "hello world"
}
// C++ using pointers:
void foo(std::string* bar)
{
bar = new std::string("goodbye world");
delete bar; // you don't want to leak
}
int main()
{
std::string bar = "goodbye world";
foo(&bar);
std::cout << bar << std::endl; // prints "hello world"
}
Mit anderen Worten: Wenn Sie in C++ Referenzen verwenden, haben Sie es in Wirklichkeit mit der gleiche Variable Sie haben bestanden. Alle Änderungen, die Sie daran vornehmen, auch Zuweisungen, werden im übergeordneten Bereich berücksichtigt. (Dies ist zum Teil darauf zurückzuführen, wie C++ mit dem Zuweisungsoperator umgeht.) Bei der Verwendung von Zeigern erhalten Sie ein Verhalten, das dem von Java-Referenzen ähnlicher ist, allerdings um den Preis, dass Sie die Objektadressen möglicherweise über den unären &
Operator (siehe foo(&bar)
in meinem Beispiel), wobei die Verwendung der ->
Operator, um auf Mitglieder zuzugreifen, und einige zusätzliche Komplexität für die Verwendung von Operatorüberladungen.
Ein weiterer bemerkenswerter Unterschied ist, dass, da die Verwendung von by-reference-Argumenten syntaktisch eng mit der Verwendung von by-copy-Argumenten verwandt ist, Funktionen in der Lage sein sollten, davon auszugehen, dass die Objekte, die Sie per Referenz übergeben, gültig sind. Auch wenn es normalerweise möglich ist, eine Referenz an NULL
ist davon dringend abzuraten, da die einzige Möglichkeit, dies zu tun, die Dereferenzierung NULL
was zu einem undefinierten Verhalten führt. Wenn Sie also in der Lage sein müssen, eine NULL
als Parameter verwenden, werden Sie es vorziehen, Argumente per Adresse statt per Verweis zu übergeben.
Meistens werden Sie per Referenz statt per Adresse übergeben wollen, wenn Sie ein Argument aus einer Funktion ändern wollen, weil das "C++-freundlicher" ist (es sei denn, Sie brauchen die NULL
Wert), auch wenn dies nicht genau dem entspricht, was Java tut.