Care este diferența între
Mi-ai putea da cateva exemple, te rog?
Acum, autentic definiție este:
Acum, în limbile moderne, variabile tind să fie de "tipuri de referință" (un alt concept inventat mai târziu decât "trece de referință" și inspirat de ea), adică obiectul real datele sunt stocate separat undeva (de obicei, pe heap), și doar "referințe" pentru aceasta sunt organizate vreodată în variabile și transmise ca parametri.3 Trece o astfel de referință cade sub pass-by-value pentru o variabilă's valoare este punct de vedere tehnic de referință, în sine, nu face referire obiect. Cu toate acestea, efectul net pe programul poate fi aceeași fie ca pass-by-value sau trece de referință:
NOTĂ: Pentru o lungă perioadă de timp, acest răspuns obișnuia să spună:
Spun, vreau să împărtășesc o pagină web cu tine. Dacă-ți spun URL-ul, am'm trecerea de referință. Puteți utiliza URL-ul pentru a vedea aceeași pagină web am se poate vedea. Dacă pagina este schimbat, ne-am vedea modificările. Dacă ștergeți URL-ul, tot ce're face este de a distruge dvs. de referință la care pagina - ai're nu ștergerea efectivă pagina în sine.
Dacă nu imprimați pagina si da imprimat, am'm in trecere prin valoare. Pagina dvs. este un deconectat copie a originalului. Ai câștigat't vedea orice modificări ulterioare, precum și orice modificări pe care le face (de exemplu, scriind pe imprimare) nu va apărea pe pagina originală. Dacă distruge imprimare, aveți de fapt au distrus-o copie a obiect - dar pagina web originală rămâne intact. Acest lucru este mostly corectă except în sens mai restrâns de "de referință" - aceasta fiind atât temporară, cât și implicite (nu't trebuie, dar fiind explicită și/sau persistente sunt caracteristici suplimentare, nu o parte a trece de referință semantică, așa cum am explicat mai sus). O mai strânsă analogie ar fi oferindu-vă o copie a unui document vs invitându-vă să lucreze pe original.
1Dacă nu sunteți de programare în Fortran sau Visual Basic, l's nu comportamentul implicit, și în cele mai multe limbi în utilizarea modernă, adevărat apel de referință nu este posibil. 2O valoare justă de cei mai în vârstă susțin, de asemenea 3În mai multe limbi moderne, toate tipurile sunt tipuri referință. Această abordare a fost inițiată de limba CLU în 1975 și de atunci a fost adoptat de multe alte limbi, inclusiv în Python și Ruby. Și mult mai multe limbi folosesc o abordare hibridă, în cazul în care unele tipuri sunt "tipuri de valoare", iar altele sunt "tipuri de referință", printre ei sunt C#, Java, JavaScript și. 4Nu's nimic rău cu reciclarea unui montaj vechiul termen per se, dar unul are de a face într-un fel clar care sensul este folosit de fiecare dată. Nu fac asta este exact ceea ce ține provocând confuzie.
L's o modalitate de cum să treacă argumente la funcții. Trecerea de referință înseamnă a sunat funcții' parametru va fi la fel ca apelantii' a trecut argument (nu valoarea, dar identitatea - variabila în sine). Trece de valoare înseamnă a sunat funcții' parametru va fi o copie a apelanților' a trecut argument. Valoarea va fi la fel, dar identitatea - variabila - este diferit. Astfel de modificări de la un parametru realizat prin funcția numită într-un caz modificări argumentul trecut și în celălalt caz se schimbă doar valoarea parametrului numit în funcție (care este doar o copie). Într-un mod rapid grabă:
ref
folosit la apelant și numește funcție). Jon Skeet, de asemenea, are o frumoasă explicație a acestui aici.Coduri
Deoarece limba mea este C++, voi folosi aici
// 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);
}
Și un exemplu în Java câștigat't rănit:
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
Acest tip destul de mult unghiile:
Multe răspunsuri (în special cele mai extrem de upvoted răspuns) sunt incorecte, deoarece au înțeles greșit ceea ce "apel de referință" înseamnă cu adevărat. Aici's my încerca să aranjez lucrurile în ordine.
În termeni simpli:
int&
), care este nu cum ar fi Java și C#'s "tipuri de referință", dar e ca "apel de referință". Java și C#'s "tipuri de referință" și toate tipuri în Python, sunt ca ceea ce C și C++ apel "indicatorul de tipuri de" (de exemplu, int*
). OK, aici's mai mult și mai mult explicație oficială.
Pentru a începe cu, aș dori să subliniez unele părți importante de terminologie, pentru a ajuta la clarificarea răspunsul meu și pentru a ne asigura're toate referindu-se la aceleași idei atunci când folosim cuvinte. (În practică, cred că marea majoritate de confuzie cu privire la subiecte cum ar fi acestea rezultă din utilizarea de cuvinte în moduri care să nu comunica pe deplin sensul că a fost destinat.) Pentru a începe, aici's un exemplu în unele C-ca limbă de o declarație a funcției:
void foo(int param) { // line 1
param += 1;
}
Și aici's un exemplu de asteptare această funcție:
void bar() {
int arg = 1; // line 2
foo(arg); // line 3
}
Folosind acest exemplu, vreau să definesc unele părți importante ale terminologiei:
param
e o parametru formal a "foo", a declarat, de asemenea, pe linia 1 arg
e o variabile, în special o variabile locale funcția "bar", declarată și inițializată pe linia 2 arg
este, de asemenea, o argument la o anumit invocarea de " foo " pe linia 3
Există două foarte importante seturi de concepte pentru a distinge aici. Prima este valoarea față variabile: int arg = 1;
, expresia arg
are valoarea 1
. final
sau C#'s readonly
) sau profund imuabile (de exemplu, folosind C++'s const
).
Alte importante pereche de concepte pentru a distinge este parametru față argument: În apel de valoare, funcția's parametrii formali sunt variabile care sunt nou create pentru funcția de invocare, și care sunt inițializate cu valori de argumentele lor. Aceasta funcționează exact la fel ca orice alte tipuri de variabilele sunt inițializate cu valori. De exemplu:
int arg = 1;
int another_variable = arg;
Aici arg " și " another_variable
sunt complet independente variabile, valorile lor se poate schimba în mod independent unul de celălalt. Cu toate acestea, de la punctul unde another_variableeste declarată, este inițializat să dețină aceeași valoare ca
argdeține -- care este
1. Deoarece acestea sunt variabile independente, modificări la
another_variablenu afecta
arg`:
int arg = 1;
int another_variable = arg;
another_variable = 2;
assert arg == 1; // true
assert another_variable == 2; // true
Acest lucru este exact la fel ca relația dintre arg " și " param
în exemplul nostru de mai sus, pe care am'll repet aici pentru simetrie:
void foo(int param) {
param += 1;
}
void bar() {
int arg = 1;
foo(arg);
}
Este exact ca și cum am fi scris codul de acest fel:
// entering function "bar" here
int arg = 1;
// entering function "foo" here
int param = arg;
param += 1;
// exiting function "foo" here
// exiting function "bar" here
Asta este, caracteristica definitorie a ce apel de valoare înseamnă că persoana ("foo" în acest caz) primește valori ca argumente, dar are propriile sale separate variabile pentru cei valorile din variabilele apelantului ("bar" în acest caz).
Mă voi întoarce la metafora de mai sus, dacă am'm " bar "și te're "foo", atunci când te sun, te mână o bucată de hârtie cu o valoare scris pe ea. Asta numești tu bucată de hârtie param
. Această valoare este un copia* din valoarea am scris în caietul meu (mea variabile locale), într-o variabilă eu numesc arg
.
(Ca o paranteză: în funcție de hardware-ul și sistemul de operare, există diverse de asteptare convenții* despre cum de a apela o funcție la alta. Chemarea convenția este ca noi decide dacă am scrie valoarea pe o bucată de hârtie și apoi mana la tine, sau dacă aveți o bucată de hârtie pe care am scris-o, sau daca am scrie pe peretele din fața noastră. Acesta este un subiect interesant, dar mult dincolo de domeniul de aplicare al prezentului deja de mult răspunsul.)
În apel de referință, funcția's parametrii formali sunt pur și simplu nume noi pentru aceleași variabile care apelantul provizii ca argumente. Revenind la exemplul de mai sus, l's echivalentă cu:
// 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
Din param
este doar un alt nume pentru arg
- care este, ele sunt aceeași variabilă, modificări la param
sunt reflectate în arg
. Acesta este modul fundamental în care apelul prin referință diferă de apel de valoare.
Foarte puține limbi de sprijin apel de referință, dar în C++ se poate face astfel:
void foo(int& param) {
param += 1;
}
void bar() {
int arg = 1;
foo(arg);
}
În acest caz, param
nu't doar au aceeași valoare ca arg
, de fapt e arg
(doar prin nume diferite) și deci " bar " se poate observa că arg
a fost incrementat.
Rețineți că acest lucru este nu cum de Java, JavaScript, C, Objective-C, Python, sau aproape orice alt limbaj popular astăzi funcționează. Acest lucru înseamnă că aceste limbi sunt nu apel de referință, acestea sunt de apel de valoare.
Dacă ceea ce ai este apel de valoare, dar valoarea reală este un tipul de referință sau pointer tip, apoi "valoarea" se't foarte interesante (de exemplu, în C l's doar un număr întreg de o platforma-dimensiune specifică) - ceea ce's interesant este ce valoare puncte. Dacă ce tip de referință (care este, pointer) puncte de la e mutabil apoi un efect interesant este posibilă: puteți modifica subliniat-la valoare, și apelantul poate observa modificări subliniat-la valoare, chiar dacă apelantul nu poate observa modificări ale indicatorului în sine. Pentru a împrumuta analogie de URL-ul din nou, faptul că ți-am dat o copia a URL-ului catre un site nu este deosebit de interesant dacă ne pasă este site-ul, nu URL-ul. Faptul că scriind peste copie a URL-ului nu't mi afecteze copie a URL-ul nu't un lucru care ne interesează (și, de fapt, în limbaje cum ar fi Java și Python "URL", sau o referință de tip valoare, poate't fi modificate deloc, singurul lucru subliniat de se poate). Barbara Liskov, atunci când ea a inventat CLU limbaj de programare (care a avut aceste semantica), a dat seama că condițiile existente "apel de valoare" și "apel de referință" nu't deosebit de util pentru a descrie semantica acestui nou limbaj. Așa că a inventat un nou termen: apel către obiect partajarea. Atunci când se discută de limbi, care sunt punct de vedere tehnic apel de valoare, dar în cazul în tipurile comune în utilizare sunt de referință sau un pointer tipuri (care este: aproape fiecare modern imperativ, orientat-obiect, sau multi-paradigmă limbaj de programare), am găsi-o's mult mai puțin confuz pentru a evita, pur și simplu vorbesc despre apel de valoare sau apel de referință. Stick la apel către obiect partajarea (sau pur și simplu apel de obiect) și nimeni nu va fi confuz. :-)
Înainte de înțelegerea de 2 termeni, vă TREBUIE să înțeleagă următoarele. Fiecare obiect, are 2 lucrurile care pot fi distinse.
Deci, dacă spui angajat.nume = "John"
știu că acolo sunt 2 lucruri despre "nume". Valoarea care este"John" și, de asemenea, locația sa în memorie, care este un număr hexazecimal poate ca aceasta: 0x7fd5d258dd00
.
În funcție de limba's arhitectură sau tip (class, struct, etc.) de obiect, v-ar fi transferul de "John" " sau " 0x7fd5d258dd00
Trece "John" este cunoscut ca trece prin valoare. Trece
0x7fd5d258dd00este cunoscut ca trece de referință. Oricine care este îndreptat la această locație de memorie vor avea acces la valoarea de
"John"`.
Pentru mai multe detalii despre acest lucru, vă recomand să citiți despre dereferencing un pointer și, de asemenea, de ce să alegeți struct (tip valoare) pe clasa (tipul de referință)
Aici este un exemplu:
#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
}
Cel mai simplu mod de a obține acest lucru este pe un fișier Excel. Să spunem de exemplu că ai două numere, 5 și 2 în celulele A1 și B1, în consecință, și doriți să găsiți suma lor într-o a treia celulă, să's spun A2. Puteți face acest lucru în două moduri.
Fie prin trecerea lor de valori de la celula A2 prin tastarea = 5 + 2 în această celulă. În acest caz, dacă valorile din celulele A1 sau B1 schimba, suma în A2 rămâne aceeași.
Sau trece "referințe" din celulele A1 și B1 la celula A2 prin tastarea = A1 + B1. În acest caz, dacă valorile din celulele A1 sau B1 schimba, suma în A2 se schimbă, de asemenea.
Atunci când trece printr-ref practic trece un pointer la variabila. Trece de valoare se trece o copie a variabilei. În utilizarea de bază în mod normal trece prin ref schimbări de variabilă va fi văzut de metoda de asteptare si trece prin valoarea ei obiceiul.
Trece prin valoarea trimite o COPIE a datelor stocate în variabila specificată, trece de referință trimite un link direct la variabila în sine. Deci, dacă trece o variabilă de referință și apoi schimbarea de variabilă în interiorul blocului trecut, în original variabilă va fi schimbat. Dacă pur și simplu trece de valoare, variabila originală nu va fi capabil de a fi schimbat de bloc ai trecut-o în dar veți obține o copie a tot ce conținea, la momentul apelului.
Trece de valoare - funcția de exemplare variabila si functioneaza cu o copie(deci nu't schimba nimic în original variabilă)
Trece de referință - funcția folosește variabila originală, dacă vă schimbați variabila în altă funcție, se schimbă în original de asemenea variabilă.
Exemplu(copie și de a folosi/o incerci si tu si vezi) :
#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;
}
Păstrați-l simplu, peeps. Ziduri de text poate fi un obicei prost.
O diferență majoră dintre ele este că valoarea variabile de tip magazin de valori, deci, specificând o valoare de tip variabilă într-un apel de metodă trece o copie a acelei variabile's valoare a metodei. De referință-variabile de tip magazin referințe la obiecte, deci, specificând o referință de tip variabil ca un argument trece la metoda o copie de referința reală care se referă la obiect. Chiar dacă de referință în sine este transmis prin valoare, metoda se poate utiliza în continuare de referință primește pentru a interacționa cu—și, eventual, modifica—obiectul original. În mod similar, atunci când se întorc de informații de la o metodă printr-o declarație de întoarcere, metoda returnează o copie a valorii stocate într-o valoare de tip variabilă sau o copie de referință stocate într-o referință de tip variabil. Atunci când o referință este returnat, metoda de asteptare poate folosi ca referință pentru a interacționa cu referire obiect. Deci, în vigoare, obiectele sunt întotdeauna transmise prin referință.
În c#, pentru a trece o variabilă de referință așa numita metodă poate modifica variabila's, C# oferă cuvinte cheie ref și out. Aplicarea ref cuvinte cheie pentru un parametru declarație vă permite să treacă o variabilă la o metodă de referință—numita metodă va fi capabil de a modifica variabila originală în apelantului. Arbitrul de cuvinte cheie este folosit pentru variabilele care au fost deja inițializat în metoda de asteptare. În mod normal, atunci când un apel de metodă conține o variabila neinitializata ca un argument, compilatorul generează o eroare. Anterior un parametru cu cuvinte cheie de afară creează un parametru de ieșire. Acest lucru indică compilatorului că argumentul va fi trecut în numita metodă de referință și că numita metodă va atribui o valoare inițială variabilei în apelantului. Dacă metoda nu se atribuie o valoare de parametru de ieșire în fiecare cale posibilă de execuție, compilatorul generează o eroare. Acest lucru previne, de asemenea, compilatorul de a genera un mesaj de eroare pentru o variabila neinitializata care este transmis ca argument al unei metode. O metodă poate returna o singură valoare pentru apelant printr-o declarație de întoarcere, dar poate returna mai multe valori prin specificarea multiple output (ref și/sau în afara) parametri.
vezi c# discuții și exemple aici link text
Exemple:
class Dog
{
public:
barkAt( const std::string& pOtherDog ); // const reference
barkAt( std::string pOtherDog ); // value
};
const &
este, în general, mai bune. Nu't suporta construcția și distrugerea de penalizare. Dacă referința e't const interfața este sugerând că se va schimba trecut în date.
Pe scurt, a Trecut prin valoarea este ceea CE este și transmise prin referință este UNDE este.
Dacă valoarea ta este VAR1 = "Tip Fericit!", veți vedea doar "Tip Fericit!". Dacă VAR1 modificări la "Fata Fericita!", ai castigat't știu asta. Daca's a trecut de referință, și VAR1 modificări, va.
Dacă tu nu't doriți să modificați valoarea variabilei originale după trecerea într-o funcție, funcția ar trebui să fie construite cu o "se trece prin valoare" parametru.
Atunci funcția va avea DOAR valoarea, dar nu adresa de trecut în variabilă. Fără variabil's adresa, codul din interiorul funcției nu poate schimba valoarea variabilei după cum se vede din afara funcției.
Dar dacă doriți pentru a da funcția abilitatea de a schimba valoarea variabilei după cum se vede din exterior, aveți nevoie pentru a utiliza trece de referință. Ca valoare și adresa (de referință) sunt transmise în și disponibile în interiorul funcției.
trece de valoare înseamnă cum să treacă valoare a unei funcții prin utilizarea de argumente. în trecere prin valoarea putem copia datele stocate în variabila în care vom specifica și că este mai lent decât să treacă prin referire bcse t a de date este copiat . de vom face modificări în datele copiate datele originale nu este afectată. nd în trecere prin referinta sau trece prin adresa trimitem link-ul direct la variabila în sine . sau trece pointer la o variabilă. este mai rapid bcse mai puțin timp este consumat
Aici este un exemplu care demonstrează diferențele între trece de valoare indicator valoare de referință:
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
}
"Trecerea de referință" metoda a o limitare importantă. Dacă un parametru este declarată ca transmise prin referință (deci este precedată de & sign) corespunzătoare real parametru trebuie să fie o variabilă.
Un parametru real referindu-se la "a trecut de valoare" parametru formal poate fi o expresie în general, așa că este permis să se utilizeze nu numai o variabilă, dar, de asemenea, un literal sau chiar o funcție de invocare's rezultat.
Funcția nu este capabil de a plasa o valoare în altceva decât o variabilă. Nu se poate atribui o valoare nouă pentru un literal sau forțează o expresie să-și schimbe rezultatul.
PS: puteți verifica, de asemenea, Dylan Beattie răspuns în firul curent care explică în cuvinte simple.