Toán tử :: được gọi là scope resolution operator, có thể dịch là toán tử phân giải phạm vi. Đây là toán tử một ngôi (unary).
outer block: là một khối lệnh bên ngoài khối lệnh đang tham chiếu đến.
global variable: Biến toàn cục.
nonglobal variable: Biến không toàn cục (Không phải sẽ là biến local trong trường hợp này, nên không dịch là biến cục bộ)
Tạm dịch thành thế này:
Nó là một lỗi cố gắng sử dụng toán tử ( :: ) để truy cập một biến không toàn cục trong một outer block. Nếu không có biến toàn cục tồn tại với tên đó, một lỗi biên dịch sẽ xảy ra. Nếu một biến toàn cục tồn tại với tên đó, đây là lỗi logic, bởi vì chương trình sẽ tham chiếu đến biến toàn cục khi bạn có ý định truy cập vào biến không toàn cục trong một outer block.
Ví dụ:
C Code:
- int iNumber= 0; // global variable named iNumber
- int main(void)
- {
- int iNumber = 0; // local variable named iNumber
- ::iNumber= 1; // set global iNumber to 1
- iNumber= 2; // set local iNumber to 2
- ::iCount = 1; // Error here...
- }
Như đã được giải thích, scope (phạm vi) resolution (phân định) operator (toán tử) được ký hiệu là ::
Khi dùng, người ta đặt nó trước một phần tử (phần tử này có thể là một biến, hặc hàm, hoặc là một toán tử phân định phạm vi khác) để xác định rõ rệt phần tử mà mình muốn nói tới.
Lý do: C++ là ngôn ngữ tuân theo luật đóng khung (block). Những phần tử trong khung sẽ che khuất (masked) nhũng phần tử ngoài khung trùng tên.
Code:
// vd
int t1 = 1;
int t2 = 2;
{ // khung
int t1 = 10;
cout<<t1; // in ra 10, trong khung, t1 có trị là 1 bị che
cout<<t2; // in ra 2, tuy trong khung nhưng không bị che
}
cout<<t1; // in ra 1, ngoài khung, t1 có trị là 1 không còn bị che
int t1 = 1;
int t2 = 2;
{ // khung
int t1 = 10;
cout<<t1; // in ra 10, trong khung, t1 có trị là 1 bị che
cout<<t2; // in ra 2, tuy trong khung nhưng không bị che
}
cout<<t1; // in ra 1, ngoài khung, t1 có trị là 1 không còn bị che
Như vậy, ở trong khung mà muốn sử dụng phần tử t1 thì làm cách nào? Đó là nhiệm vụ của toán tử phân định phạm vi, [namespace]::t1
Trong code trên, t1 được tuyên bố không nằm trong phạm vi nào, vì vậy nó được mặc định là 'global namespace' (phạm vi danh xưng toàn trình). Trong ngôn ngữ C++, phạm vi global được quyền hiểu ngầm, không phải ghi rõ namespace, tức là ::t1
Code:
int t1 = 1; // biến global
int t2 = 2; // biến global
{ // khung
int t1 = 10;
cout<<::t1; // in ra 1, trong khung, tuy t1 bị che nhưng ::t1 chỉ thẳng vào global
cout<<t2; // in ra 2, tuy trong khung nhưng không bị che
}
int t2 = 2; // biến global
{ // khung
int t1 = 10;
cout<<::t1; // in ra 1, trong khung, tuy t1 bị che nhưng ::t1 chỉ thẳng vào global
cout<<t2; // in ra 2, tuy trong khung nhưng không bị che
}
Trở lại câu hỏi của chủ đề bài, phần tiếng Anh ý là muốn nói cho trường hợp này:
Code:
int t1 = 1; // biến global
int t2 = 2; // biến global
{ // khung ngoài
int t1 = 100; // biến này che biến t1 global
{ // khung trong
int t1 = 10; // biến này che cả hai t1 global và khung ngoài
cout<<::t1; // in ra 1, trong khung, ::t1 chỉ thẳng vào global
// và không thèm đếm xỉa đến t1 của khung ngoài
cout<<t2; // in ra 2, tuy qua nhiều khung nhưng không bị che
}
}
int t2 = 2; // biến global
{ // khung ngoài
int t1 = 100; // biến này che biến t1 global
{ // khung trong
int t1 = 10; // biến này che cả hai t1 global và khung ngoài
cout<<::t1; // in ra 1, trong khung, ::t1 chỉ thẳng vào global
// và không thèm đếm xỉa đến t1 của khung ngoài
cout<<t2; // in ra 2, tuy qua nhiều khung nhưng không bị che
}
}
Ý của câu tiếng Anh là người dùng đừng ngạc nhiên khi không thấy in ra 100, ::t1 chỉ vào global chứ không phải là chỉ vào vòng/khung ngoài (như đã nói trên, global namespace được hiểu ngầm). Toán tử :: không có namespace là muốn nói global namespace chứ không phải nói vòng/khung ngoài.
Nói cách khác, nếu không có câu:
int t1 = 1; // biến global
thì trình dịch sẽ báo lỗi, ::t1 chỉ vào một biến không hề được khai báo
nếu có câu:
int t1 = 1; // biến global
thì ::t1 luôn luôn chỉ biến này, bất cứ trường hợp nào. Trình dịch không báo lỗi, nhưng nếu người dùng thực ra muốn cái biến ở vòng ngoài thì kq sẽ sai (logical error).
Muốn gọi phần tử nonglobal đã bị che, chỉ có cách duy nhất là đặt namespace cho chúng:
Code:
int t1 = 1; // biến global
int t2 = 2; // biến global
namespace K { int t1; }
{ // khung ngoài
K::t1 = 100; // biến này bây giờ có phạm vi đàng hoàng
{ // khung trong
int t1 = 10; // biến này che cả hai t1 global và khung ngoài
cout<<K::t1; // in ra 100, K::t1 là hoàn toàn xác định, không nhầm lẫn
cout<<t2; // in ra 2, tuy qua nhiều khung nhưng không bị che
}
}
int t2 = 2; // biến global
namespace K { int t1; }
{ // khung ngoài
K::t1 = 100; // biến này bây giờ có phạm vi đàng hoàng
{ // khung trong
int t1 = 10; // biến này che cả hai t1 global và khung ngoài
cout<<K::t1; // in ra 100, K::t1 là hoàn toàn xác định, không nhầm lẫn
cout<<t2; // in ra 2, tuy qua nhiều khung nhưng không bị che
}
}
