Tham chiếu (Reference)
Tham chiếu (reference) là một cách khác để làm việc với một biến đã tồn tại mà không cần sao chép nó - đơn giản và an toàn hơn con trỏ trong nhiều trường hợp.
Tham chiếu là gì?
Phần tiêu đề “Tham chiếu là gì?”Một tham chiếu là một “bí danh” (alias) - một tên gọi khác cho một biến đã tồn tại. Khi bạn thay đổi tham chiếu, bạn thực chất đang thay đổi biến gốc, vì chúng là cùng một ô nhớ:
#include <iostream>
int main() { int age = 25; int& age_ref = age; // age_ref là một BÍ DANH của age
std::cout << age << std::endl; // 25 std::cout << age_ref << std::endl; // 25
age_ref = 30; // Thay đổi thông qua tham chiếu std::cout << age << std::endl; // 30 (age cũng đổi theo, vì chúng là MỘT)
return 0;}Khai báo tham chiếu
Phần tiêu đề “Khai báo tham chiếu”Cú pháp: KieuDuLieu& ten_tham_chieu = bien_da_ton_tai;
int x = 10;int& ref = x; // ref bây giờ là một tên khác của x⚠️ Tham chiếu phải được khởi tạo ngay khi khai báo và không thể “trỏ lại” sang biến khác sau đó - khác với con trỏ, có thể gán lại địa chỉ mới bất cứ lúc nào:
int x = 10;int y = 20;int& ref = x;// int& ref2; // LỖI! Tham chiếu phải được khởi tạo ngay
ref = y; // Đây KHÔNG làm ref "trỏ sang" y - mà đang GÁN giá trị của y (20) cho x!std::cout << x << std::endl; // 20 (x đã đổi, không phải ref đổi hướng)Tham chiếu dùng nhiều nhất trong tham số hàm
Phần tiêu đề “Tham chiếu dùng nhiều nhất trong tham số hàm”Đây là ứng dụng phổ biến và quan trọng nhất của tham chiếu - đã được giới thiệu ở bài “Các cách truyền đối số vào hàm”:
#include <iostream>
void increase(int& x) { x = x + 1; // Thay đổi trực tiếp biến gốc thông qua tham chiếu}
int main() { int number = 5; increase(number); std::cout << number << std::endl; // 6
return 0;}Tham chiếu hằng (const&): tránh sao chép mà vẫn an toàn
Phần tiêu đề “Tham chiếu hằng (const&): tránh sao chép mà vẫn an toàn”Khi truyền dữ liệu lớn (như std::string, std::vector) vào hàm chỉ để đọc, const& là lựa chọn tốt nhất: vừa tránh sao chép tốn kém, vừa đảm bảo hàm không vô tình sửa đổi dữ liệu gốc:
#include <iostream>#include <string>
void print_message(const std::string& message) { std::cout << message << std::endl; // message += "!"; // LỖI! Không thể sửa đổi tham chiếu hằng}
int main() { std::string text = "Hello, C++!"; print_message(text); // Không sao chép chuỗi, chỉ truyền tham chiếu return 0;}Tham chiếu trong range-based for
Phần tiêu đề “Tham chiếu trong range-based for”Tham chiếu cũng thường dùng để duyệt và sửa đổi trực tiếp phần tử trong container, tránh sao chép từng phần tử:
#include <vector>#include <iostream>
int main() { std::vector<int> numbers = {1, 2, 3};
for (int& n : numbers) { // & giúp sửa trực tiếp phần tử trong vector n *= 2; } // numbers bây giờ là {2, 4, 6}
for (const int& n : numbers) { // const& khi chỉ đọc, tránh sao chép std::cout << n << " "; }
return 0;}Tổng kết
Phần tiêu đề “Tổng kết”- Tham chiếu là một bí danh (alias) cho một biến đã tồn tại - không phải một biến độc lập
- Phải khởi tạo ngay khi khai báo, và không thể “trỏ lại” sang biến khác sau đó
KieuDuLieu&dùng để tham số hàm có thể thay đổi biến gốc, tránh sao chépconst KieuDuLieu&dùng khi muốn tránh sao chép dữ liệu lớn nhưng không muốn sửa đổi nó