Kapan saya menggunakan titik, panah, atau titik dua untuk merujuk ke anggota kelas di C ++?

243

Datang dari bahasa C yang diturunkan lainnya (seperti Java atau C #) ke C ++, itu pada awalnya sangat membingungkan bahwa C ++ memiliki tiga cara untuk merujuk kepada anggota kelas: a::b, a.b, dan a->b. Kapan saya menggunakan salah satu dari operator ini?

(Catatan: Ini dimaksudkan sebagai entri untuk FAQ C ++ Stack Overflow . Jika Anda ingin mengkritik gagasan menyediakan FAQ dalam formulir ini, maka pengeposan pada meta yang memulai semua ini akan menjadi tempat untuk melakukan itu. Jawaban untuk pertanyaan itu dipantau di chatroom C ++ , di mana ide FAQ dimulai sejak awal, jadi jawaban Anda sangat mungkin untuk dibaca oleh mereka yang mengemukakan ide itu.)

sbi
sumber

Jawaban:

248

Tiga operator berbeda yang digunakan C ++ untuk mengakses anggota kelas atau objek kelas, yaitu titik dua ::, titik ., dan panah ->, digunakan untuk tiga skenario berbeda yang selalu didefinisikan dengan baik. Mengetahui hal ini memungkinkan Anda untuk segera tahu cukup banyak tentang adan bhanya dengan melihat a::b, a.batau a->bmasing-masing, dalam kode Anda melihat.

  1. a::bhanya digunakan jika bmerupakan anggota kelas (atau namespace) a. Artinya, dalam hal ini aakan selalu menjadi nama kelas (atau namespace).

  2. a.bhanya digunakan jika bmerupakan anggota objek (atau referensi ke objek) a. Jadi untuk a.b, aakan selalu menjadi objek aktual (atau referensi ke objek) dari suatu kelas.

  3. a->badalah, pada awalnya, notasi singkatan (*a).b. Namun, ->adalah satu-satunya operator akses anggota yang dapat kelebihan beban, jadi jika aobjek kelas yang overloads operator->(umum jenis tersebut adalah pointer pintar dan iterator), maka artinya adalah apa pun yang diterapkan oleh perancang kelas. Untuk menyimpulkan: Dengan a->b, jika aadalah pointer, bakan menjadi anggota objek yang ditunjuk oleh pointer a. Namun, ajika objek kelas yang overload operator ini, maka fungsi operator overload operator->()dipanggil.


Cetakan kecil:

  • Dalam C ++, jenis dinyatakan sebagai class, structatau uniondianggap "dari jenis kelas". Jadi di atas merujuk pada ketiganya.
  • Referensi adalah, semantik, alias untuk objek, jadi saya seharusnya menambahkan "atau referensi ke pointer" ke # 3 juga. Namun, saya pikir ini akan lebih membingungkan daripada membantu, karena referensi ke pointer ( T*&) jarang digunakan.
  • Operator titik dan panah dapat digunakan untuk merujuk ke anggota kelas statis dari suatu objek, meskipun mereka bukan anggota objek. (Terima kasih kepada Oli untuk menunjukkan ini!)
sbi
sumber
10
Mungkin harus diklarifikasi .dan ->dapat juga digunakan untuk mengakses statika kelas melalui suatu objek, meskipun mereka tidak sepenuhnya "anggota objek".
Oliver Charlesworth
@Li: Itu memang benar. Saya telah menambahkannya ke cetakan kecil, karena saya pikir itu tidak umum dan cukup penting untuk dicantumkan dalam teks utama.
sbi
3
Untuk kelengkapan, mungkin perlu menunjukkan bahwa operator*()juga dapat kelebihan beban, dan tidak ada yang memaksa kelebihan beban untuk konsisten operator->()! (Saya tidak mengungguli BTW, baru saja tiba di sini melalui serangkaian duplikat yang panjang)
juanchopanza
@ OliCharlesworth apakah Anda tahu di mana itu ditentukan dalam standar C ++?
Babi
1
@juanchopanza: Namun, Anda tidak bisa mendapatkan perilaku merantai ->dengan kelebihan beban operator*dan penggunaan .. Hanya operator->kelebihan beban yang mendapatkannya.
Ben Voigt
36

Menyarankan alternatif untuk poin sbi 3

a->bhanya digunakan jika aadalah pointer. Ini adalah singkatan untuk (*a).b, banggota objek yang amenunjuk. C ++ memiliki dua jenis pointer, "biasa" dan pointer pintar. Untuk pointer reguler seperti A* a, kompiler mengimplementasikan ->. Untuk pointer cerdas seperti std::shared_ptr<A> a, ->adalah fungsi anggota kelas shared_ptr.

Dasar Pemikiran: audiens target FAQ ini tidak menulis smart pointer. Mereka tidak perlu tahu ->benar-benar dipanggil operator->(), atau bahwa itu adalah satu-satunya metode akses anggota yang dapat kelebihan beban.

MSalters
sumber
4
Tidak peduli apakah saya setuju atau tidak, saya memberikan ini +1hanya untuk memberikan jawaban alternatif.
sbi
2
Nah, untuk bersikap adil ->juga kelebihan beban untuk iterator standar yang mana setiap programmer C ++ harus segera bertemu, jadi mengatakan itu hanya digunakan untuk pointer bisa membingungkan.
Kiscsirke
@Kiscsirke "programmer C ++ biasa" tidak perlu menulis smart pointer atau tipe iterator, cukup gunakan saja. "Dereferences like a pointer" berlaku untuk keduanya.
Caleth
0
#include <iostream>
#include <string>

using namespace std;

class Human {
private:
    int age;

public:
    string name;

    Human(int humanAge, string humanName) 
         : age(humanAge), name(std::move(humanName)) {}

    void DoSomething() {
        cout << age << endl;
    }

    static void DisplayAge(const Human& person) {
        cout << person.age << endl;
    }

    // ...
};

int main() {
    // Usage of Dot(.) 
    Human firstMan(13, "Jim"); // firstMan is an instance of class Human
    cout << firstMan.name << endl; // accessing member attributes
    firstMan.DoSomething(); // accessing member functions

    // Usage of Pointer Operator (->)
    Human* secondMan = new Human(24, "Tom");
    cout << secondMan->name << endl; // accessing member attributes
    secondMan->DoSomething(); // accessing member functions
    cout << (*secondMan).name << endl; // accessing member attributes
    (*secondMan).DoSomething(); // accessing member functions

    // Usage of Double Colon (::)
    Human::DisplayAge(firstMan);
    firstMan.DisplayAge(firstMan); // ok but not recommended
    secondMan->DisplayAge(firstMan); // ok but not recommended

    delete(secondMan);

    return 0;
}

Dari contoh pengkodean di atas, kita melihat bahwa:
* Mengakses anggota (atribut dan fungsi) dari instance (atau objek) menggunakan operator titik ( .)
* Mengakses anggota (atribut dan fungsi) dari pointer ke objek (atau dibuat oleh new) menggunakan pointer operator ( ->)
* Mengakses fungsi anggota statis dari kelas itu sendiri tanpa memiliki objek sebagai pegangan menggunakan titik dua ( ::). [ Catatan: Anda juga dapat menjalankan fungsi anggota statis dari instance dengan .atau ->yang tidak disarankan]

Hu Xixi
sumber
@ SB begitu pemarah ha, aku tahu itu semacam pengulangan. Saya hanya ingin memberikan contoh eksplisit untuk menunjukkan cara menggunakannya. Dan di mana saya katakan ->hanya bisa digunakan oleh pointer yang dialokasikan pada heap new? Di bawah, item kedua, saya pikir saya benar-benar membuatnya jelas ->untuk pointer. Dan sebelum Anda downvote, Anda lebih baik mencoba className::non_static_member_function()dengan c ++ 14 sendiri. Referensi bukan pointer, jadi bisa digunakan ., dan saya akan membuatnya lebih jelas dalam jawaban saya.
Hu Xixi
0

Operator dot digunakan dalam skenario pemilihan anggota langsung.

print(a.b)

Di sini, kita mengakses b, yang merupakan anggota langsung dari suatu objek a. Jadi, terutama, aadalah objek dan banggota (fungsi / variabel dll) dari a.


Operator panah digunakan dalam skenario pemilihan anggota tidak langsung.

print(a->b)

Di sini, kita mengakses byang merupakan anggota objek, yang ditunjuk oleh a. Ini adalah singkatan (*a).bdan jadi di sini, aterutama adalah penunjuk ke objek dan bmerupakan anggota dari objek itu.


Operator Double Colon (Scope) digunakan dalam skenario pemilihan anggota langsung terkait namespace.

print(a::b)

Di sini, kita mengakses byang merupakan anggota dari kelas / namespace a. Jadi, terutama, aadalah kelas / namespace dan bmerupakan anggota (fungsi / variabel dll) dari a.

muditrustagii
sumber