Qu’est-ce qu’une méthode ‘const’ peut changer?

Les méthodes C ++ permettent à un qualificateur const d’indiquer que l’object n’est pas modifié par la méthode. Mais qu’est ce que ça veut dire? Par exemple. si les variables d’instance sont des pointeurs, cela signifie-t-il que les pointeurs ne sont pas modifiés ou que la mémoire sur laquelle elles pointent n’est pas modifiée?

Concrètement, voici un exemple minimal de classe

 class myclass { int * data; myclass() { data = new int[10]; } ~myclass() { delete [] data; } void set(const int index) const { data[index] = 1; } }; 

La méthode set correctement est-elle qualifiée de const ? Cela ne change pas les data variable membre, mais cela change certainement le contenu du tableau.

Plus simplement, cela signifie que le type de this est const T * intérieur de fonctions membres const, où T est votre classe, alors que dans les fonctions non qualifiées, il s’agit de T * .

Votre set méthodes ne modifie pas les data , il peut donc être qualifié de const. En d’autres termes, myclass::data est accessible en tant que this->data et est de type int * const .

Qu’est-ce qu’une méthode ‘const’ peut changer?

Sans exclure explicitement constness, une méthode const peut changer:

  • membres de données mutable , et
  • toute donnée à laquelle la classe a un access non const , que ces données soient ou non accessibles:
    • via des variables membres qui sont des pointeurs ou des références,
    • via des pointeurs ou des références passés en parameters de fonction,
    • via des pointeurs ou des références renvoyées par des fonctions,
    • directement dans l’espace de nom ou la classe (pour la statique) qui le contient.

Pour les membres de type class / struct / union , il s’appuie sur la constance de leurs fonctions membre pour déterminer les opérations à autoriser. (Cela peut également changer les variables locales non constantes et les parameters par valeur, mais je sais que ce n’est pas ce qui vous intéresse).

Il peut appeler d’autres méthodes const qui auront ces mêmes capacités et ressortingctions.

Par exemple. si les variables d’instance sont des pointeurs, cela signifie-t-il que les pointeurs ne sont pas modifiés ou que la mémoire sur laquelle elles pointent n’est pas modifiée?

Cela signifie que les pointeurs ne peuvent pas être modifiés (facilement / accidentellement). Cela ne signifie pas que la mémoire pointée ne peut pas être changée.

Ce que vous avez découvert, c’est l’inconvénient logique d’une fonction const qui modifie des données pointées ou référencées appartenant conceptuellement à l’object. Comme vous l’avez constaté, le compilateur n’applique pas l’exactitude de const que vous souhaitez peut-être ou attendez ici. C’est un peu dangereux, mais cela signifie que la constance n’a pas besoin d’être explicitement supprimée pour les pointeurs / références à d’autres objects qui peuvent être modifiés en tant qu’effet secondaire de la fonction const . Par exemple, un object de journalisation. (En règle générale, de tels objects ne sont pas logiquement “possédés” par l’object dont la fonction const est utilisée.) Le point clé est que le compilateur ne peut pas distinguer de manière fiable le type de propriété logique qu’un object a sur les données pointées. il faut deviner d’une manière ou d’une autre et permettre au programmeur de remplacer ou de ne pas être protégé par const -ness. C ++ renonce à la protection.

Intéressant, j’ai entendu dire que le langage D de Walter Bright inversait cette valeur par défaut, faisant de const -donnée pointée par défaut dans les fonctions const . Cela me semble plus sûr, mais il est difficile d’imaginer combien de fois on finira par avoir besoin de rejeter explicitement la constance pour autoriser les effets secondaires recherchés, et si cela donnerait une sensation satisfaisante de précision ou une verbosité ennuyeuse.

Il y a deux aspects à cette question:

  1. que signifie const pour le compilateur?
  2. comment const s’applique-t-il lorsqu’il ne peut pas être validé par le compilateur?

question 1

Le premier est plutôt simple. Le compilateur valide qu’aucun membre de données n’est modifié (à moins qu’ils ne soient qualifiés de mutable ). Il le valide de manière récursive: pour tous les types définis par l’utilisateur, il vérifie qu’aucune méthode non const n’est invoquée. Pour les types intégrés, il valide qu’ils ne sont pas affectés.

La transformation des pointeurs est T* à T*const (pointeur const), et non pas const T* (pointeur à const). Cela signifie que le compilateur ne valide pas que l’object pointé n’est pas modifié. Cela mène évidemment à la question 2.

question 2

Comment const s’applique-t-il lorsqu’il n’est pas validé par le compilateur? Cela signifie tout ce que cela devrait signifier pour votre application. Ceci est généralement appelé logique. Quand utiliser const par rapport à la constance logique est sujet à discussion .

const gros, const empêche de changer les valeurs des membres de l’instance de la classe dans la fonction. Ceci est utile pour une interface plus claire, mais pose des ressortingctions lors de l’utilisation de l’inheritance par exemple. C’est parfois un peu trompeur (ou beaucoup en fait), comme dans l’exemple que vous avez posté.

const serait le plus approprié pour les fonctions Get , où il est évident que l’appelant lit une valeur et n’a pas l’intention de changer l’état de l’object. Dans ce cas, vous voudrez peut-être aussi limiter les implémentations héritées à la const , afin d’éviter toute confusion et tout bogue caché lors de l’utilisation du polymorphism.

Par exemple

 class A{ int i; public: virtual int GetI() {return i;}; } class B : public A{ public: int GetI() { i = i*2; return i;}; // undesirable } 

changer de A à:

 virtual int GetI() const {return i;}; 

résout le problème.

const lorsqu’il est appliqué à une méthode signifie:

Cela signifie que l’ state de l’object ne sera pas modifié par la méthode.
Cela signifie que tous les membres qui font partie de l’état des objects ne peuvent pas être modifiés, et aucune fonction qui n’est pas également const ne peut être appelée.

En ce qui concerne les pointeurs. Cela signifie que le pointeur (s’il fait partie de l’état) ne peut pas être modifié. Mais l’object pointé par le pointeur fait partie d’un autre object, ce qui signifie que vous pouvez appeler des méthodes sans coût sur cet object (car il ne fait pas partie de l’état de cet object).