Quand dois-je utiliser un point, une flèche ou un double signe deux-points pour faire référence aux membres d'une classe en C ++?


243

En venant d'autres langues dérivées C (comme Java ou C #) à C ++, il est tout d' abord très déroutant que C ++ a trois façons de se référer aux membres d'une classe: a::b, a.b, et a->b. Quand dois-je utiliser lequel de ces opérateurs?

(Remarque: Ceci est censé être une entrée dans la FAQ C ++ de Stack Overflow . Si vous voulez critiquer l'idée de fournir une FAQ sous cette forme, alors la publication sur la méta qui a commencé tout cela serait l'endroit pour le faire. Réponses à cette question est surveillée dans le salon de discussion C ++ , où l'idée de FAQ a commencé en premier lieu, donc votre réponse est très susceptible d'être lue par ceux qui ont eu l'idée.)

Réponses:


248

Les trois opérateurs distincts utilisés par C ++ pour accéder aux membres d'une classe ou d'un objet de classe, à savoir les deux points ::, le point .et la flèche ->, sont utilisés pour trois scénarios différents qui sont toujours bien définis. Sachant cela vous permet de connaître immédiatement beaucoup de choses sur aet bjuste en regardant a::b, a.bou a->b, respectivement, en tout code que vous regardez.

  1. a::bn'est utilisé que s'il best membre de la classe (ou de l'espace de noms) a. Autrement dit, dans ce cas asera toujours le nom d'une classe (ou espace de noms).

  2. a.bn'est utilisé que s'il best membre de l'objet (ou référence à un objet) a. Donc, pour a.b, asera toujours un objet réel (ou une référence à un objet) d'une classe.

  3. a->best, à l'origine, une notation abrégée pour (*a).b. Cependant, ->est le seul des opérateurs d'accès membres qui peut être surchargé, donc s'il as'agit d'un objet d'une classe qui surcharge operator->(les types courants sont les pointeurs intelligents et les itérateurs), la signification est celle que le concepteur de classe a implémentée. Pour conclure: Avec a->b, si aest un pointeur, bsera un membre de l'objet auquel le pointeur afait référence. Si, cependant, aest un objet d'une classe qui surcharge cet opérateur, alors la fonction d'opérateur surchargée operator->()est invoquée.


Les petits caractères:

  • En C ++, les types déclarés class, structou unionsont considérés comme « de type de classe ». Donc, ce qui précède se réfère à tous les trois.
  • Les références sont, sémantiquement, des alias d'objets, donc j'aurais dû ajouter "ou référence à un pointeur" au # 3 également. Cependant, j'ai pensé que ce serait plus déroutant qu'utile, car les références aux pointeurs ( T*&) sont rarement utilisées.
  • Les opérateurs point et flèche peuvent être utilisés pour faire référence aux membres de classe statiques d'un objet, même s'ils ne sont pas membres de l'objet. (Merci à Oli de l'avoir signalé!)

10
Il devrait éventuellement être clarifié .et ->peut également être utilisé pour accéder à la statique de classe via un objet, même s'ils ne sont pas strictement "membres de l'objet".
Oliver Charlesworth

@Oli: C'est en effet vrai. Je l'ai ajouté aux petits caractères, car je pense que ce n'est pas courant et suffisamment important pour être répertorié dans le texte principal.
sbi

3
Par souci d'exhaustivité, il peut être utile de souligner que l' operator*()on peut également être surchargé, et que rien n'oblige cette surcharge à être cohérente operator->()! (Je n'ai pas downvote BTW, je suis juste arrivé ici via une longue séquence de doublons)
juanchopanza

@OliCharlesworth sauriez-vous où cela est spécifié dans la norme C ++?
le porc du

1
@juanchopanza: Cependant, vous ne pouvez pas obtenir le comportement de chaînage ->en surchargeant operator*et en utilisant .. Seules les operator->surcharges l'obtiennent.
Ben Voigt du

36

Proposer une alternative au point 3 de sbi

a->bn'est utilisé que si aest un pointeur. Il s'agit d'un raccourci pour (*a).b, le bmembre de l'objet qui apointe vers. C ++ possède deux types de pointeurs, les pointeurs «réguliers» et les pointeurs intelligents. Pour les pointeurs réguliers tels que A* ale compilateur implémente ->. Pour les pointeurs intelligents tels que std::shared_ptr<A> a, ->est une fonction membre de la classe shared_ptr.

Justification: le public cible de cette FAQ n'écrit pas de pointeurs intelligents. Ils n'ont pas besoin de savoir que ->c'est vraiment appelé operator->(), ou que c'est la seule méthode d'accès membre qui peut être surchargée.


4
Peu importe que je sois d'accord ou non, je donne ceci +1juste pour fournir une réponse alternative.
sbi

2
Eh bien, pour être juste, il ->est également surchargé pour les itérateurs standard que tout programmeur C ++ devrait bientôt rencontrer, donc dire qu'il n'est utilisé que pour les pointeurs pourrait être source de confusion.
Kiscsirke

@Kiscsirke "les programmeurs C ++ ordinaires" n'ont pas besoin d' écrire des types de pointeurs ou d'itérateurs intelligents, juste de les utiliser. "Les déréférences comme un pointeur" s'appliquent aux deux.
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;
}

De l'exemple de codage ci-dessus, nous voyons que:
* Accès aux membres (attributs et fonctions) à partir d'une instance (ou objet) en utilisant l'opérateur point ( .)
* Accès aux membres (attributs et fonctions) à partir d'un pointeur vers un objet (ou créé par new) using the pointer operator ( ->)
* Accès aux fonctions membres statiques à partir de la classe elle-même sans avoir d'objet comme poignée à l'aide du double signe deux-points ( ::). [ Remarque: vous pouvez également appeler la fonction membre statique à partir d'une instance avec .ou ->qui n'est pas recommandée]


@sbi ha tellement grincheux, je sais que c'est une sorte de répétition. Je veux juste donner un exemple explicite pour montrer comment les utiliser. Et où j'ai dit ->ne peut être utilisé que par un pointeur alloué sur le tas par new? Ci-dessous, le deuxième élément, je pense que je précise vraiment que ->c'est pour le pointeur. Et avant de downvote, vous feriez mieux d'essayer className::non_static_member_function()avec c ++ 14 par vous-même. La référence n'est pas un pointeur, elle peut donc être utilisée ., et je le préciserai dans ma réponse.
Hu Xixi

0

L'opérateur point est utilisé dans les scénarios de sélection directe des membres.

print(a.b)

Ici, nous accédons b, qui est un membre direct d'un objet a. Donc, principalement, aest un objet et best un membre (fonction / variable, etc.) de a.


L'opérateur de flèche est utilisé dans les scénarios de sélection de membres indirects.

print(a->b)

Ici, nous accédons à bun membre de l'objet, indiqué par a. Il est un raccourci (*a).bet donc ici, aest principalement un pointeur vers un objet et best un membre de cet objet.


L'opérateur Double Colon (Scope) est utilisé dans les scénarios de sélection directe des membres liés à l' espace de noms.

print(a::b)

Ici, nous accédons à bun membre de la classe / espace de noms a. Donc, principalement, aest une classe / espace de noms et best un membre (fonction / variable, etc.) de a.

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.