Warum kann eine const-Member-Funktion ein statisches Datenelement ändern?

85

Im folgenden C++Programm funktioniert das Ändern eines statischen Datenelements aus einer constFunktion einwandfrei:

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

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

Das Ändern eines nicht statischen Datenelements aus einer constFunktion funktioniert jedoch nicht:

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

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

Warum kann eine constMitgliedsfunktion ein staticDatenelement ändern ?

msc
quelle
Es wäre hilfreich, wenn Sie uns mitteilen könnten, mit welcher Plattform und welchem ​​Compiler Sie arbeiten. So können wir feststellen, ob das Verhalten ein Fehler ist, der mit Ihrem spezifischen Setup zusammenhängt, oder ob das Verhalten tatsächlich korrekt ist und nur erklärt werden muss.
Alex Zywicki
@AlexZywicki G ++ Compiler auf Linux-Plattform.
msc
8
Das ist nicht nötig. Es ist beabsichtigt und alle C ++ - Compiler müssen es unterstützen. Aber warum werden solche guten Fragen nicht mehr positiv bewertet?
Bathseba
18
Es ist ein Betrüger, aber dank eines besseren MCVE ist es besser geschrieben als das andere, also habe ich es als Ziel verwendet.
Baum mit Augen
5
Die Motivation hierbei ist, dass consteine Elementfunktion eines Objekts dieses eine Objekt nicht ändern kann . Es kann andere Objekte derselben Klasse oder staticDaten, die der Klasse zugeordnet sind, ändern , nicht eine bestimmte Instanz davon. (Oder mutableDatenelemente, die als Ausnahme von dieser Regel erstellt wurden.)
Davislor

Antworten:

99

Es ist die Regel, das ist alles. Und das aus gutem Grund.

Das constQualifikationsmerkmal für eine Mitgliedsfunktion bedeutet, dass Sie keine mutableNicht- staticKlassen-Mitgliedsvariablen ändern können.

Um eine gewisse Rationalisierung zu ermöglichen, ist der thisZeiger in einer constqualifizierten Elementfunktion ein constTyp und thisinhärent mit einer Instanz einer Klasse verbunden. staticMitglieder sind nicht mit einer Klasseninstanz verbunden. Sie benötigen keine Instanz, um ein staticMitglied zu ändern. Sie können dies in Ihrem Fall durch Schreiben tun A::a = 10;.

Stellen Sie sich in Ihrem ersten Fall eine a = 10;Abkürzung für A::a = 10;und im zweiten Fall eine Abkürzung für vor this->a = 10;, die nicht kompilierbar ist, da die Art von thisist const A*.

Bathseba
quelle
1
Nur ein kleiner Fehler hier: Da Sie das nicht neu zuweisen können thisZeiger, wäre es der Typ sein , const A* const in consts Fall‘.
Taylor Hansen
2
@TaylorHansen thisist ein Wert vom Zeigertyp. Werte von Nicht-Klassentypen sind niemals lebenslaufqualifiziert.
21

Gemäß dem C ++ Standard (9.2.3.2 Statische Datenelemente)

1 Ein statisches Datenelement ist nicht Teil der Unterobjekte einer Klasse ...

Und (9.2.2.1 Der dieser Zeiger)

1 Im Hauptteil einer nicht statischen (9.2.1) Elementfunktion ist das Schlüsselwort this ein prvalue-Ausdruck, dessen Wert die Adresse des Objekts ist, für das die Funktion aufgerufen wird. Der Typ in einer Mitgliedsfunktion einer Klasse X ist X *. Wenn die Elementfunktion als const deklariert ist, lautet der Typ const X * , ...

Und endlich (9.2.2 Nicht statische Elementfunktionen)

3 ... wenn die Namenssuche (3.4) den Namen im ID-Ausdruck in ein nicht statisches Nicht-Typ-Mitglied einer Klasse C auflöst und wenn entweder der ID-Ausdruck möglicherweise ausgewertet wird oder C X oder eine Basisklasse ist von X wird der ID-Ausdruck in einen Klassenmitgliedszugriffsausdruck (5.2.5) umgewandelt, wobei (* this) (9.2.2.1) als Postfix-Ausdruck links vom verwendet wird. Operator.

Also in dieser Klassendefinition

class A 
{
  public:   
    static int a; 

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

Das statische Datenelement aist kein Unterobjekt eines Objekts vom Klassentyp, und der Zeiger thiswird nicht für den Zugriff auf das statische Datenelement verwendet. Daher kann jede Elementfunktion, nicht statische Konstante oder Nichtkonstante oder eine statische Elementfunktion das Datenelement ändern, da es keine Konstante ist.

In dieser Klassendefinition

class A 
{
  public:   
    int a; 

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

Das nicht statische Datenelement aist ein Unterobjekt eines Objekts vom Klassentyp. Um in einer Mitgliedsfunktion darauf zuzugreifen, wird entweder eine Mitgliedszugriffssyntax dieser Syntax impliziert. Sie dürfen keinen konstanten Zeiger verwenden this, um das Datenelement zu ändern. Und der Zeiger, den dies ist, hat tatsächlich einen Typ const A *innerhalb der Funktion, setda die Funktion mit dem Qualifizierer deklariert wird const. Wenn die Funktion in diesem Fall kein Qualifikationsmerkmal hätte, könnte das Datenelement geändert werden.

Vlad aus Moskau
quelle
13

Die Sache ist, dass, wenn eine Elementfunktion einer Klasse Aist const, der Typ von thisist const X*und dadurch verhindert wird , dass nicht statische Datenelemente geändert werden (siehe z. B. C ++ - Standard ):

9.3.2 Der this-Zeiger [class.this]

Im Hauptteil einer nicht statischen (9.3) Elementfunktion ist das Schlüsselwort this ein prvalue-Ausdruck, dessen Wert die Adresse des Objekts ist, für das die Funktion aufgerufen wird. Der Typ in einer Mitgliedsfunktion einer Klasse X ist X *. Wenn die Elementfunktion als const deklariert ist, lautet der Typ const X *, ...

Wenn aes sich um ein nicht statisches Datenelement handelt, a=10ist es dasselbe wie this->a = 10, was nicht zulässig ist, wenn der Typ von thisist const A*und anicht als deklariert wurde mutable. Daher ist dieser Zugriff nicht erlaubt , da er void set() constdie Art des thisSeins macht const A*.

Wenn aes sich dagegen um ein statisches Datenelement handelt, handelt es sich a=10überhaupt nicht darum this. und solange static int aan sich nicht als deklariert wurde const, a=10ist eine Aussage erlaubt.

Stephan Lechner
quelle
1

Die constQualifier auf einem Member - Funktion bedeutet , dass Sie nicht ändern können non-mutable, non-static Klasse Datenelemente .

Li Kui
quelle