Surcharger l'opérateur -> en C++
Tags: cpp, french
Published: 2022-02-10 10:46:17

---
layout: post
title: Surcharger l'opérateur -> en C++
published: true
tags: [Cpp, French]
---

## 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](https://en.cppreference.com/w/cpp/language/operator_member_access). De base, il permet d’accéder à un attribut ou à une méthode d’un objet via un pointeur. Exemple : 
```C++
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 :
```C++
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 :
- un pointeur
- un objet, par référence ou par valeur, qui a lui-même une surcharge de l’opérateur ->

```C++
// 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à :
```C++
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 :
```C++
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 -> :
* Avoir une utilisation et un comportement similaire à celui d’un pointeur : c’est le cas par exemple pour les [pointeurs intelligents](https://docs.microsoft.com/en-us/cpp/cpp/smart-pointers-modern-cpp?view=msvc-160)
* 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
* [std::unique_ptr](https://en.cppreference.com/w/cpp/memory/unique_ptr)
* [std::shared_ptr](https://en.cppreference.com/w/cpp/memory/shared_ptr)
* [std::optional](https://en.cppreference.com/w/cpp/utility/optional)
* Les itérateurs des [conteneurs](https://en.cppreference.com/w/cpp/container)

## Sources
* [https://docs.microsoft.com/en-us/cpp/cpp/smart-pointers-modern-cpp?view=msvc-160](https://docs.microsoft.com/en-us/cpp/cpp/smart-pointers-modern-cpp?view=msvc-160)
* [https://en.cppreference.com/w/cpp/language/operator_member_access](https://en.cppreference.com/w/cpp/language/operator_member_access)
* [https://en.cppreference.com/w/cpp/language/operators](https://en.cppreference.com/w/cpp/language/operators)
* [https://en.cppreference.com/w/cpp/utility/optional](https://en.cppreference.com/w/cpp/utility/optional)
* [https://en.cppreference.com/w/cpp/memory/unique_ptr](https://en.cppreference.com/w/cpp/memory/unique_ptr)
* [https://en.cppreference.com/w/cpp/memory/shared_ptr](https://en.cppreference.com/w/cpp/memory/shared_ptr)