Operator scope resolution :: menjawab satu pertanyaan: nama ini milik siapa? Bila nama yang sama dipakai di beberapa tempat — variabel global, variabel lokal, anggota namespace, atau anggota class — operator ini menunjuk secara tepat entitas yang kita maksud. Ia punya dua bentuk: unary ::nama yang selalu menunjuk lingkup global, dan binary kiri::kanan yang menunjuk kanan di dalam lingkup kiri, misalnya std::cout atau kantor::kuota. Pada Chapter ini kita memakai keduanya untuk menembus shadowing (variabel yang saling menutupi) dan membahas kapan menulis std:: eksplisit lebih baik daripada using namespace std;.
Lingkup Nama dan Shadowing #
Nama di C++ berlaku dalam sebuah lingkup (scope). Variabel global berlaku di seluruh file, variabel lokal berlaku di dalam fungsi atau blok { } tempat ia dideklarasikan, dan nama di dalam namespace berlaku bila diakses melalui nama namespace-nya. Ketika lingkup dalam mendeklarasikan nama yang sama dengan lingkup luar, nama dalam menutupi (shadow) nama luar: selama di lingkup dalam, penulisan nama itu selalu merujuk ke yang terdekat. Variabel yang tertutup tidak hilang — nilai tetap ada — hanya jalur aksesnya yang perlu diberi tanda.
#include <iostream>
namespace kantor {
const int kuota = 200; // milik namespace kantor
}
int kuota = 100; // variabel global
int main() {
int kuota = 50; // variabel lokal main(), menutupi global
std::cout << "main() : " << kuota << "\n";
std::cout << "::kuota : " << ::kuota << "\n";
std::cout << "kantor::kuota : " << kantor::kuota << "\n\n";
{ // blok dalam: lingkup lebih kecil
int kuota = 5; // menutupi kuota milik main()
std::cout << "blok dalam : " << kuota << "\n";
}
std::cout << "setelah blok : " << kuota << "\n";
return 0;
}Output yang Dihasilkan:
main() : 50
::kuota : 100
kantor::kuota : 200
blok dalam : 5
setelah blok : 50Mari kita bedah baris demi baris:
- Baris 4-6 (
namespace kantor): namespace berisi konstantakuota = 200. Konsep namespace sudah kita pelajari pada Chapter Namespace di Section Dasar Pemrograman; di sini ia dipakai sebagai lingkup milik sendiri. - Baris 8 (
int kuota = 100;): variabel global. Deklarasinya di luar semua fungsi dan namespace. - Baris 12 (
int kuota = 50;): variabel lokalmain()menutupi global. Karena itu baris berikutnya mencetak50, bukan100. - Baris 14 (
::kuota): unary::tanpa nama kiri berarti “lingkup global”. Di sinilah100muncul kembali — variabel global terjangkau meski tertutup. - Baris 15 (
kantor::kuota): bentuk binary::menunjukkuotamilik namespacekantor, menghasilkan200. Inilah mekanisme yang sama denganstd::cout: namacoutdi dalam namespacestd. - Baris 17-20 (blok dalam): blok
{ }biasa membuat lingkup baru;kuota = 5menutupikuotamilikmain(). Setelah blok berakhir (baris 22), yang terlihat kembali adalah50milikmain().
Satu batasan penting: unary :: hanya bisa menembus ke global. Dari dalam blok, kita bisa mencapai ::kuota (global), tetapi tidak punya operator untuk menyebut kuota milik main() — jalurnya sudah tertutup. Karena itu best practice-nya bukan mengandalkan tanda, melainkan memberi nama berbeda agar shadowing tidak terjadi.
Bentuk Binary :: di Sekitar Kita #
Kita sebenarnya sudah memakai binary :: sejak Chapter pertama: std::cout, std::endl, dan std::string semuanya mengambil nama dari namespace std. Pola yang sama berlaku untuk namespace lain yang kita buat sendiri, dan nanti juga untuk anggota class. Bila sebuah class memiliki member static bernama total, pemanggilannya ditulis NamaClass::total — bentuk class::nama ini baru bisa kita tulis lengkap setelah Section Pemrograman Berorientasi Objek.
Operator ini juga melekat pada banyak fitur lanjutan: std:: di depan tipe standar, ::std::cout yang memaksa pencarian dari global, hingga nested namespace seperti std::chrono::seconds. Semuanya satu ide: berjalan melalui peta lingkup, dari kiri ke kanan.
std:: Eksplisit vs using namespace std #
Dua gaya umum di kode C++: menulis std:: di setiap nama standar, atau membuka namespace dengan using namespace std; lalu menulis cout saja. Gaya kedua lebih pendek, tetapi membawa risiko pada file besar: semua nama dari std ikut masuk, sehingga kemungkinan benturan nama dan shadowing naik — dan error yang muncul justru membingungkan.
Operator scope resolution menjawab “nama ini milik siapa”. Chapter berikutnya membahas pertanyaan yang berbeda: “nilai ini mau diubah jadi tipe apa?” — lewat operator cast seperti static_cast dan saudara-saudaranya.