web-dev-qa-db-fra.com

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 ++?

Venant d'autres langages dérivés du C (comme Java ou C #) en C++, il est au début très déroutant que C++ dispose de trois façons de faire référence aux membres d'une classe: a::b, a.b et a->b. Quand dois-je utiliser lequel de ces opérateurs?

(Remarque: il s'agit d'une entrée dans FAQ C++ de Stack Overflow . Si vous souhaitez critiquer l'idée de fournir une FAQ dans ce formulaire , alors la publication sur la méta qui a commencé tout cela serait l'endroit pour le faire. Les réponses à cette question sont surveillées dans le C++ chatroom , où la FAQ L’idée a commencé au début, alors votre réponse sera très probablement lue par ceux qui l’ont proposée.)

235
sbi

Les trois opérateurs distincts utilisés par C++ pour accéder aux membres d'une classe ou d'un objet de classe, à savoir le double signe 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 en savez immédiatement beaucoup sur a et b simplement en regardant a::b, a.b Ou a->b, respectivement, dans n'importe quel code que vous regardez.

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

  2. a.b N'est utilisé que si b est un membre de l'objet (ou une référence à un objet) a. Donc 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 pour (*a).b. Cependant, -> Est le seul des opérateurs d'accès membre pouvant être surchargé. Par conséquent, si a est un objet d'une classe qui surcharge operator-> (Ces types courants sont des pointeurs intelligents.) et itérateurs), la signification est celle que le concepteur de classe a implémentée. Pour conclure: Avec a->b, Si a est un pointeur, b sera un membre de l'objet auquel le pointeur a fait référence. Si, toutefois, a est un objet d'une classe qui surcharge cet opérateur, la fonction opérateur surchargée operator->() est invoquée.


Les petits caractères:

  • En C++, les types déclarés comme class, struct ou union sont considérés comme "de type classe". Donc, ce qui précède fait référence aux trois d'entre eux.
  • Les références sont sémantiquement des alias sur des objets, donc j'aurais aussi dû ajouter "ou une référence à un pointeur" au n ° 3. Cependant, j'ai pensé que cela serait plus déroutant qu'utile, car les références aux pointeurs (T*&) Sont rarement utilisés.
  • Les opérateurs point et flèche peuvent être utilisés pour faire référence à des membres statiques d'une classe à partir d'un objet, même s'ils ne sont pas membres de l'objet. (Merci à Oli de l'avoir signalé!)
236
sbi

Proposer une alternative au point 3 de sbi

a->b N'est utilisé que si a est un pointeur. C'est un raccourci pour (*a).b, Le membre b de l'objet sur lequel a pointe. C++ a deux types de pointeurs, les pointeurs "normaux" et les pointeurs intelligents. Pour les pointeurs ordinaires 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 ceci FAQ n'écrit pas de pointeurs intelligents. Ils n'ont pas besoin de savoir que -> S'appelle vraiment operator->(), ou que c'est la seule méthode d'accès membre qui peut être surchargée.

36
MSalters
#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;
}

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

0
Hu Xixi