Was ist der Unterschied zwischen
- Ein Parameter, der als Referenz übergeben wird
- ein Parameter, der als Wert übergeben wird?
Könnten Sie mir bitte einige Beispiele geben?
Was ist der Unterschied zwischen
Könnten Sie mir bitte einige Beispiele geben?
Antworten:
In erster Linie ist die in der CS-Theorie definierte Unterscheidung zwischen "Pass by Value vs. Pass by Reference" veraltet, da die ursprünglich als "Pass by Reference" definierte Technik seitdem in Ungnade gefallen ist und derzeit nur noch selten verwendet wird. 1
Neuere Sprachen 2 verwenden in der Regel ein anderes (aber ähnliches) Technikpaar, um die gleichen Effekte zu erzielen (siehe unten), was die Hauptursache für Verwirrung ist.
Eine sekundäre Quelle der Verwirrung ist die Tatsache, dass "Referenz" in "Referenzübergabe" eine engere Bedeutung hat als der allgemeine Begriff "Referenz" (weil der Ausdruck älter ist als er).
Die authentische Definition lautet nun:
Wenn ein Parameter als Referenz übergeben wird , verwenden der Aufrufer und der Angerufene dieselbe Variable für den Parameter. Wenn der Angerufene die Parametervariable ändert, ist der Effekt für die Variable des Anrufers sichtbar.
Wenn ein Parameter als Wert übergeben wird , haben der Anrufer und der Angerufene zwei unabhängige Variablen mit demselben Wert. Wenn der Angerufene die Parametervariable ändert, ist der Effekt für den Anrufer nicht sichtbar.
In dieser Definition sind folgende Punkte zu beachten:
"Variable" bedeutet hier die (lokale oder globale) Variable des Aufrufers selbst. Wenn ich also eine lokale Variable als Referenz übergebe und ihr zuweise, ändere ich die Variable des Aufrufers selbst, nicht z. B. was auch immer sie zeigt, wenn es sich um einen Zeiger handelt .
Die Bedeutung von "Referenz" in "Referenz übergeben" . Der Unterschied zum allgemeinen Begriff "Referenz" besteht darin, dass diese "Referenz" vorübergehend und implizit ist. Was der Angerufene im Grunde bekommt, ist eine "Variable", die irgendwie "die gleiche" wie die ursprüngliche ist. Wie genau dieser Effekt erzielt wird, ist irrelevant (z. B. kann die Sprache auch einige Implementierungsdetails offenlegen - Adressen, Zeiger, Dereferenzierung - dies ist alles irrelevant; wenn der Nettoeffekt dies ist, wird er als Referenz übergeben).
In modernen Sprachen sind Variablen in der Regel "Referenztypen" (ein anderes Konzept, das später als "Referenzübergabe" erfunden und von ihm inspiriert wurde), dh die tatsächlichen Objektdaten werden separat irgendwo gespeichert (normalerweise auf dem Heap) Nur "Verweise" darauf werden jemals in Variablen gespeichert und als Parameter übergeben. 3
Das Übergeben einer solchen Referenz fällt unter den Wert " Übergeben", da der Wert einer Variablen technisch gesehen die Referenz selbst und nicht das referenzierte Objekt ist. Der Nettoeffekt auf das Programm kann jedoch der gleiche sein wie Pass-by-Value oder Pass-by-Reference:
Wie Sie vielleicht sehen, ist dieses Technikpaar fast dasselbe wie das in der Definition, nur mit einer Indirektionsebene: Ersetzen Sie einfach "Variable" durch "referenziertes Objekt".
Es gibt keinen vereinbarten Namen für sie, was zu verzerrten Erklärungen wie "Call by Value, bei dem der Wert eine Referenz ist" führt. 1975 schlug Barbara Liskov den Begriff " Call-by-Object-Sharing " (oder manchmal auch nur "Call-by-Sharing") vor, obwohl er sich nie ganz durchsetzte. Darüber hinaus zeichnet keiner dieser Sätze eine Parallele zum ursprünglichen Paar. Kein Wunder, dass die alten Begriffe in Abwesenheit von etwas Besserem wiederverwendet wurden, was zu Verwirrung führte. 4
HINWEIS : Diese Antwort lautete lange Zeit:
Angenommen, ich möchte eine Webseite mit Ihnen teilen. Wenn ich Ihnen die URL sage, übergebe ich als Referenz. Sie können diese URL verwenden, um dieselbe Webseite anzuzeigen, die ich sehen kann. Wenn diese Seite geändert wird, sehen wir beide die Änderungen. Wenn Sie die URL löschen, zerstören Sie lediglich Ihren Verweis auf diese Seite - Sie löschen nicht die eigentliche Seite.
Wenn ich die Seite ausdrucke und Ihnen den Ausdruck gebe, übergebe ich den Wert. Ihre Seite ist eine nicht verbundene Kopie des Originals. Sie werden keine nachfolgenden Änderungen sehen und alle Änderungen, die Sie vornehmen (z. B. Kritzeleien auf Ihrem Ausdruck), werden nicht auf der Originalseite angezeigt. Wenn Sie den Ausdruck zerstören, haben Sie tatsächlich Ihre Kopie des Objekts zerstört - die ursprüngliche Webseite bleibt jedoch erhalten.
Dies ist größtenteils richtig, mit Ausnahme der engeren Bedeutung von "Referenz" - es ist sowohl temporär als auch implizit (es muss nicht, aber explizit und / oder persistent zu sein, sind zusätzliche Merkmale, die nicht Teil der Referenz-Semantik sind , wie oben erklärt). Eine nähere Analogie wäre, Ihnen eine Kopie eines Dokuments zu geben, anstatt Sie einzuladen, am Original zu arbeiten.
1 Wenn Sie nicht in Fortran oder Visual Basic programmieren, ist dies nicht das Standardverhalten, und in den meisten modernen Sprachen ist ein echter Call-by-Reference nicht einmal möglich.
2 Eine ganze Reihe älterer unterstützt dies ebenfalls
3 In mehreren modernen Sprachen sind alle Typen Referenztypen. Dieser Ansatz wurde 1975 von der Sprache CLU entwickelt und seitdem von vielen anderen Sprachen übernommen, darunter Python und Ruby. Viele weitere Sprachen verwenden einen hybriden Ansatz, bei dem einige Typen "Werttypen" und andere "Referenztypen" sind - darunter C #, Java und JavaScript.
4 Es ist nichts Schlimmes daran, einen passenden alten Begriff per se zu recyceln , aber man muss irgendwie klar machen, welche Bedeutung jedes Mal verwendet wird. Nicht zu tun ist genau das, was immer wieder Verwirrung stiftet.
Auf diese Weise können Argumente an Funktionen übergeben werden. Als Referenz übergeben bedeutet, dass der Parameter der aufgerufenen Funktionen mit dem übergebenen Argument des Aufrufers identisch ist (nicht der Wert, sondern die Identität - die Variable selbst). Wert übergeben bedeutet, dass der Parameter der aufgerufenen Funktionen eine Kopie des übergebenen Arguments des Aufrufers ist. Der Wert ist der gleiche, aber die Identität - die Variable - ist unterschiedlich. Änderungen an einem Parameter, die von der aufgerufenen Funktion ausgeführt werden, ändern in einem Fall das übergebene Argument und im anderen Fall nur den Wert des Parameters in der aufgerufenen Funktion (die nur eine Kopie ist). In kurzer Zeit:
ref
das beim Aufrufer verwendet wird und die aufgerufene Funktion). Jon Skeet hat auch eine schöne Erklärung dafür hier .Codes
Da meine Sprache C ++ ist, werde ich das hier verwenden
// passes a pointer (called reference in java) to an integer
void call_by_value(int *p) { // :1
p = NULL;
}
// passes an integer
void call_by_value(int p) { // :2
p = 42;
}
// passes an integer by reference
void call_by_reference(int & p) { // :3
p = 42;
}
// this is the java style of passing references. NULL is called "null" there.
void call_by_value_special(int *p) { // :4
*p = 10; // changes what p points to ("what p references" in java)
// only changes the value of the parameter, but *not* of
// the argument passed by the caller. thus it's pass-by-value:
p = NULL;
}
int main() {
int value = 10;
int * pointer = &value;
call_by_value(pointer); // :1
assert(pointer == &value); // pointer was copied
call_by_value(value); // :2
assert(value == 10); // value was copied
call_by_reference(value); // :3
assert(value == 42); // value was passed by reference
call_by_value_special(pointer); // :4
// pointer was copied but what pointer references was changed.
assert(value == 10 && pointer == &value);
}
Und ein Beispiel in Java wird nicht schaden:
class Example {
int value = 0;
// similar to :4 case in the c++ example
static void accept_reference(Example e) { // :1
e.value++; // will change the referenced object
e = null; // will only change the parameter
}
// similar to the :2 case in the c++ example
static void accept_primitive(int v) { // :2
v++; // will only change the parameter
}
public static void main(String... args) {
int value = 0;
Example ref = new Example(); // reference
// note what we pass is the reference, not the object. we can't
// pass objects. The reference is copied (pass-by-value).
accept_reference(ref); // :1
assert ref != null && ref.value == 1;
// the primitive int variable is copied
accept_primitive(value); // :2
assert value == 0;
}
}
Wikipedia
http://en.wikipedia.org/wiki/Pass_by_reference#Call_by_value
http://en.wikipedia.org/wiki/Pass_by_reference#Call_by_reference
Dieser Typ nagelt es so ziemlich:
Viele Antworten hier (und insbesondere die am besten bewertete Antwort) sind sachlich falsch, da sie falsch verstehen, was "Call by Reference" wirklich bedeutet. Hier ist mein Versuch, die Sache klar zu stellen.
In einfachsten Worten:
In metaphorischen Begriffen:
Beachten Sie, dass diese beiden Konzepte völlig unabhängig und orthogonal vom Konzept der Referenztypen (die in Java alle Typen sind, die Untertypen sind Object
, und in C # alle class
Typen) oder vom Konzept der Zeigertypen wie in C (die semantisch äquivalent sind) sind zu Javas "Referenztypen", einfach mit unterschiedlicher Syntax).
Der Begriff des Referenztyps entspricht einer URL: Er ist sowohl selbst eine Information als auch eine Referenz (ein Zeiger , wenn Sie so wollen) auf andere Informationen. Sie können viele Kopien einer URL an verschiedenen Stellen haben, und sie ändern nicht, auf welche Website sie alle verlinken. Wenn die Website aktualisiert wird, führt jede URL-Kopie weiterhin zu den aktualisierten Informationen. Umgekehrt wirkt sich das Ändern der URL an einer beliebigen Stelle nicht auf eine andere schriftliche Kopie der URL aus.
Beachten Sie, dass C ++ hat einen Begriff von „Referenzen“ (zB int&
) , das ist nicht wie Java und C # 's ‚Referenz - Typen‘, sondern ist wie ‚call by reference‘. Die "Referenztypen" von Java und C # sowie alle Typen in Python entsprechen denen, die C und C ++ als "Zeigertypen" bezeichnen (z int*
. B. ).
OK, hier ist die längere und formellere Erklärung.
Zunächst möchte ich einige wichtige Begriffe hervorheben, um meine Antwort zu verdeutlichen und sicherzustellen, dass wir uns bei der Verwendung von Wörtern alle auf dieselben Ideen beziehen. (In der Praxis glaube ich, dass die überwiegende Mehrheit der Verwirrung über Themen wie diese darauf zurückzuführen ist, dass Wörter so verwendet werden, dass die beabsichtigte Bedeutung nicht vollständig kommuniziert wird.)
Hier ist zunächst ein Beispiel in einer C-ähnlichen Sprache für eine Funktionsdeklaration:
void foo(int param) { // line 1
param += 1;
}
Und hier ist ein Beispiel für den Aufruf dieser Funktion:
void bar() {
int arg = 1; // line 2
foo(arg); // line 3
}
Anhand dieses Beispiels möchte ich einige wichtige Begriffe definieren:
foo
ist eine in Zeile 1 deklarierte Funktion (Java besteht darauf, alle Funktionsmethoden zu erstellen, aber das Konzept ist das gleiche ohne Verlust der Allgemeinheit; C und C ++ unterscheiden zwischen Deklaration und Definition, auf die ich hier nicht näher eingehen werde).param
ist ein formaler Parameter von foo
, der ebenfalls in Zeile 1 deklariert istarg
ist eine Variable , insbesondere eine lokale Variable der Funktion bar
, die in Zeile 2 deklariert und initialisiert wirdarg
ist auch ein Argument für einen bestimmten Aufruf von foo
in Zeile 3Hier sind zwei sehr wichtige Konzepte zu unterscheiden. Der erste ist Wert gegen Variable :
bar
obigen Funktion int arg = 1;
hat der Ausdruck beispielsweise nach der Zeile arg
den Wert 1
.final
oder C # deklariert readonly
) oder tief unveränderlich (z. B. mit C ++ const
) sein.Das andere wichtige Konzeptpaar, das unterschieden werden muss, ist Parameter gegenüber Argument :
Beim Aufruf nach Wert sind die formalen Parameter der Funktion Variablen, die für den Funktionsaufruf neu erstellt und mit den Werten ihrer Argumente initialisiert werden .
Dies funktioniert genauso wie alle anderen Arten von Variablen mit Werten initialisiert werden. Zum Beispiel:
int arg = 1;
int another_variable = arg;
Hier arg
und another_variable
sind völlig unabhängige Variablen - ihre Werte können sich unabhängig voneinander ändern. An dem Punkt, an dem another_variable
deklariert wird, wird es jedoch so initialisiert, dass es denselben Wert enthält, der arg
gilt - nämlich 1
.
Da es sich um unabhängige Variablen handelt, wirken sich Änderungen another_variable
nicht auf Folgendes aus arg
:
int arg = 1;
int another_variable = arg;
another_variable = 2;
assert arg == 1; // true
assert another_variable == 2; // true
Dies ist genau das gleiche wie die Beziehung zwischen arg
und param
in unserem obigen Beispiel, die ich hier aus Symmetriegründen wiederholen werde:
void foo(int param) {
param += 1;
}
void bar() {
int arg = 1;
foo(arg);
}
Es ist genau so, als hätten wir den Code so geschrieben:
// entering function "bar" here
int arg = 1;
// entering function "foo" here
int param = arg;
param += 1;
// exiting function "foo" here
// exiting function "bar" here
Das heißt, das definierende Merkmal dessen, was Call by Value bedeutet, ist, dass der Angerufene ( foo
in diesem Fall) Werte als Argumente empfängt , aber eine eigene separate hat für diese Werte Variablen von den Variablen des Aufrufers ( bar
in diesem Fall) hat.
Zurück zu meiner Metapher oben: Wenn ich bar
und du sind foo
, wenn ich dich anrufe , gebe ich dir ein Stück Papier mit einem darauf geschriebenen Wert . Sie nennen das Stück Papier param
. Dieser Wert ist eine Kopie des Werts, den ich in mein Notizbuch (meine lokalen Variablen) in einer von mir aufgerufenen Variablen geschrieben habe arg
.
(Nebenbei: Je nach Hardware und Betriebssystem gibt es verschiedene Aufrufkonventionen, wie Sie eine Funktion von einer anderen aufrufen. Die Aufrufkonvention ist so, als würden wir entscheiden, ob ich den Wert auf ein Stück meines Papiers schreibe und ihn Ihnen dann übergebe oder wenn Sie ein Stück Papier haben, auf das ich es schreibe, oder wenn ich es vor uns beiden an die Wand schreibe. Dies ist ebenfalls ein interessantes Thema, das jedoch weit über den Rahmen dieser bereits langen Antwort hinausgeht.)
Beim Aufruf per Referenz sind die formalen Parameter der Funktion einfach neue Namen für dieselben Variablen, die der Aufrufer als Argumente angibt.
Zurück zu unserem obigen Beispiel: Es entspricht:
// entering function "bar" here
int arg = 1;
// entering function "foo" here
// aha! I note that "param" is just another name for "arg"
arg /* param */ += 1;
// exiting function "foo" here
// exiting function "bar" here
Da param
es sich nur um einen anderen Namen handelt arg
- das heißt, es handelt sich um dieselbe Variable , in der sich Änderungen param
widerspiegelnarg
. Dies ist die grundlegende Art und Weise, in der sich Call by Reference von Call by Value unterscheidet.
Sehr wenige Sprachen unterstützen Call-by-Reference, aber C ++ kann dies folgendermaßen tun:
void foo(int& param) {
param += 1;
}
void bar() {
int arg = 1;
foo(arg);
}
In diesem Fall param
muss nicht nur den gleichen Wert wie arg
es tatsächlich ist arg
(nur unter einem anderen Namen) und so bar
kann beobachten , dassarg
erhöht wurde.
Beachten Sie, dass dies ist nicht wie jeder von Java, JavaScript, C, Objective-C, Python, oder fast jede andere populäre Sprache heute funktioniert. Dies bedeutet, dass diese Sprachen nicht sind als Referenz aufgerufen werden, sondern als Wert.
Wenn das, was Sie haben, ein Aufruf nach Wert ist, der tatsächliche Wert jedoch ein Referenztyp oder ein Zeigertyp ist , ist der "Wert" selbst nicht sehr interessant (z. B. in C ist es nur eine Ganzzahl einer plattformspezifischen Größe) - was ist Interessant ist, worauf dieser Wert hinweist .
Wenn das, worauf dieser Referenztyp ( dh der Zeiger) zeigt, veränderbar ist ein interessanter Effekt möglich: Sie können den Wert, auf den gezeigt wird, ändern, und der Aufrufer kann Änderungen des Werts beobachten, auf den gezeigt wird, obwohl der Anrufer dies nicht beobachten kann wechselt zum Zeiger selbst.
Um die Analogie der URL noch einmal auszuleihen, ist die Tatsache, dass ich Ihnen eine Kopie der URL zu einer Website gegeben habe, nicht besonders interessant, wenn es uns beiden um die Website geht, nicht um die URL. Die Tatsache, dass Sie über Ihre Kopie der URL kritzeln, wirkt sich nicht auf meine Kopie der URL aus. Dies ist uns egal (und in Sprachen wie Java und Python kann dies die "URL" oder der Referenztypwert überhaupt nicht modifiziert werden, nur das, worauf es hinweist, kann).
Als Barbara Liskov die CLU-Programmiersprache (die diese Semantik hatte) erfand, stellte sie fest, dass die vorhandenen Begriffe "Call by Value" und "Call by Reference" für die Beschreibung der Semantik dieser neuen Sprache nicht besonders nützlich waren. Also erfand sie einen neuen Begriff: Call by Object Sharing .
Wenn ich über Sprachen spreche, die technisch nach Wert aufgerufen werden, bei denen jedoch häufig verwendete Referenz- oder Zeigertypen verwendet werden (dh fast jede moderne imperative, objektorientierte oder Multi-Paradigma-Programmiersprache), finde ich dies viel weniger verwirrend Vermeiden Sie es einfach, über Call by Value oder Call by Reference zu sprechen . Halten Sie sich an die gemeinsame Nutzung von Objekten (oder rufen Sie einfach nach Objekten an ), und niemand wird verwirrt sein. :-)
The first is value versus variable.
The other important pair of concepts to distinguish is parameter versus argument:
Bevor Sie die beiden Begriffe verstehen , MÜSSEN Sie Folgendes verstehen. Jedes Objekt hat zwei Dinge, die es unterscheiden können.
Also wenn du sagst employee.name = "John"
Ich weiß, dass es zwei Dinge gibt name
. Sein Wert, der ist, "John"
und auch seine Position im Speicher, die eine hexadezimale Zahl ist, könnten wie folgt aussehen : 0x7fd5d258dd00
.
Abhängig von der Architektur der Sprache oder dem Typ (Klasse, Struktur usw.) Ihres Objekts würden Sie entweder "John"
oder übertragen0x7fd5d258dd00
Das Übergeben "John"
wird als Übergeben nach Wert bezeichnet. Das Übergeben 0x7fd5d258dd00
wird als Übergeben als Referenz bezeichnet. Jeder, der auf diesen Speicherort zeigt, hat Zugriff auf den Wert von "John"
.
Um mehr darüber zu erfahren , empfehle ich Ihnen, sich über die Dereferenzierung eines Zeigers zu informieren und darüber, warum Sie struct (Werttyp) anstelle von class (Referenztyp) wählen.
Hier ist ein Beispiel:
#include <iostream>
void by_val(int arg) { arg += 2; }
void by_ref(int&arg) { arg += 2; }
int main()
{
int x = 0;
by_val(x); std::cout << x << std::endl; // prints 0
by_ref(x); std::cout << x << std::endl; // prints 2
int y = 0;
by_ref(y); std::cout << y << std::endl; // prints 2
by_val(y); std::cout << y << std::endl; // prints 2
}
y
wurde in der vorhergehenden Zeile bereits auf 2 gesetzt. Warum sollte es auf 0 zurückgehen?
Der einfachste Weg, dies zu erreichen, ist eine Excel-Datei. Nehmen wir zum Beispiel an, Sie haben zwei Zahlen, 5 und 2 in den Zellen A1 und B1, und Sie möchten ihre Summe in einer dritten Zelle finden, sagen wir A2. Sie können dies auf zwei Arten tun.
Entweder indem Sie ihre Werte an Zelle A2 übergeben, indem Sie = 5 + 2 in diese Zelle eingeben . In diesem Fall bleibt die Summe in A2 gleich, wenn sich die Werte der Zellen A1 oder B1 ändern.
Oder indem Sie die "Referenzen" der Zellen A1 und B1 an Zelle A2 übergeben, indem Sie = A1 + B1 eingeben . In diesem Fall ändert sich auch die Summe in A2, wenn sich die Werte der Zellen A1 oder B1 ändern.
Wenn Sie an ref vorbeikommen, übergeben Sie grundsätzlich einen Zeiger auf die Variable. Als Wert übergeben Sie übergeben eine Kopie der Variablen. In der Grundverwendung bedeutet dies normalerweise, dass Änderungen an der Variablen, die als Referenz übergeben werden, als aufrufende Methode angesehen werden und als Wert übergeben werden, den sie nicht verwenden.
Übergeben nach Wert sendet eine KOPIE der Daten, die in der von Ihnen angegebenen Variablen gespeichert sind. Übergeben als Referenz sendet eine direkte Verknüpfung zur Variablen selbst. Wenn Sie also eine Variable als Referenz übergeben und dann die Variable innerhalb des Blocks ändern, in den Sie sie übergeben haben, wird die ursprüngliche Variable geändert. Wenn Sie einfach den Wert übergeben, kann die ursprüngliche Variable von dem Block, in den Sie sie übergeben haben, nicht geändert werden. Sie erhalten jedoch eine Kopie dessen, was zum Zeitpunkt des Aufrufs enthalten war.
Wert übergeben - Die Funktion kopiert die Variable und arbeitet mit einer Kopie (sodass an der ursprünglichen Variablen nichts geändert wird).
Referenzübergabe - Die Funktion verwendet die ursprüngliche Variable. Wenn Sie die Variable in der anderen Funktion ändern, ändert sich auch die ursprüngliche Variable.
Beispiel (kopieren und verwenden / versuchen Sie dies selbst und sehen Sie):
#include <iostream>
using namespace std;
void funct1(int a){ //pass-by-value
a = 6; //now "a" is 6 only in funct1, but not in main or anywhere else
}
void funct2(int &a){ //pass-by-reference
a = 7; //now "a" is 7 both in funct2, main and everywhere else it'll be used
}
int main()
{
int a = 5;
funct1(a);
cout<<endl<<"A is currently "<<a<<endl<<endl; //will output 5
funct2(a);
cout<<endl<<"A is currently "<<a<<endl<<endl; //will output 7
return 0;
}
Halte es einfach, guck mal. Textwände können eine schlechte Angewohnheit sein.
Ein Hauptunterschied zwischen ihnen besteht darin, dass Variablen vom Werttyp Werte speichern. Wenn Sie also eine Variable vom Typ Wert in einem Methodenaufruf angeben, wird eine Kopie des Werts dieser Variablen an die Methode übergeben. Variablen vom Referenztyp speichern Verweise auf Objekte. Wenn Sie also eine Variable vom Referenztyp als Argument angeben, wird der Methode eine Kopie der tatsächlichen Referenz übergeben, die auf das Objekt verweist. Obwohl die Referenz selbst als Wert übergeben wird, kann die Methode die empfangene Referenz weiterhin verwenden, um mit dem ursprünglichen Objekt zu interagieren und es möglicherweise zu ändern. In ähnlicher Weise gibt die Methode beim Zurückgeben von Informationen von einer Methode über eine return-Anweisung eine Kopie des in einer Variablen vom Wertetyp gespeicherten Werts oder eine Kopie der in einer Variablen vom Referenztyp gespeicherten Referenz zurück. Wenn eine Referenz zurückgegeben wird, kann die aufrufende Methode diese Referenz verwenden, um mit dem referenzierten Objekt zu interagieren. Damit,
Um in c # eine Variable als Referenz zu übergeben, damit die aufgerufene Methode die Variablen ändern kann, stellt C # die Schlüsselwörter ref und out bereit. Durch Anwenden des Schlüsselworts ref auf eine Parameterdeklaration können Sie eine Variable als Referenz an eine Methode übergeben. Die aufgerufene Methode kann die ursprüngliche Variable im Aufrufer ändern. Das Schlüsselwort ref wird für Variablen verwendet, die bereits in der aufrufenden Methode initialisiert wurden. Wenn ein Methodenaufruf eine nicht initialisierte Variable als Argument enthält, generiert der Compiler normalerweise einen Fehler. Wenn Sie einem Parameter mit dem Schlüsselwort out vorangehen, wird ein Ausgabeparameter erstellt. Dies zeigt dem Compiler an, dass das Argument als Referenz an die aufgerufene Methode übergeben wird und dass die aufgerufene Methode der ursprünglichen Variablen im Aufrufer einen Wert zuweist. Wenn die Methode dem Ausgabeparameter nicht in jedem möglichen Ausführungspfad einen Wert zuweist, generiert der Compiler einen Fehler. Dies verhindert auch, dass der Compiler eine Fehlermeldung für eine nicht initialisierte Variable generiert, die als Argument an eine Methode übergeben wird. Eine Methode kann über eine return-Anweisung nur einen Wert an ihren Aufrufer zurückgeben, aber durch Angabe mehrerer Ausgabeparameter (ref und / oder out) viele Werte zurückgeben.
siehe c # Diskussion und Beispiele hier Linktext
Beispiele:
class Dog
{
public:
barkAt( const std::string& pOtherDog ); // const reference
barkAt( std::string pOtherDog ); // value
};
const &
ist in der Regel am besten. Sie müssen keine Bau- und Zerstörungsstrafe zahlen. Wenn die Referenz nicht const ist, schlägt Ihre Schnittstelle vor, die übergebenen Daten zu ändern.
Kurz gesagt, Übergeben als Wert ist WAS es ist und als Referenz übergeben ist WO es ist.
Wenn Ihr Wert VAR1 = "Happy Guy!" Ist, wird nur "Happy Guy!" Angezeigt. Wenn VAR1 zu "Happy Gal!" Wechselt, wissen Sie das nicht. Wenn es als Referenz übergeben wird und sich VAR1 ändert, werden Sie.
Wenn Sie den Wert der ursprünglichen Variablen nach der Übergabe an eine Funktion nicht ändern möchten, sollte die Funktion mit einem " Übergabewert " erstellt werden Parameter " erstellt werden.
Dann hat die Funktion NUR den Wert, aber nicht die Adresse der übergebenen Variablen. Ohne die Adresse der Variablen kann der Code innerhalb der Funktion den Variablenwert von außerhalb der Funktion nicht ändern.
Wenn Sie der Funktion jedoch die Möglichkeit geben möchten, den Wert der Variablen von außen gesehen zu ändern , müssen Sie die Referenzübergabe verwenden . Da sowohl der Wert als auch die Adresse (Referenz) übergeben werden und innerhalb der Funktion verfügbar sind.
Wert übergeben bedeutet, wie ein Wert unter Verwendung von Argumenten an eine Funktion übergeben wird. Bei der Übergabe des Wertes kopieren wir die Daten, die in der von uns angegebenen Variablen gespeichert sind, und sie sind langsamer als die Übergabe als Referenz, da die Daten kopiert werden. Wenn wir Änderungen an den kopierten Daten vornehmen, sind die Originaldaten nicht betroffen. nd in pass by refernce oder pass by address senden wir einen direkten Link zur Variablen selbst. oder Zeiger auf eine Variable übergeben. Es ist schneller, da weniger Zeit verbraucht wird
Hier ist ein Beispiel, das die Unterschiede zwischen Wertübergabe - Zeigerwert - Referenz zeigt :
void swap_by_value(int a, int b){
int temp;
temp = a;
a = b;
b = temp;
}
void swap_by_pointer(int *a, int *b){
int temp;
temp = *a;
*a = *b;
*b = temp;
}
void swap_by_reference(int &a, int &b){
int temp;
temp = a;
a = b;
b = temp;
}
int main(void){
int arg1 = 1, arg2 = 2;
swap_by_value(arg1, arg2);
cout << arg1 << " " << arg2 << endl; //prints 1 2
swap_by_pointer(&arg1, &arg2);
cout << arg1 << " " << arg2 << endl; //prints 2 1
arg1 = 1; //reset values
arg2 = 2;
swap_by_reference(arg1, arg2);
cout << arg1 << " " << arg2 << endl; //prints 2 1
}
Die Methode "Referenzübergabe" weist eine wichtige Einschränkung auf . Wenn ein Parameter als Referenz übergeben deklariert wird (daher steht vor dem & -Zeichen), muss sein entsprechender tatsächlicher Parameter eine Variable sein .
Ein tatsächlicher Parameter, der sich auf den formalen Parameter "übergeben durch Wert" bezieht, kann im Allgemeinen ein Ausdruck sein , sodass nicht nur eine Variable, sondern auch ein Literal oder sogar das Ergebnis eines Funktionsaufrufs verwendet werden darf.
Die Funktion kann keinen Wert in etwas anderes als eine Variable setzen. Es kann einem Literal keinen neuen Wert zuweisen oder einen Ausdruck zwingen, sein Ergebnis zu ändern.
PS: Sie können auch die Antwort von Dylan Beattie im aktuellen Thread überprüfen, der sie in einfachen Worten erklärt.