DEV Community

Lena
Lena

Posted on

Surcharger l'opérateur -> en C++

Qu'est-ce que l’opérateur -> ?

L’opérateur ->, de son petit nom opérateur membre de pointeur, est un des opérateurs d'accès membres. De base, il permet d’accéder à un attribut ou à une méthode d’un objet via un pointeur. Exemple :

std::string str = "Hello, World !";
std::string* ptr = &str;
bool is_empty = ptr->empty();
Enter fullscreen mode Exit fullscreen mode

Il est l’équivalent de la combinaison de l’opérateur de déréférencement "*" et de l'opérateur membre d'objet "." , par exemple le snippet de code précédent est l’équivalent de celui-ci :

std::string str = "Hello, World !";
std::string* ptr = &str;
// On utilise des parenthèses à cause de la précédence de l'opérateur . sur l'opérateur *
bool is_empty = (*ptr).empty();
Enter fullscreen mode Exit fullscreen mode

La surcharge, ça se passe comment ?

Le prototype de la surcharge

Pour surcharger l’opérateur ->, il faut déclarer une méthode nommée operator->, sans argument, qui retourne soit :

  • un pointeur
  • un objet, par référence ou par valeur, qui a lui-même une surcharge de l’opérateur ->
// Exemple où l'on retourne un pointeur
struct StrWrapper
{
    std::string* operator->()
    {
        return &str;
    }

    std::string str;
};

// Exemple où l'on retourne un objet qui a un opérateur -> surchargé
struct WrapperOfWrapper
{   
    StrWrapper operator->()
    {
        return str_wrapper;
    }

    StrWrapper str_wrapper;
};
Enter fullscreen mode Exit fullscreen mode

Le comportement si un pointeur est retourné

C’est le cas le plus simple : dans ce cas, on utilise directement le pointeur retourné comme un pointeur classique, et ainsi on peut accéder à un attribut ou à une méthode comme on le ferait avec un pointeur normal. Si on reprend la classe StrWrapper de l’exemple ci-dessus, on peut écrire ce code-là :

StrWrapper str_wrapper{"Awesome"};
std::cout << str_wrapper->size() << std::endl; // Affiche 7
// La ligne ci-dessus et l'équivalent de la ligne ci-dessous car l'opérateur ->
// retourne un pointeur vers la std::string contenu dans la classe
std::cout << str_wrapper.str.size() << std::endl; // Affiche 7 aussi
Enter fullscreen mode Exit fullscreen mode

Le comportement si un objet est retourné

Dans ce cas, le compilateur va appeler l’opérateur -> de l’objet retourné : si ce nouvel appel retourne un objet, on recommence successivement jusqu’à obtenir un pointeur, ce qui nous fait retomber sur le premier cas expliqué précédemment. Voici un exemple reprenant les classes StrWrapper et WrapperOfWrapper pour mieux comprendre :

WrapperOfWrapper wow{"Awesome"};
std::cout << wow->size() << std::endl; // Affiche 7
// C'est l'équivalent de ça :
std::cout << wow.str_wrapper->size() << std::endl;
// Qui est lui même l'équivalent de ça :
std::cout << wow.str_wrapper.str.size() << std::endl; 
Enter fullscreen mode Exit fullscreen mode

Pourquoi surcharger cet opérateur ?

On peut citer deux raisons communes de surcharger l’opérateur -> :

  • Avoir une utilisation et un comportement similaire à celui d’un pointeur : c’est le cas par exemple pour les pointeurs intelligents
  • Pouvoir accéder facilement aux méthodes et attributs d'une classe wrappée à partir d'une autre classe (qui la contient). On peut citer les itérateurs de la bibliothèque standard comme exemple.

Exemples de surcharges de l’opérateur -> dans la bibliothèque standard

Sources

Latest comments (0)