Apa arti dari tanda titik dua "::"?

411

Saya menemukan baris kode ini di kelas yang harus saya ubah:

::Configuration * tmpCo = m_configurationDB;//pointer to current db

dan saya tidak tahu apa sebenarnya arti dari usus besar ganda yang diawali dengan nama kelas. Tanpa itu saya akan membaca: deklarasi tmpCosebagai penunjuk ke objek kelas Configuration... tapi usus besar bersebelahan membingungkan saya.

Saya juga menemukan:

typedef ::config::set ConfigSet;
rmbianchi
sumber
7
Jangan merasa itu adalah jawaban, jadi saya akan berkomentar: en.wikipedia.org/wiki/Scope_resolution_operator . Dalam konteks ini, ::berarti telanjang merujuk variabel dari namespace global / anonim.
wkl

Jawaban:

491

Ini memastikan bahwa resolusi muncul dari namespace global, alih-alih dimulai dari namespace tempat Anda berada saat ini. Misalnya, jika Anda memiliki dua kelas berbeda yang disebut Configurationsebagai:

class Configuration; // class 1, in global namespace
namespace MyApp
{
    class Configuration; // class 2, different from class 1
    function blah()
    {
        // resolves to MyApp::Configuration, class 2
        Configuration::doStuff(...) 
        // resolves to top-level Configuration, class 1
        ::Configuration::doStuff(...)
    }
}

Pada dasarnya, ini memungkinkan Anda untuk melintasi ke namespace global karena nama Anda mungkin akan dihancurkan oleh definisi baru di dalam namespace lain, dalam hal ini MyApp.

Wyatt Anderson
sumber
Apa alasan menempatkan 2 set titik dua? Dalam hal ini:::Configuration::doStuff(...)
Azurespot
@NoniA. apakah Anda bertanya, apa yang dilakukan set kedua dari titik dua?
FC
1
@ WyattAnderson, tidak ada set pertama. Saya rasa saya mengerti bahwa ::di antara dua istilah mengacu pada namespace atau kelas dan anggotanya. Tapi bagaimana dengan yang ke-1?
Azurespot
6
@Azurespot itulah yang ditanyakan OP, itulah pertanyaan yang dijawab pos ini. Itu memastikan untuk menggunakan pengidentifikasi dari namespace global. Lihatlah contohnya lagi
hungryWolf
193

The ::operator disebut operator lingkup-resolusi dan tidak hanya itu, menyelesaikan lingkup. Jadi, dengan mengawali tipe-nama dengan ini, ia memberitahu kompiler Anda untuk mencari di namespace global untuk tipe tersebut.

Contoh:

int count = 0;

int main(void) {
  int count = 0;
  ::count = 1;  // set global count to 1
  count = 2;    // set local count to 2
  return 0;
}
Jus Moo
sumber
122

Sudah banyak jawaban masuk akal. Saya akan menambahkan analogi yang dapat membantu beberapa pembaca. ::bekerja sangat mirip dengan pemisah direktori filesystem ' /', ketika mencari jalur Anda untuk program yang ingin Anda jalankan. Mempertimbangkan:

/path/to/executable

Ini sangat eksplisit - hanya dapat dieksekusi di lokasi yang tepat di pohon sistem file yang dapat cocok dengan spesifikasi ini, terlepas dari PATH yang berlaku. Demikian pula...

::std::cout

... sama eksplisit di C ++ namespace "tree".

Berbeda dengan jalur absolut seperti itu, Anda dapat mengonfigurasi shell UNIX yang baik (misalnya zsh ) untuk menyelesaikan jalur relatif di bawah direktori Anda saat ini atau elemen apa pun dalam PATHvariabel lingkungan Anda , jadi jika PATH=/usr/bin:/usr/local/bin, dan Anda berada "di" /tmp, maka ...

X11/xterm

... akan dengan senang hati lari /tmp/X11/xtermjika ditemukan, yang lain /usr/bin/X11/xterm, yang lain /usr/local/bin/X11/xterm. Demikian pula, katakanlah Anda berada di namespace bernama X, dan " using namespace Y" berlaku, lalu ...

std::cout

