Question sur le masquage de la structure interne des classes

Résolu/Fermé
regitraz Messages postés 89 Date d'inscription vendredi 17 octobre 2014 Statut Membre Dernière intervention 30 mai 2021 - Modifié le 15 janv. 2020 à 17:28
mamiemando Messages postés 33079 Date d'inscription jeudi 12 mai 2005 Statut Modérateur Dernière intervention 23 avril 2024 - 24 mars 2020 à 12:46
Bonjour,
voici deux screenshot d'un de mes cours de programmation en c++ et j'aimerai comprendre ce qui est fait sur la deuxieme image.
Le contexte : il s'agit de la création de la structure d'une liste doublement chainé (la cellule est donnée ailleur) :





Merci

1 réponse

mamiemando Messages postés 33079 Date d'inscription jeudi 12 mai 2005 Statut Modérateur Dernière intervention 23 avril 2024 7 749
24 mars 2020 à 12:46
Bonjour,

En C et en C++, il est possible de déclarer un type (sur la base d'un autre type).

Exemples :
typedef int toto_t;
typedef int * pointeur_t;


En C++, il est possible de déclarer un type à l'intérieur d'une classe ou d'une structure. C'est ce qui est fait avec :

class Liste {
...
    typedef Cell * Place;
...
}


Ainsi, utiliser
Place
ou
Cell *
à l'intérieur de la classe
Liste
a le même sens.

L'opérateur
::


Comme le type
Place
est dans la classe, c'est un nom "relatif". Depuis l'extérieur de
Liste
il faut donc utiliser son nom absolu. Pour cela, le C++ a introduit (par rapport au C) un nouvel opérateur :
::
. Celui-ci se comporte comme
/
pour un chemin. Sauf qu'au lieu d'écrire
/Liste/Place
on écrit
::Liste::Place
ou plus simplement
Liste::Place
.

L'opérateur
::
s'applique aux classes, structures, mais aussi aux espaces de nommage (voir mot clé
namespace
).

Quel est l'intérêt ?

Dans l'absolu, on sent qu'on aura besoin du type de la cellule par exemple dans la méthode qui retournera le i-ème élément de la liste. Sans
typedef
, cette méthode aurait les signatures :

Cell * Liste::get(int i) const { ... }
const Cell * Liste::get(int i) const { ... }


On sent que ça n'est pas très élégant d'une part, et surtout si un jour on veut changer
Cell
par
Cellule
, cela impactera non seulement le code de
Liste
mais aussi tout le code qui utilise
Liste
. On voit alors que le fait d'utiliser
Cell
est un détail d'implémentation.

En déclarant le type
Place
, on abstrait le code extérieur à
Liste
de ce détail, car la signatures deviennent :

Place Liste::get(int i) const { ... }
const Place Liste::get(int i) const { ... }


On peut donc adapter l'implémentation de
Liste::Place
sans affecter le reste du code.

Pour aller plus loin

L'opérateur
::
peut, à l'image de
/
, être enchaîné. Ainsi voici à quoi ressemble la liste standard du C++ :

namespace std {
  template <typename T>
  class list {
    public:
      typedef ... iterator;
      typedef ... const_iterator;
    ...
  };
}


Ici on peut donc tout a fait parler de
std::list<int>::iterator
ou
std::list<int>::const_iterator
.

Bonne chance
0