Quando uso un punto, una freccia o un doppio punto per fare riferimento ai membri di una classe in C ++?


243

Venendo da altri linguaggi C-derivati (come Java o C #) per C ++, è in un primo momento molto confuso che il C ++ ha tre modi per fare riferimento ai membri di una classe: a::b, a.b, e a->b. Quando uso quale di questi operatori?

(Nota: questo dovrebbe essere una voce alle FAQ C ++ di Stack Overflow . Se vuoi criticare l'idea di fornire una FAQ in questo modulo, allora la pubblicazione su meta che ha iniziato tutto questo sarebbe il posto dove farlo. tale domanda viene monitorata nella chatroom di C ++ , dove l'idea FAQ è iniziata in primo luogo, quindi è molto probabile che la tua risposta venga letta da coloro che hanno avuto l'idea.)

Risposte:


248

I tre distinti operatori che C ++ utilizza per accedere ai membri di una classe o di un oggetto classe, ovvero i due punti ::, il punto .e la freccia ->, vengono utilizzati per tre diversi scenari che sono sempre ben definiti. Sapendo questo permette di conoscere subito un bel po 'su ae bsolo guardando a::b, a.bo a->brispettivamente, in qualsiasi codice si guardano.

  1. a::bviene utilizzato solo se bè un membro della classe (o dello spazio dei nomi) a. Cioè, in questo caso asarà sempre il nome di una classe (o spazio dei nomi).

  2. a.bviene utilizzato solo se bè un membro dell'oggetto (o riferimento a un oggetto) a. Quindi a.b, asarà sempre un oggetto reale (o un riferimento a un oggetto) di una classe.

  3. a->bè, in origine, una notazione abbreviata per (*a).b. Tuttavia, ->è l'unico degli operatori ad accedere ai membri che può essere sovraccaricato, quindi se aè un oggetto di una classe che sovraccarica operator->(i tipi comuni di questo tipo sono puntatori intelligenti e iteratori), allora il significato è qualunque cosa abbia implementato il progettista di classe. Per concludere: Con a->b, se aè un puntatore, bsarà un membro dell'oggetto a cui afa riferimento il puntatore . Se, tuttavia, aè un oggetto di una classe che sovraccarica questo operatore, operator->()viene invocata la funzione di operatore sovraccarico .


La piccola stampa:

  • In C ++, i tipi dichiarati come class, structo unionsono considerati "di tipo di classe". Quindi quanto sopra si riferisce a tutti e tre.
  • I riferimenti sono, semanticamente, alias di oggetti, quindi avrei dovuto aggiungere "o riferimento a un puntatore" anche al n. 3. Tuttavia, ho pensato che sarebbe stato più confuso che utile, dal momento che i riferimenti a pointers ( T*&) sono usati raramente.
  • Gli operatori punto e freccia possono essere utilizzati per fare riferimento a membri di classi statici da un oggetto, anche se non sono membri dell'oggetto. (Grazie a Oli per averlo sottolineato!)

10
Dovrebbe forse essere chiarito che .e ->può anche essere usato per accedere alla statica di classe tramite un oggetto, anche se non sono rigorosamente "membri dell'oggetto".
Oliver Charlesworth,

@Oli: è vero. L'ho aggiunto alla piccola stampa, poiché penso che non sia abbastanza comune e importante essere elencati nel testo principale.
sabato

3
Per completezza, potrebbe valere la pena sottolineare che operator*()può anche essere sovraccarico e che nulla costringe tale sovraccarico a essere coerente operator->()! (Non ho sottovalutato BTW, sono appena arrivato qui attraverso una lunga sequenza di duplicati)
juanchopanza

@OliCharlesworth sapresti dove è specificato nello standard C ++?
il maiale il

1
@juanchopanza: Tuttavia, non è possibile ottenere il comportamento incatenato ->sovraccaricandolo operator*e usando .. Solo i operator->sovraccarichi lo ottengono.
Ben Voigt,

36

Suggerire un'alternativa al punto 3 di sbi

a->bviene utilizzato solo se aè un puntatore. È una scorciatoia per (*a).bil bmembro dell'oggetto a cui apunta. C ++ ha due tipi di puntatori, "regolari" e puntatori intelligenti. Per puntatori regolari come A* a, il compilatore implementa ->. Per i puntatori intelligenti come std::shared_ptr<A> a, ->è una funzione membro della classe shared_ptr.

Motivazione: il pubblico di riferimento di queste FAQ non sta scrivendo suggerimenti intelligenti. Non hanno bisogno di sapere che ->si chiama davvero operator->(), o che è l'unico metodo di accesso dei membri che può essere sovraccaricato.


4
Indipendentemente dal fatto che io sia d'accordo o no, do questo +1solo per fornire una risposta alternativa.
sabato

2
Bene, ad essere onesti ->è anche sovraccarico per gli iteratori standard che qualsiasi programmatore C ++ dovrebbe incontrare presto, quindi dire che è usato solo per i puntatori potrebbe essere fonte di confusione.
Kiscsirke,

@Kiscsirke "normali programmatori C ++" non ha bisogno di scrivere tipi di puntatori intelligenti o iteratori, semplicemente li usa. "Dereferenze come un puntatore" si applica a entrambi.
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;
}

Dall'esempio di codifica sopra, vediamo che:
* Accesso ai membri (attributi e funzioni) da un'istanza (o oggetto) usando l'operatore punto ( .)
* Accesso ai membri (attributi e funzioni) da un puntatore a un oggetto (o creato da new) utilizzando l'operatore pointer ( ->)
* Accedere alle funzioni dei membri statici dalla classe stessa senza avere un oggetto come handle usando i due punti ( ::). [ Nota: è anche possibile richiamare la funzione membro statico da un'istanza con .o ->che non è consigliata]


@sbi così scontroso ah, so che è una specie di ripetizione. Voglio solo fare un esempio esplicito per mostrare come usarli. E dove ho detto ->può essere utilizzato solo da un puntatore che è stato allocato sull'heap new? Di seguito, il secondo elemento, penso di chiarire davvero che ->è per il puntatore. E prima di sottovalutare, è meglio provare className::non_static_member_function()con c ++ 14 da soli. Il riferimento non è un puntatore, quindi può essere utilizzato .e lo renderò più chiaro nella mia risposta.
Hu Xixi,

0

L'operatore punto viene utilizzato negli scenari di selezione diretta dei membri.

print(a.b)

Qui stiamo accedendo b, che è un membro diretto di un oggetto a. Quindi, in primo luogo, aè un oggetto e bè un membro (funzione / variabile, ecc) di a.


L'operatore freccia viene utilizzato negli scenari di selezione dei membri indiretti.

print(a->b)

Qui stiamo accedendo a bquale è un membro dell'oggetto, a cui punta a. È una scorciatoia di (*a).be quindi qui, aè principalmente un puntatore a un oggetto ed bè un membro di quell'oggetto.


L'operatore Double Colon (Scope) viene utilizzato negli scenari di selezione diretta dei membri relativi allo spazio dei nomi.

print(a::b)

Qui stiamo accedendo a bun membro della classe / namespace a. Quindi, principalmente, aè una classe / namespace ed bè un membro (funzione / variabile ecc.) a.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.