... dapat ditemukan di salah ::X::std::cout, ::std::cout, ::Y::std::cout, dan tempat-tempat mungkin lain karena argumen-dependent lookup (ADL, alias Koenig lookup). Jadi, hanya ::std::coutbenar-benar eksplisit tentang objek yang Anda maksud, tetapi untungnya tidak ada orang waras yang pernah membuat kelas / struct atau namespace mereka sendiri yang disebut " std", atau apa pun yang disebut " cout", jadi dalam praktiknya menggunakan hanya std::coutbaik-baik saja.

Perbedaan yang patut diperhatikan :

1) shell cenderung menggunakan pertandingan pertama menggunakan urutan PATH, sedangkan C ++ memberikan kesalahan kompilator ketika Anda telah ambigu.

2) Dalam C ++, nama tanpa lingkup utama dapat dicocokkan di namespace saat ini, sementara sebagian besar shell UNIX hanya melakukan itu jika Anda memasukkannya ke .dalam PATH.

3) C ++ selalu mencari namespace global (seperti memiliki /Anda secara implisit PATH).

Diskusi umum tentang ruang nama dan kesederhanaan simbol

Menggunakan ::abc::def::..."jalur" absolut kadang-kadang bisa berguna untuk mengisolasi Anda dari ruang nama lain yang Anda gunakan, bagian dari tetapi tidak benar-benar memiliki kontrol atas konten, atau bahkan perpustakaan lain yang juga menggunakan kode klien perpustakaan Anda. Di sisi lain, ini juga memasangkan Anda dengan lebih erat ke lokasi simbol "absolut" yang ada, dan Anda kehilangan keuntungan dari pencocokan tersirat dalam ruang nama: lebih sedikit sambungan, lebih mudah mobilitas kode antara ruang nama, dan kode sumber yang lebih ringkas dan mudah dibaca .

Seperti banyak hal, ini adalah tindakan penyeimbang. C ++ Standar menempatkan banyak pengidentifikasi bawah std::yang kurang "unik" dari cout, bahwa programmer mungkin menggunakan untuk sesuatu yang sama sekali berbeda dalam kode mereka (misalnya merge, includes, fill, generate, exchange, queue, toupper, max). Dua perpustakaan non-Standar yang tidak terkait memiliki peluang yang jauh lebih tinggi untuk menggunakan pengidentifikasi yang sama karena para penulis umumnya tidak atau kurang menyadari satu sama lain. Dan perpustakaan - termasuk perpustakaan C ++ Standard - mengubah simbol mereka dari waktu ke waktu. Semua ini berpotensi menciptakan ambiguitas ketika mengkompilasi ulang kode lama, terutama ketika sudah ada banyak penggunaan using namespaces: hal terburuk yang dapat Anda lakukan dalam ruang ini adalah memungkinkanusing namespaceada di header untuk menghindari lingkup header, sehingga sejumlah besar kode klien langsung dan tidak langsung tidak dapat membuat keputusan sendiri tentang ruang nama mana yang akan digunakan dan bagaimana mengelola ambiguitas.

Jadi, yang terdepan ::adalah salah satu alat di kotak alat programmer C ++ untuk secara aktif mengacaukan bentrokan yang diketahui, dan / atau menghilangkan kemungkinan ambiguitas di masa depan ....

Tony Delroy
sumber
8
+1 untuk analogi yang bagus. analogi tidak digunakan hampir cukup IMO sebagai alat pengajaran.
Trevor Boyd Smith
38

::adalah operator resolusi ruang lingkup. Ini digunakan untuk menentukan ruang lingkup sesuatu.

Misalnya, ::sendiri adalah ruang lingkup global, di luar semua ruang nama lainnya.

some::thing dapat diartikan dengan salah satu cara berikut:

  • someadalah namespace (dalam lingkup global, atau lingkup luar dari yang sekarang) dan thingmerupakan tipe , fungsi , objek atau namespace bersarang ;
  • someadalah kelas yang tersedia dalam ruang lingkup saat ini dan thingmerupakan objek anggota , fungsi atau jenis dari somekelas;
  • dalam fungsi anggota kelas , somebisa menjadi tipe dasar dari tipe saat ini (atau tipe saat ini sendiri) dan thingkemudian menjadi salah satu anggota kelas ini, tipe , fungsi atau objek .

Anda juga dapat memiliki ruang lingkup bersarang, seperti pada some::thing::bad. Di sini setiap nama bisa berupa tipe, objek, atau namespace. Selain itu, yang terakhir bad,, juga bisa menjadi fungsi. Yang lain tidak bisa, karena fungsi tidak dapat mengekspos apa pun dalam lingkup internal mereka.

