Chương 4 Hàm
4.5.2. Truyền tham chiếu
Khác với truyền giá trị, cơ chế truyền tham chiếu hay truyền bằng tham chiếu (pass-by-reference) cho phép hàm được gọi truy nhập trực tiếp tới dữ liệu
tham chiếu giúp chương trình có hiệu năng cao hơn do tránh được chi phí cho việc sao chép dữ liệu. Tuy nhiên, truyền tham chiếu làm cho chương trình kém an toàn do nguy cơ hàm được gọi làm rối loạn dữ liệu của hàm gọi. Mục này nói về một cơ chế mà C++ cung cấp để truyền tham số bằng tham chiếu. Ngồi ra, Chương 6 sẽ nói đến một dạng truyền tham chiếu khác đặc thù của C/C++: con trỏ.
Trước tiên chúng ta tìm hiểu về khái niệm tham chiếu trong ngơn ngữ lập trình C++. Tham chiếu (reference) của một biến về bản chất là một biệt danh hay
một cái tên khác của chính biến đó. Các thao tác trên tham chiếu của một biến cũng có hiệu quả giống hệt như thao tác trên chính biến đó và ngược lại. Sau khi khai báo, tham chiếu được sử dụng trong chương trình như các biến khác. Ví dụ dịng:
int &numberStick = numberUSB;
khai báo numberStick là một tham chiếu tới một biến kiểu int có tên numberUSB. Lưu ý rằng trong khai báo có dấu &. Ngoài ra, tham chiếu phải được khởi tạo ngay khi khai báo, C++ không chấp nhận tình trạng một tham chiếu khơng chiếu đi đâu cả.
Hình 4.5 minh họa cách khai báo và sử dụng tham chiếu. Biến numberStick được khai báo (có dấu & vào đằng trước tên biến) là một tham chiếu tới biến numberUSB (stick là một tên gọi khác của USB stick). Mọi tính tốn và tác động
trên biến numberStick sẽ tương tự như trên biến numberUSB và ngược lại vì
Trong nhiều trường hợp, chúng ta muốn việc thay đổi giá trị của một tham số trong hàm sẽ làm thay đổi giá trị của đối số tương ứng. Ví dụ, khi ta viết một hàm nhập giá trị cho các biến từ bàn phím.
Để làm như vậy, ta có thể sử dụng cơ chế truyền tham chiếu. Tức là, tham số hình thức sẽ là một tham chiếu tới đối số tương ứng. Trong cơ chế này, các sửa đổi đối với tham số hình thức ở bên trong hàm được thực hiện trên chính đối số dùng cho lời gọi hàm.
Hình 4.6 minh họa cơ chế truyền tham chiếu với hàm getStudent. Hàm này
nhập hai số nguyên từ bàn phím và lưu chúng vào hai tham số id và mark (đã được khai báo là tham chiếu). Việc lưu giá trị vào id và mark sẽ làm thay đổi
giá trị của đối số là các biến tương ứng của hàm main.
Khác biệt duy nhất về cú pháp giữa truyền giá trị và truyền tham chiếu là ở danh sách khai báo tham số hình thức. Để quy định tham số nào sẽ được truyền bằng tham chiếu, cần có dấu & đặt ngay sau tên kiểu dữ liệu tại khai báo tham số đó trong định nghĩa hàm. Trong ví dụ hàm getStudent, có các dấu & đặt tại khai
báo của các tham số id và mark.
void getStudent (int &id, int &mark);
Lưu ý: Hàm getStudent không cần trả về giá trị gì nên nó đã được khai báo với từ khóa void cho kiểu giá trị trả về và khơng cần có lệnh return kèm giá trị
#include <iostream> using namespace std;
void getStudent (int &id, int &mark) {
cout << "Enter student’s id and mark: "; cin >> id >> mark;
return; }
int main() {
int id1, mark1;
getStudent (id1, mark1);
cout << "Student " << id1 << " gets mark " << mark1 << endl; int id2, mark2;
getStudent (id2, mark2);
cout << "Student " << id2 << " gets mark " << mark2 << endl; cout << "Total mark: " << (mark1 + mark2);
return 0; }
Kết quả chạy chương trình Enter student's id and mark: 1 5 Student 1 gets mark 5
Enter student's id and mark: 2 6 Student 2 gets mark 6
Total mark: 11
Hình 4.6: Ví dụ về truyền tham biến cho hàm.
Như đã nói ở trên, việc cho phép hàm được gọi truy nhập trực tiếp tới dữ liệu của nơi gọi hàm gây nguy cơ hàm được gọi phá rối dữ liệu của nơi gọi hàm. Vậy có cách nào để giảm bớt hoặc ngăn chặn nguy cơ này? Đó là hằng tham chiếu. Một khi một tham chiếu được khai báo là hằng, trình biên dịch sẽ đảm bảo rằng tham chiếu đó sẽ chỉ được dùng để đọc chứ khơng thể sửa đổi biến mà nó chiếu tới.