Baduit

A young French developper who really likes (modern) C++

About me
01 October 2021

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

by Baduit

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 :

1
2
3
std::string str = "Hello, World !";
std::string* ptr = &str;
bool is_empty = ptr->empty();

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 :

1
2
3
4
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();

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 :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// 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;
};

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à :

1
2
3
4
5
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

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 :

1
2
3
4
5
6
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; 

Pourquoi surcharger cet opérateur ?

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

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

Sources

tags: C++