บทความนี้จะเกี่ยวกับเรื่องของ ฟังก์ชันที่มีการรับค่าแบบตัวแปรอ้างอิง ( reference variables ) (เขียนโปรแกรมมาตั้งแต่ปีหนึ่งมา เพิ่งมาเจอเอาตอนปีสอง เลยเอามาเขียนสรุปๆ ลงบล็อกไว้กันลืม) หน้าตามันจะเป็นอย่างไร มีความพิเศษยังไง แตกต่างจากฟังก์ชันอื่นๆ อย่างไร เอาไว้ทำอะไรบ้าง มีประโยชน์อย่างไร ลองอ่านกันเลย
มองภาพรวมก่อน
การผ่านค่าของตัวแปรให้กับฟังก์ชัน มีด้วยกันนั้นมีสองแบบ คือ
- pass-by-value
- pass-by-reference
ความแตกต่างระหว่าง pass-by-value กับ pass-by-reference
ง่ายๆ เลย pass-by-value เป็นการผ่านค่าจริงๆ ของตัวแปร ส่วน pass-by-reference เป็นการผ่าน address ของตัวแปร
มาดูตัวอย่างการผ่านแบบ pass-by-value และ pass-by-reference ในโปรแกรมเดียวกัน
#include <iostream>
using namespace std;
char changeVal(char);
void changeRef(char &);
int main() {
char letter = 'A';
cout << "\nOriginal value\n";
cout << "letter = " << letter << endl;
cout << "\nPass-by-value\n";
letter = changeVal(letter);
cout << "Now letter = " << letter << endl;
cout << "\n\nPass-by-Reference\n";
changeRef(letter);
cout << "Now letter = " << letter << endl;
return 0;
}
char changeVal(char l) {
l = 'B';
return l;
}
void changeRef(char &ch) {
ch = 'C';
}
จากโค๊ดข้างบนนี้ บรรทัดที่ 14 เป็นการส่งค่าภายในตัวแปร letter ซึ่งก็คือ A ให้กับฟังก์ชัน changeVal() จากนั้นค่า A จะถูกก็อปปี้มาเก็บไว้ในตัวแปร l บรรทัดที่ 25 มีการกำหนดค่า B ให้แก่ตัวแปร l จากนั้นคืนค่า B กลับไปยัง ณ ตำแหน่งที่เรียกใช้ฟังก์ชัน changeVal() พร้อมกับนำค่า B มาเก็บไว้ในตัวแปร letter ณ ตอนนี้ ค่าภายในตัวแปร letter ได้เปลี่ยนจาก A มาเป็น B เรียบร้อยแล้ว ส่วนบรรทัดที่ 18 มีหลักการทำงานคล้ายๆ กัน เพียงแต่ว่า ตัวแปร letter ไม่ได้ส่งค่าของตัวแปรมาให้แก่ฟังก์ชัน changeRef() นั่นก็คือว่า ไม่ได้ส่งค่า B มาให้นั่นเอง เนื่องจากว่า พารามิเตอร์ของฟังก์ชัน changeRef() ถูกประกาศเป็น reference parameter (ตัวแปรพารามิเตอร์แบบอ้างอิง) แล้วมัน หมายความว่ายังไงล่ะ!!! หมายความว่าตัวแปร letter กับ ตัวแปร ch เป็นตัวแปรเดียวกัน ตัวแปรเดียวกันจริงๆ แต่เพียงคนละชื่อ (เหมือนกับเป็น ชื่อเล่น แทนชื่อจริงนั่นแหละ เราอ้างถึงคนคนเดียวกัน แต่คนละชื่อ) ถ้าจะพูดให้ถูกก็คือว่า ตัวแปรสองตัวนี้อ้างอิงถึงตำแหน่งเดียวกันในหน่วยความจำ อ่าว! ยังไง หลายคนอาจจะสงสัย ถ้ายังงั้น แล้วจะเอาอะไรมาพิสูจน์ว่ามันเป็นตัวแปรเดียวกันล่ะ??? วิธีที่จะทราบว่า letter กับ ch เป็นตัวแปรเดียวกัน คือ เราต้องสั่งแสดงค่า address ของตัวแปรทั้งสองตัว ตามโค๊ดด้านล่างนี้ #include <iostream>
using namespace std;
char changeVal(char);
void changeRef(char &);
int main()
char letter = 'A';
cout << "\nOriginal value\n";
cout << "\nAddress of letter = " << (unsigned long) &letter << endl;
cout << "letter = " << letter << endl;
cout << "\nPass-by-value\n";
letter = changeVal(letter);
cout << "Now letter = " << letter << endl;
cout << "\n\nPass-by-Reference\n";
changeRef(letter);
cout << "Now letter = " << letter << endl;
return 0;
}
char changeVal(char l) {
cout << "Address of l = " << (unsigned long) &l << endl;
l = 'B';
return l;
}
void changeRef(char &ch) {
cout << "Address of ch = " << (unsigned long) &ch << endl;
ch = 'C';
} ผลลัพธ์จากการรันโปรแกรม
จากการรันโปรแกรมจะเห็นว่า ตำแหน่งของตัวแปร letter กับ ตำแหน่งของตัวแปร ch เป็นตำแหน่งเดียวกัน นั่นคือ 3220023647 (ตำแหน่งแอดเดรสสที่ได้ของท่านอาจแตกต่างกันออกไป) พอมาถึงตรงนี้ แล้วเราจะทำ reference variable ไปทำไม ก็ในเมื่อมันก็ใช้ได้เหมือนกันกับตัวแปรธรรมดา จริงอยู่ถ้าทำตัวแปรเดียวมันไม่มีประโยชน์เลย ที่จะมาใช้ไอ & ตัวเนี้ย (จริงๆ ถึงจะใช้แค่ตัวแปรเดียว แต่ถ้าส่ง object เข้ามาแล้วหาก object มันมี attribute มาก จะมีประโยชน์มาก เพราะถ้าส่งแบบ pass-by-value จะเสียพื้นที่หน่วยความจำในการก็อปปี้ค่ามาใช้ในฟังก์ชันที่ถูกเรียกเป็นจำนวนมากขึ้น ตามจำนวน attribute ของ object นั้นๆ ในทางการเขียนโปรแกรมจริงๆ มันจึงมีประโยชน์มาก เพราะ attribute ของ object หนึ่งๆ มักจะมีจำนวนมาก)
ประโยชน์ของ reference variable
- มีประโยชน์ตอนคืนค่าจากฟังก์ชัน ซึ่งปกติเราสามารถคืนค่าจากฟังก์ชันได้เพียงค่าเดียว แต่ถ้าเป็น reference variable สามารถคืนค่าได้หลายค่า
- ประหยัดพื้นที่หน่วยความจำ เพราะตัวแปรไม่ได้ถูกคัดลอกเหมือนกับการส่งแบบ pass-by-value (ยิ่งส่งตัวแปรเข้าฟังก์ชันมาก ยิ่งใช้พื้นที่หน่วยความจำมาก หากใช้การส่งแบบ pass-by-value)
- กรณีที่ต้องการเปลี่ยนแปลงค่า จากฟังก์ชันที่ถูกเรียกให้มีผลต่อฟังก์ชันที่เรียกโดยตรง







3 ความคิดเห็น:
ชงมาล คุมอวอ ^^
คุณเกรียนค่ะ ภาษาที่ใช้วัยสะรุ่นเหลือเกินเนอะ 555555
กรีนครับไม่ใช่เกรียน ไอดง
แสดงความคิดเห็น