Pourquoi une fonction membre const peut-elle modifier un membre de données statique?

86

Dans le C++programme suivant , la modification d'un membre de données statiques à partir d'une constfonction fonctionne correctement:

class A 
{
  public:   
    static int a; // static data member

    void set() const
    {
        a = 10;
    }
};

Mais la modification d'un membre de données non statique à partir d'une constfonction ne fonctionne pas:

class A 
{
  public:   
    int a; // non-static data member

    void set() const
    {
        a = 10;
    }
};

Pourquoi une constfonction membre peut-elle modifier un staticmembre de données?

msc
la source
Ce serait utile si vous pouviez nous dire avec quelle plate-forme et compilateur vous travaillez? Nous pouvons donc déterminer si le comportement est un bogue lié à votre configuration spécifique ou si le comportement est effectivement correct et a juste besoin d'être expliqué.
Alex Zywicki
Compilateur @AlexZywicki G ++ sur plateforme Linux.
msc
8
Ce n'est pas nécessaire. C'est intentionnel et tous les compilateurs C ++ doivent le prendre en charge. Mais pourquoi de bonnes questions comme celle-ci ne sont-elles plus votées?
Bathsheba
18
C'est une dupe, mais c'est mieux écrit que l'autre grâce à un meilleur MCVE, donc je l'ai utilisé comme cible.
Baum mit Augen
5
La motivation ici est que cela constsignifie qu'une fonction membre d'un objet ne peut pas modifier cet objet . Il peut modifier d'autres objets de la même classe, ou des staticdonnées, qui sont associées à la classe, pas une instance particulière de celle-ci. (Ou mutableles membres de données, qui ont été créés pour être l'exception à cette règle.)
Davislor

Réponses:

100

C'est la règle, c'est tout. Et pour une bonne raison.

Le constqualificatif sur une fonction membre signifie que vous ne pouvez pas modifier les variables membres non mutablenon- staticclasse.

Pour offrir une certaine rationalisation, le thispointeur dans une constfonction membre qualifiée est un consttype, et thisest intrinsèquement lié à une instance d'une classe. staticles membres ne sont pas liés à une instance de classe. Vous n'avez pas besoin d'une instance pour modifier un staticmembre: vous pouvez le faire, dans votre cas, en écrivant A::a = 10;.

Donc, dans votre premier cas, pensez a = 10;à un raccourci pour A::a = 10;et dans le second cas, considérez-le comme un raccourci pour this->a = 10;, qui n'est pas compilable puisque le type de thisest const A*.

Bathsheba
la source
1
Juste une petite erreur ici: puisque vous ne pouvez pas réaffecter le thispointeur, il serait de type const A* const dans constle cas de.
Taylor Hansen
2
@TaylorHansen thisest une valeur de type pointeur. Les valeurs prvalues ​​des types non-classe ne sont jamais qualifiées cv.
21

Selon la norme C ++ (9.2.3.2 membres de données statiques)

1 Un membre de données statique ne fait pas partie des sous-objets d'une classe ...

Et (9.2.2.1 Le pointeur this)

1 Dans le corps d'une fonction membre non statique (9.2.1), le mot-clé this est une expression prvalue dont la valeur est l'adresse de l'objet pour lequel la fonction est appelée. Le type de ceci dans une fonction membre d'une classe X est X *. Si la fonction membre est déclarée const, le type de ceci est const X * , ...

Et enfin (9.2.2 Fonctions membres non statiques)

3 ... si la recherche de nom (3.4) résout le nom dans l'expression-id en un membre non-statique non-type d'une classe C, et si soit l'expression-id est potentiellement évaluée, soit C est X ou une classe de base de X, l'expression id est transformée en une expression d'accès de membre de classe (5.2.5) en utilisant (* this) (9.2.2.1) comme expression de suffixe à gauche de. opérateur.

Ainsi dans cette définition de classe

class A 
{
  public:   
    static int a; 

    void set() const
    {
        a = 10;
    }
};

le membre de données statiques an'est pas un sous-objet d'un objet du type de classe et le pointeur thisn'est pas utilisé pour accéder au membre de données statiques. Ainsi, toute fonction membre, constante non statique ou non constante, ou une fonction membre statique peut changer le membre de données car ce n'est pas une constante.

Dans cette définition de classe

class A 
{
  public:   
    int a; 

    void set() const
    {
        a = 10;
    }
};

le membre de données non statique aest un sous-objet d'un objet de type classe. Pour y accéder dans une fonction membre, on utilise soit une syntaxe d'accès aux membres de cette syntaxe est implicite. Vous ne pouvez pas utiliser un pointeur constant thispour modifier le membre de données. Et le pointeur dont il s'agit a en effet du type const A *dans la fonction setcar la fonction est déclarée avec le qualificatif const. Si la fonction n'avait pas de qualificatif dans ce cas, le membre de données pourrait être modifié.

Vlad de Moscou
la source
13

Le fait est que si une fonction membre d'une classe Aest const, alors le type de thisest const X*, et empêche ainsi les membres de données non statiques d'être modifiés (cf., par exemple, le standard C ++ ):

9.3.2 Le pointeur this [class.this]

Dans le corps d'une fonction membre non statique (9.3), le mot-clé this est une expression prvalue dont la valeur est l'adresse de l'objet pour lequel la fonction est appelée. Le type de ceci dans une fonction membre d'une classe X est X *. Si la fonction membre est déclarée const, le type de ceci est const X *, ...

Si aest un membre de données non statique, alors a=10est identique à this->a = 10, ce qui n'est pas autorisé si le type de thisest const A*et an'a pas été déclaré comme mutable. Ainsi, puisque void set() constfait le type d' thisêtre const A*, cet accès n'est pas autorisé.

Si aest un membre de données statique, en revanche, a=10n'implique pas thisdu tout; et tant que static int apar lui-même n'a pas été déclaré comme const, la déclaration a=10est autorisée.

Stéphan Lechner
la source
1

Le constqualificatif sur une fonction membre des moyens que vous ne pouvez pas modifier non-mutable, les non-static membres de données de classe .

Li Kui
la source