Apa perbedaan antara
- parameter yang dilewatkan oleh referensi
- sebuah parameter dilewatkan oleh nilai?
Bisakah Anda memberi saya beberapa contoh?
Apa perbedaan antara
Bisakah Anda memberi saya beberapa contoh?
Jawaban:
Pertama dan terutama, perbedaan "pass by value vs. pass by reference" seperti yang didefinisikan dalam teori CS sekarang sudah usang karena teknik yang awalnya didefinisikan sebagai "pass by reference" sejak itu tidak disukai dan jarang digunakan sekarang. 1
Bahasa yang lebih baru 2 cenderung menggunakan pasangan teknik yang berbeda (tetapi serupa) untuk mencapai efek yang sama (lihat di bawah) yang merupakan sumber utama kebingungan.
Sumber kebingungan kedua adalah fakta bahwa dalam "pass by reference", "reference" memiliki arti yang lebih sempit daripada istilah umum "reference" (karena frasa yang mendahului).
Sekarang, definisi otentik adalah:
Ketika suatu parameter dilewatkan dengan referensi , pemanggil dan callee menggunakan variabel yang sama untuk parameter. Jika callee memodifikasi variabel parameter, efeknya terlihat oleh variabel pemanggil.
Ketika suatu parameter dilewatkan oleh nilai , penelepon dan callee memiliki dua variabel independen dengan nilai yang sama. Jika callee memodifikasi variabel parameter, efeknya tidak terlihat oleh pemanggil.
Hal yang perlu diperhatikan dalam definisi ini adalah:
"Variabel" di sini berarti variabel penelepon (lokal atau global) itu sendiri - yaitu jika saya melewatkan variabel lokal dengan referensi dan menugaskannya, saya akan mengubah variabel penelepon itu sendiri, bukan misalnya apa pun yang menunjuk jika itu adalah penunjuk .
Arti "referensi" dalam "lewat referensi" . Perbedaannya dengan istilah "referensi" umum adalah bahwa "referensi" ini bersifat sementara dan implisit. Apa yang pada dasarnya didapatkan oleh callee adalah "variabel" yang entah bagaimana "sama" dengan yang asli. Seberapa spesifik efek ini dicapai adalah tidak relevan (mis. Bahasa juga dapat mengekspos beberapa detail implementasi - alamat, pointer, dereferencing - ini semua tidak relevan; jika efek bersihnya adalah ini, ini hanya sebagai referensi).
Sekarang, dalam bahasa modern, variabel cenderung berasal dari "tipe referensi" (konsep lain ditemukan lebih lambat dari "lewat referensi" dan diilhami olehnya), yaitu data objek aktual disimpan secara terpisah di suatu tempat (biasanya, di heap), dan hanya "referensi" yang pernah disimpan dalam variabel dan dikirimkan sebagai parameter. 3
Melewati referensi seperti itu jatuh di bawah nilai by-pass karena nilai variabel secara teknis referensi itu sendiri, bukan objek yang dirujuk. Namun, efek bersih pada program bisa sama dengan pass-by-value atau pass-by-reference:
Seperti yang Anda lihat, pasangan teknik ini hampir sama dengan yang ada di definisi, hanya dengan tingkat tipuan: ganti saja "variabel" dengan "objek yang direferensikan".
Tidak ada nama yang disepakati untuk mereka, yang mengarah ke penjelasan yang berkerut seperti "panggilan berdasarkan nilai di mana nilainya adalah referensi". Pada tahun 1975, Barbara Liskov menyarankan istilah " call-by-object-sharing " (atau kadang-kadang hanya "call-by-sharing") meskipun tidak pernah cukup populer. Selain itu, tidak satu pun dari frasa ini yang sejajar dengan pasangan aslinya. Tidak heran istilah lama akhirnya digunakan kembali tanpa adanya sesuatu yang lebih baik, yang menyebabkan kebingungan. 4
CATATAN : Untuk waktu yang lama, jawaban ini digunakan untuk mengatakan:
Katakanlah saya ingin berbagi halaman web dengan Anda. Jika saya memberi tahu Anda URL, saya memberikan referensi. Anda dapat menggunakan URL itu untuk melihat halaman web yang sama dengan yang saya lihat. Jika halaman itu diubah, kami berdua melihat perubahannya. Jika Anda menghapus URL, yang Anda lakukan adalah menghancurkan referensi Anda ke halaman itu - Anda tidak menghapus halaman itu sendiri.
Jika saya mencetak halaman dan memberi Anda hasil cetak, saya memberikan nilai. Halaman Anda adalah salinan asli dari yang terputus. Anda tidak akan melihat perubahan berikutnya, dan perubahan apa pun yang Anda buat (mis. Mencoret-coret pada cetakan Anda) tidak akan muncul di halaman asli. Jika Anda menghancurkan cetakan, Anda sebenarnya telah menghancurkan salinan objek - tetapi halaman web asli tetap utuh.
Ini sebagian besar benar kecuali arti yang lebih sempit dari "referensi" - itu bersifat sementara dan implisit (tidak harus, tetapi menjadi eksplisit dan / atau persisten adalah fitur tambahan, bukan bagian dari semantik pass-by-reference , seperti dijelaskan di atas). Analogi yang lebih dekat akan memberi Anda salinan dokumen vs mengundang Anda untuk mengerjakan yang asli.
1 Kecuali Anda memprogram dalam Fortran atau Visual Basic, itu bukan perilaku default, dan dalam sebagian besar bahasa dalam penggunaan modern, panggilan-dengan-referensi yang sebenarnya bahkan tidak mungkin.
2 Sejumlah yang lebih tua juga mendukungnya
3 Dalam beberapa bahasa modern, semua tipe adalah tipe referensi. Pendekatan ini dipelopori oleh bahasa CLU pada tahun 1975 dan sejak itu telah diadopsi oleh banyak bahasa lain, termasuk Python dan Ruby. Dan masih banyak lagi bahasa yang menggunakan pendekatan hybrid, di mana beberapa tipe adalah "tipe nilai" dan yang lain adalah "tipe referensi" - di antaranya adalah C #, Java, dan JavaScript.
4 Tidak ada yang buruk dengan mendaur ulang istilah lama yang pas , tapi kita harus membuatnya dengan jelas makna mana yang digunakan setiap kali. Tidak melakukan hal itulah yang menyebabkan kebingungan.
Ini adalah cara bagaimana menyampaikan argumen ke fungsi. Melewati dengan referensi berarti parameter fungsi yang dipanggil akan sama dengan argumen yang dilewati oleh penelepon (bukan nilai, tetapi identitas - variabel itu sendiri). Lewat nilai berarti parameter fungsi yang dipanggil akan menjadi salinan dari argumen yang dilewati penelepon. Nilainya akan sama, tetapi identitas - variabel - berbeda. Jadi perubahan pada parameter yang dilakukan oleh fungsi yang dipanggil dalam satu kasus mengubah argumen yang diteruskan dan dalam kasus lain hanya mengubah nilai parameter dalam fungsi yang disebut (yang hanya merupakan salinan). Terburu-buru cepat:
ref
digunakan pada fungsi pemanggil dan dipanggil). Jon Skeet juga memiliki penjelasan yang bagus tentang ini di sini .Kode
Karena bahasa saya adalah C ++, saya akan menggunakannya di sini
// 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);
}
Dan contoh di Jawa tidak akan sakit:
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
Orang ini cukup berhasil:
Banyak jawaban di sini (dan khususnya jawaban yang paling banyak dipilih) secara faktual salah, karena mereka salah mengerti apa arti "panggilan dengan referensi". Inilah upaya saya untuk meluruskan masalah.
Secara sederhana:
Dalam istilah metaforis:
Perhatikan bahwa kedua konsep ini sepenuhnya independen dan ortogonal dari konsep tipe referensi (yang di Jawa adalah semua tipe yang merupakan subtipe dari Object
, dan dalam semua class
tipe C ), atau konsep tipe pointer seperti dalam C (yang secara semantik setara untuk "tipe referensi" Java, hanya dengan sintaks yang berbeda).
Gagasan tipe referensi sesuai dengan URL: itu sendiri merupakan sepotong informasi, dan merupakan referensi (a pointer , jika Anda mau) ke informasi lain. Anda dapat memiliki banyak salinan URL di tempat yang berbeda, dan mereka tidak mengubah situs web yang mereka tautkan; jika situs web diperbarui maka setiap salinan URL masih akan mengarah pada informasi yang diperbarui. Sebaliknya, mengubah URL di satu tempat tidak akan memengaruhi salinan tertulis URL lainnya.
Perhatikan bahwa C ++ memiliki gagasan "referensi" (misalnya int&
) yang tidak seperti Java dan C # 's 'referensi jenis', tetapi adalah seperti 'panggilan dengan referensi'. "Tipe referensi" Java dan C #, dan semua tipe dalam Python, seperti apa yang C dan C ++ sebut "tipe pointer" (mis int*
.).
OKE, inilah penjelasan yang lebih panjang dan lebih formal.
Untuk mulai dengan, saya ingin menyoroti beberapa terminologi penting, untuk membantu memperjelas jawaban saya dan untuk memastikan kita semua mengacu pada ide yang sama ketika kita menggunakan kata-kata. (Dalam praktiknya, saya percaya sebagian besar kebingungan tentang topik-topik seperti ini berasal dari penggunaan kata-kata dengan cara yang tidak sepenuhnya mengomunikasikan makna yang dimaksudkan.)
Untuk memulai, berikut adalah contoh dalam beberapa bahasa mirip C dari deklarasi fungsi:
void foo(int param) { // line 1
param += 1;
}
Dan inilah contoh memanggil fungsi ini:
void bar() {
int arg = 1; // line 2
foo(arg); // line 3
}
Dengan menggunakan contoh ini, saya ingin mendefinisikan beberapa bit penting dari terminologi:
foo
adalah fungsi yang dideklarasikan pada baris 1 (Java bersikeras membuat semua metode fungsi, tetapi konsepnya sama tanpa kehilangan keumuman; C dan C ++ membuat perbedaan antara deklarasi dan definisi yang tidak akan saya bahas di sini)param
adalah parameter formal untuk foo
, juga dinyatakan pada baris 1arg
adalah variabel , khususnya variabel lokal dari fungsi bar
, dideklarasikan dan diinisialisasi pada baris 2arg
juga merupakan argumen untuk spesifik doa dari foo
on line 3Ada dua rangkaian konsep yang sangat penting untuk dibedakan di sini. Yang pertama adalah nilai versus variabel :
bar
fungsi di atas, setelah baris int arg = 1;
, ekspresi arg
memiliki nilai 1
.final
atau C # 'sreadonly
) atau sangat tidak dapat diubah (misalnya menggunakan C ++' s const
).Sepasang konsep penting lainnya untuk dibedakan adalah parameter versus argumen :
Dalam panggilan dengan nilai , parameter formal fungsi adalah variabel yang baru dibuat untuk pemanggilan fungsi, dan yang diinisialisasi dengan nilai argumennya.
Ini bekerja persis dengan cara yang sama seperti jenis variabel lainnya diinisialisasi dengan nilai. Sebagai contoh:
int arg = 1;
int another_variable = arg;
Di sini arg
dan another_variable
merupakan variabel yang sepenuhnya independen - nilainya dapat berubah secara independen satu sama lain. Namun, pada titik di mana another_variable
dinyatakan, diinisialisasi untuk memegang nilai yang sama dengan yang arg
memegang - yaitu 1
.
Karena mereka adalah variabel independen, perubahan another_variable
tidak mempengaruhi arg
:
int arg = 1;
int another_variable = arg;
another_variable = 2;
assert arg == 1; // true
assert another_variable == 2; // true
Ini persis sama dengan hubungan antara arg
dan param
dalam contoh kita di atas, yang akan saya ulangi di sini untuk simetri:
void foo(int param) {
param += 1;
}
void bar() {
int arg = 1;
foo(arg);
}
Persis seperti kita telah menulis kode dengan cara ini:
// entering function "bar" here
int arg = 1;
// entering function "foo" here
int param = arg;
param += 1;
// exiting function "foo" here
// exiting function "bar" here
Yaitu, karakteristik yang menentukan dari apa yang disebut dengan nilai berarti bahwa callee ( foo
dalam hal ini) menerima nilai sebagai argumen, tetapi memiliki variabel tersendiri untuk nilai-nilai tersebut dari variabel pemanggil (bar
dalam kasus ini).
Kembali ke metafora saya di atas, jika saya bar
dan Anda foo
, ketika saya memanggil Anda, saya menyerahkan selembar kertas dengan nilai tertulis di atasnya. Anda menyebut selembar kertas itu param
. Nilai itu adalah salinan dari nilai yang saya tulis di notebook saya (variabel lokal saya), dalam variabel yang saya panggil arg
.
(Sebagai tambahan: tergantung pada perangkat keras dan sistem operasi, ada berbagai konvensi panggilan tentang bagaimana Anda memanggil satu fungsi dari yang lain. Konvensi panggilan seperti kita memutuskan apakah saya menulis nilai pada selembar kertas saya dan kemudian menyerahkannya kepada Anda , atau jika Anda memiliki selembar kertas yang saya tuliskan, atau jika saya menulisnya di dinding di depan kami berdua. Ini juga merupakan subjek yang menarik, tetapi jauh di luar cakupan jawaban yang sudah lama ini.)
Dalam panggilan dengan referensi , parameter formal fungsi hanyalah nama baru untuk variabel yang sama dengan yang diberikan pemanggil sebagai argumen.
Kembali ke contoh kami di atas, itu setara dengan:
// 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
Karena param
hanya nama lain untuk arg
- yaitu, mereka adalah variabel yang sama , perubahan param
tercermin dalamarg
. Ini adalah cara mendasar di mana panggilan dengan referensi berbeda dari panggilan dengan nilai.
Sangat sedikit bahasa yang mendukung panggilan dengan referensi, tetapi C ++ dapat melakukannya seperti ini:
void foo(int& param) {
param += 1;
}
void bar() {
int arg = 1;
foo(arg);
}
Dalam hal ini, param
tidak hanya harus sama nilai seperti arg
, itu benar-benar adalah arg
(hanya dengan nama yang berbeda) dan bar
dapat mengamati bahwa arg
telah bertambah.
Perhatikan bahwa ini bukan cara Java, JavaScript, C, Objective-C, Python, atau hampir semua bahasa populer lainnya saat ini. Ini berarti bahwa bahasa-bahasa itu bukan panggilan dengan referensi, mereka adalah panggilan dengan nilai.
Jika yang Anda miliki adalah panggilan dengan nilai , tetapi nilai sebenarnya adalah tipe referensi atau tipe pointer , maka "nilai" itu sendiri tidak terlalu menarik (misalnya dalam C itu hanya bilangan bulat dari ukuran platform-spesifik) - apa menarik adalah nilai apa yang ditunjukkan .
Jika apa yang ditunjuk oleh tipe referensi (yaitu, pointer) dapat diubah maka efek yang menarik mungkin terjadi: Anda dapat memodifikasi nilai menunjuk-ke, dan penelepon dapat mengamati perubahan pada nilai menunjuk-ke, meskipun penelepon tidak dapat mengamati perubahan pada pointer itu sendiri.
Untuk meminjam analogi URL lagi, fakta bahwa saya memberi Anda salinannya URL ke situs web tidak terlalu menarik jika hal yang kami berdua pedulikan adalah situs web, bukan URL. Fakta bahwa Anda menulis salinan URL tidak memengaruhi salinan URL saya bukanlah hal yang kami pedulikan (dan pada kenyataannya, dalam bahasa seperti Java dan Python "URL", atau nilai jenis referensi, dapat tidak dapat dimodifikasi sama sekali, hanya hal yang ditunjukkan olehnya yang dapat).
Barbara Liskov, ketika dia menemukan bahasa pemrograman CLU (yang memiliki semantik ini), menyadari bahwa istilah yang ada "panggilan berdasarkan nilai" dan "panggilan dengan referensi" tidak terlalu berguna untuk menggambarkan semantik bahasa baru ini. Jadi dia menemukan istilah baru: panggilan dengan berbagi objek .
Ketika membahas bahasa yang secara teknis disebut oleh nilai, tetapi di mana jenis yang umum digunakan adalah tipe referensi atau penunjuk (yaitu: hampir setiap bahasa pemrograman imperatif, berorientasi objek, atau multi-paradigma modern), saya merasa jauh lebih membingungkan untuk hanya menghindari berbicara tentang panggilan berdasarkan nilai atau panggilan dengan referensi . Stick untuk memanggil dengan berbagi objek (atau hanya memanggil dengan objek ) dan tidak ada yang akan bingung. :-)
The first is value versus variable.
The other important pair of concepts to distinguish is parameter versus argument:
Sebelum memahami 2 istilah, Anda HARUS memahami yang berikut. Setiap benda, memiliki 2 hal yang dapat membuatnya dibedakan.
Jadi, jika Anda katakan employee.name = "John"
ketahuilah bahwa ada 2 hal tentang name
. Nilainya yang "John"
dan juga lokasi di memori yang beberapa nomor heksadesimal mungkin seperti ini: 0x7fd5d258dd00
.
Bergantung pada arsitektur bahasa atau jenis (kelas, struct, dll.) Objek Anda, Anda dapat mentransfer "John"
atau0x7fd5d258dd00
Passing "John"
dikenal sebagai passing oleh nilai. Passing 0x7fd5d258dd00
dikenal sebagai passing oleh referensi. Siapa pun yang menunjuk ke lokasi memori ini akan memiliki akses ke nilai "John"
.
Untuk lebih lanjut tentang ini, saya sarankan Anda untuk membaca tentang dereferencing pointer dan juga mengapa memilih struct (tipe nilai) dari kelas (tipe referensi)
Berikut ini sebuah contoh:
#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
telah diatur ke 2 oleh baris sebelumnya. Mengapa kembali ke 0?
Cara paling sederhana untuk mendapatkan ini adalah pada file Excel. Katakanlah misalnya Anda memiliki dua angka, 5 dan 2 dalam sel A1 dan B1 yang sesuai, dan Anda ingin menemukan jumlah mereka dalam sel ketiga, katakanlah A2. Anda dapat melakukan ini dengan dua cara.
Baik dengan mengirimkan nilainya ke sel A2 dengan mengetik = 5 + 2 ke dalam sel ini. Dalam hal ini, jika nilai sel A1 atau B1 berubah, jumlah dalam A2 tetap sama.
Atau dengan melewatkan "referensi" dari sel A1 dan B1 ke sel A2 dengan mengetik = A1 + B1 . Dalam hal ini, jika nilai sel A1 atau B1 berubah, jumlah dalam A2 juga berubah.
Pass by value mengirimkan COPY dari data yang disimpan dalam variabel yang Anda tentukan, pass by reference mengirimkan tautan langsung ke variabel itu sendiri. Jadi, jika Anda melewatkan variabel dengan referensi dan kemudian mengubah variabel di dalam blok tempat Anda meneruskannya, variabel asli akan berubah. Jika Anda hanya memberikan nilai, variabel asli tidak akan dapat diubah oleh blok yang Anda berikan, tetapi Anda akan mendapatkan salinan apa pun yang ada pada saat panggilan berlangsung.
Pass by value - Fungsi menyalin variabel dan bekerja dengan salinan (sehingga tidak mengubah apa pun di variabel asli)
Lulus dengan referensi - Fungsi ini menggunakan variabel asli, jika Anda mengubah variabel di fungsi lain, itu berubah dalam variabel asli juga.
Contoh (salin dan gunakan / coba sendiri dan lihat):
#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;
}
Tetap sederhana, intip. Dinding teks bisa menjadi kebiasaan buruk.
Perbedaan utama di antara mereka adalah bahwa variabel tipe-nilai menyimpan nilai, jadi menentukan variabel tipe-nilai dalam pemanggilan metode meneruskan salinan nilai variabel itu ke metode. Variabel tipe referensi menyimpan referensi ke objek, jadi tentukan variabel tipe referensi sebagai argumen yang meneruskan metode salinan referensi aktual yang merujuk ke objek. Meskipun referensi itu sendiri dilewatkan oleh nilai, metode ini masih dapat menggunakan referensi yang diterimanya untuk berinteraksi dengan - dan mungkin memodifikasi - objek asli. Demikian pula, ketika mengembalikan informasi dari suatu metode melalui pernyataan kembali, metode mengembalikan salinan nilai yang disimpan dalam variabel tipe nilai atau salinan referensi yang disimpan dalam variabel tipe referensi. Ketika referensi dikembalikan, metode pemanggilan dapat menggunakan referensi itu untuk berinteraksi dengan objek yang direferensikan. Begitu,
Dalam c #, untuk mengirimkan variabel dengan referensi sehingga metode yang dipanggil dapat memodifikasi variabel, C # menyediakan kata kunci ref dan out. Menerapkan kata kunci ref ke deklarasi parameter memungkinkan Anda untuk mengirimkan variabel ke metode dengan referensi — metode yang dipanggil akan dapat memodifikasi variabel asli di pemanggil. Kata kunci ref digunakan untuk variabel yang sudah diinisialisasi dalam metode panggilan. Biasanya, ketika pemanggilan metode berisi variabel yang tidak diinisialisasi sebagai argumen, kompiler menghasilkan kesalahan. Sebelum parameter dengan kata kunci keluar menciptakan parameter output. Ini menunjukkan kepada kompiler bahwa argumen akan diteruskan ke metode yang dipanggil dengan referensi dan bahwa metode yang dipanggil akan memberikan nilai ke variabel asli di pemanggil. Jika metode ini tidak menetapkan nilai ke parameter output di setiap jalur eksekusi yang mungkin, kompiler menghasilkan kesalahan. Ini juga mencegah kompilator menghasilkan pesan kesalahan untuk variabel tidak diinisialisasi yang dilewatkan sebagai argumen ke metode. Suatu metode dapat mengembalikan hanya satu nilai ke pemanggilnya melalui pernyataan pengembalian, tetapi dapat mengembalikan banyak nilai dengan menetapkan beberapa parameter keluaran (ref dan / atau keluar).
lihat diskusi # c dan contoh di sini tautan teks
Contoh:
class Dog
{
public:
barkAt( const std::string& pOtherDog ); // const reference
barkAt( std::string pOtherDog ); // value
};
const &
umumnya yang terbaik. Anda tidak dikenakan hukuman konstruksi dan penghancuran. Jika referensi bukan const antarmuka Anda menyarankan bahwa itu akan mengubah data yang dikirimkan.
Singkatnya, Lulus oleh nilai adalah APA itu dan disahkan oleh referensi MANA itu.
Jika nilai Anda adalah VAR1 = "Happy Guy!", Anda hanya akan melihat "Happy Guy!". Jika VAR1 berubah menjadi "Happy Gal!", Anda tidak akan tahu itu. Jika lulus dengan referensi, dan VAR1 berubah, Anda akan melakukannya.
Jika Anda tidak ingin mengubah nilai variabel asli setelah meneruskannya ke fungsi, fungsi tersebut harus dibangun dengan parameter " pass by value ".
Maka fungsi HANYA akan memiliki nilai tetapi bukan alamat variabel yang diteruskan. Tanpa alamat variabel, kode di dalam fungsi tidak dapat mengubah nilai variabel seperti yang terlihat dari luar fungsi.
Tetapi jika Anda ingin memberikan fungsi kemampuan untuk mengubah nilai variabel seperti yang terlihat dari luar, Anda perlu menggunakan referensi lewat . Karena nilai dan alamat (referensi) dilewatkan dan tersedia di dalam fungsi.
pass by value berarti cara meneruskan nilai ke suatu fungsi dengan memanfaatkan argumen. dalam pass by value kita menyalin data yang disimpan dalam variabel yang kita tentukan dan itu lebih lambat daripada pass by reference karena data disalin. dari kami membuat perubahan dalam data yang disalin data asli tidak terpengaruh. dan melalui pass by refernce atau pass by address kami mengirimkan tautan langsung ke variabel itu sendiri. atau melewatkan pointer ke suatu variabel. lebih cepat karena lebih sedikit waktu yang dikonsumsi
Berikut adalah contoh yang menunjukkan perbedaan antara nilai by pass - nilai pointer - referensi :
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
}
Metode “passing by reference” memiliki batasan penting . Jika suatu parameter dinyatakan sebagai lulus oleh referensi (sehingga didahului oleh tanda &) parameter aktualnya yang sesuai harus berupa variabel .
Parameter aktual yang merujuk pada parameter formal "lulus oleh nilai" dapat berupa ekspresi secara umum, sehingga diizinkan untuk menggunakan tidak hanya variabel tetapi juga hasil doa fungsi literal atau bahkan fungsi.
Fungsi tidak dapat menempatkan nilai pada sesuatu selain variabel. Itu tidak bisa menetapkan nilai baru ke literal atau memaksa ekspresi untuk mengubah hasilnya.
PS: Anda juga dapat memeriksa jawaban Dylan Beattie di utas saat ini yang menjelaskannya dengan kata-kata sederhana.