275 votes

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

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

(Note : Ceci est destiné à être une entrée dans la FAQ C++ de Stack Overflow. Si vous souhaitez critiquer l'idée de fournir une FAQ sous cette forme, alors le message sur meta qui est à l'origine de tout ceci serait l'endroit idéal pour le faire. Les réponses à cette question sont contrôlées dans le salon de discussion C++, où l'idée de la FAQ a été lancée en premier lieu, donc votre réponse a de grandes chances d'être lue par ceux qui ont eu l'idée.)_

280voto

sbi Points 100828

Les trois opérateurs distincts que C++ utilise pour accéder aux membres d'une classe ou d'un objet de classe, à savoir le double point :: le point . et la flèche -> sont utilisés pour trois scénarios différents qui sont toujours bien définis. En sachant cela, vous pouvez immédiatement en savoir beaucoup sur a y b juste en regardant a::b , a.b ou a->b respectivement, dans tout code que vous consultez.

  1. a::b n'est utilisé que si b est un membre de la classe (ou de l'espace de nom) a . C'est-à-dire que dans ce cas a sera toujours le nom d'une classe (ou d'un espace de nom).

  2. a.b n'est utilisé que si b est un membre de l'objet (ou une référence à un objet) a . Ainsi pour a.b , a sera toujours un objet réel (ou une référence à un objet) d'une classe.

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


Les petits caractères :

  • En C++, les types déclarés comme class , struct ou union sont considérés comme "de type classe". Ce qui précède se réfère donc à ces trois catégories.
  • Les références sont, sémantiquement, des alias d'objets, j'aurais donc dû ajouter "ou référence à un pointeur" au n° 3 également. Cependant, je pensais que cela serait plus déroutant qu'utile, puisque les références à des pointeurs ( T*& ) sont rarement utilisés.
  • Les opérateurs point et flèche peuvent être utilisés pour faire référence aux membres statiques de la classe d'un objet, même s'ils ne sont pas membres de l'objet. (Merci à Oli de nous l'avoir signalé !)

13 votes

Il faudrait éventuellement préciser que . y -> peuvent également être utilisées pour accéder aux statiques de la classe via un objet, même si elles ne sont pas strictement des "membres de l'objet".

0 votes

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

4 votes

Pour être complet, il peut être utile de souligner que operator*() peut également être surchargé, et que rien ne force cette surcharge à être cohérente avec operator->() ! (Je n'ai pas descendu le vote BTW, je suis juste arrivé ici via une longue séquence de duplicatas)

43voto

MSalters Points 74024

Suggérer une alternative pour le point 3 de sbi

a->b n'est utilisé que si a est un pointeur. C'est un raccourci pour (*a).b le b de l'objet qui a pointe vers. Le C++ dispose de deux types de pointeurs, les pointeurs "réguliers" et les pointeurs intelligents. Pour les pointeurs réguliers tels que A* a le 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. Il n'a pas besoin de savoir -> s'appelle en réalité operator->() ou que c'est la seule méthode d'accès aux membres qui peut être surchargée.

8 votes

Que je sois d'accord ou non, je lui donne un +1 juste pour avoir fourni une réponse alternative.

2 votes

Eh bien, pour être juste -> est également surchargé pour les itérateurs standards que tout programmeur C++ devrait rencontrer prochainement, donc dire qu'il est uniquement utilisé pour les pointeurs pourrait prêter à confusion.

0 votes

@Kiscsirke Les "programmeurs C++ ordinaires" n'ont pas besoin de l'être. écrire des types de pointeurs ou d'itérateurs intelligents, il suffit de les utiliser. "Déréférencer comme un pointeur" s'applique aux deux.

11voto

muditrustagii Points 346

L'opérateur point est utilisé dans 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, a est un objet et b est un membre (fonction/ variable etc) de a .


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

print(a->b)

Ici, nous accédons b qui est un membre de l'objet, qui est pointé par a . C'est un raccourci de *`(a).b** et donc ici,aest principalement un pointeur vers un objet etb` est un membre de cet objet.


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

print(a::b)

Ici, nous accédons b qui est un membre de la classe/espace de nom a Donc, principalement, a est une classe/un espace de nom et b est un membre (fonction/ variable etc) de a .

3voto

Hu Xixi Points 137
#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;
}

D'après l'exemple de codage ci-dessus, nous voyons que :
* Accès aux membres (attributs et fonctions) à partir d'une instance (ou d'un 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 ) en utilisant l'opérateur pointeur ( -> )
* Accès aux fonctions membres statiques à partir de la classe elle-même sans avoir un objet comme handle en utilisant le double point ( :: ). [ Note : vous pouvez également invoquer la fonction membre statique depuis une instance avec . o -> ce qui n'est pas recommandé]

0 votes

@sbi so grumpy ha, je sais que c'est une sorte de répétition. Je veux juste donner un exemple explicite pour montrer comment les utiliser. Et là où j'ai dit -> ne peut être utilisé que par un pointeur alloué sur le tas par new ? Ci-dessous, le deuxième point, je pense que j'ai bien précisé que -> est pour pointeur. Et avant que tu ne votes contre, tu ferais 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 utiliser la fonction . et je le préciserai dans ma réponse.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X