Jadi, kembali ke contoh Anda, ::thingbisa jadi hanya sesuatu dalam lingkup global: tipe, fungsi, objek, atau namespace.

Cara Anda menggunakannya menyarankan (digunakan dalam deklarasi pointer) bahwa itu adalah tipe dalam lingkup global.

Saya harap jawaban ini lengkap dan cukup benar untuk membantu Anda memahami resolusi ruang lingkup.

Klaim
sumber
2
@obounaim Pertimbangkan kode ini liveworkspace.org/code/3Wabw0$5 class some { protected: int thing; }; class some_ext : public some { float thing; void action(){ some::thing = 42; thing = 666; } }; Ini someadalah kelas dasar some_extdan ketika Anda menulis some::thingke fungsi anggota some_ext, itu berarti thingobjek menjadi tipe dasar some. Tanpa some::, thingsendirian berarti thingdalam ruang lingkup terdekat, yaitu some_ext::thing. Apakah lebih jelas?
Klaim
17

:: digunakan untuk menautkan sesuatu (variabel, fungsi, kelas, typedef dll ...) ke namespace, atau ke kelas.

jika tidak ada sisi kiri sebelumnya ::, maka itu menggarisbawahi fakta bahwa Anda menggunakan namespace global.

misalnya:

::doMyGlobalFunction();

Stephane Rolland
sumber
10

disebut operator resolusi lingkup, Nama global tersembunyi dapat disebut menggunakan operator resolusi lingkup ::
Misalnya;

int x;
void f2()
{
   int x = 1; // hide global x
   ::x = 2; // assign to global x
   x = 2; // assign to local x
   // ...
}
Mustafa Ekici
sumber
10

(Jawaban ini sebagian besar untuk para googler, karena OP sudah menyelesaikan masalahnya.) Arti dari prepended :: operator ruang lingkup yang dijelaskan sebelumnya - telah dijelaskan dalam jawaban lain, tetapi saya ingin menambahkan mengapa orang menggunakannya.

Artinya adalah "mengambil nama dari namespace global, bukan yang lain". Tetapi mengapa ini harus dieja secara eksplisit?

Gunakan case - namespace clash

Ketika Anda memiliki nama yang sama di namespace global dan di namespace lokal / bersarang, yang lokal akan digunakan. Jadi, jika Anda menginginkan yang global, tambahkan dengan ::. Kasus ini dijelaskan dalam jawaban @ Wyatt Anderson, lihat contohnya.

Use case - menekankan fungsi non-anggota

Saat Anda menulis fungsi anggota (metode), panggilan ke fungsi anggota lainnya dan panggilan ke fungsi non-anggota (gratis) mirip:

class A {
   void DoSomething() {
      m_counter=0;
      ...
      Twist(data); 
      ...
      Bend(data);
      ...
      if(m_counter>0) exit(0);
   }
   int m_couner;
   ...
}

Tetapi mungkin terjadi bahwa Twistini adalah fungsi sister class A, dan Bendmerupakan fungsi bebas. Artinya, Twistbisa menggunakan dan memodifikasi m_counerdan Bendtidak bisa. Jadi, jika Anda ingin memastikan bahwa m_counter0 tetap, Anda harus memeriksa Twist, tetapi Anda tidak perlu memeriksaBend .

Jadi untuk membuatnya lebih jelas, orang bisa menulis this->Twistuntuk menunjukkan kepada pembaca yang Twistmerupakan fungsi anggota atau menulis ::Benduntuk menunjukkan yang Bendgratis. Atau keduanya. Ini sangat berguna ketika Anda melakukan atau merencanakan refactoring.

Kuda
sumber
5

:: adalah operator mendefinisikan namespace.

Misalnya, jika Anda ingin menggunakan cout tanpa menyebutkan using namespace std;kode Anda, Anda menulis ini:

std::cout << "test";

Ketika tidak ada namespace yang disebutkan, maka dikatakan bahwa kelas milik global namespace.

Vladimir Ivanov
sumber
1

"::" mewakili operator resolusi lingkup. Fungsi / metode yang memiliki nama yang sama dapat didefinisikan dalam dua kelas yang berbeda. Untuk mengakses metode operator resolusi ruang lingkup kelas tertentu digunakan.

Vaman Acharya
sumber