Perché una funzione membro const può modificare un membro dati statico?


86

Nel seguente C++programma, la modifica di un membro di dati statici da una constfunzione funziona correttamente:

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

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

Ma la modifica di un membro dati non statico da una constfunzione non funziona:

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

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

Perché una constfunzione membro può modificare un staticmembro dati?


Sarebbe utile se potessi dirci con quale piattaforma e compilatore stai lavorando? Quindi possiamo determinare se il comportamento è un bug relativo alla tua configurazione specifica o se il comportamento è effettivamente corretto e deve solo essere spiegato.
Alex Zywicki

@AlexZywicki Compilatore G ++ su piattaforma Linux.
msc

8
Non c'è bisogno. È intenzionale e tutti i compilatori C ++ devono supportarlo. Ma perché buone domande come questa non vengono più votate?
Bathsheba

18
È un dupe, ma è scritto meglio dell'altro grazie a un MCVE migliore, quindi l'ho usato come target.
Baum mit Augen

5
La motivazione qui è che constsignifica che una funzione membro di un oggetto non può modificare quell'unico oggetto . Può modificare altri oggetti della stessa classe, o staticdati, che sono associati alla classe, non una particolare istanza di essa. (O mutabledati membri, che sono stati creati per essere l'eccezione a questa regola.)
Davislor

Risposte:


100

È la regola, tutto qui. E per una buona ragione.

Il constqualificatore su una funzione membro significa che non è possibile modificare variabili membro mutablenon di staticclasse.

A titolo di razionalizzazione, il thispuntatore in una constfunzione membro qualificato è un consttipo ed thisè intrinsecamente correlato a un'istanza di una classe. statici membri non sono correlati a un'istanza di classe. Non hai bisogno di un'istanza per modificare un staticmembro: puoi farlo, nel tuo caso, scrivendo A::a = 10;.

Quindi, nel tuo primo caso, pensa a a = 10;come scorciatoia per A::a = 10;e nel secondo caso, pensalo come scorciatoia per this->a = 10;, che non è compilabile poiché il tipo di thisè const A*.


1
Solo un piccolo errore qui: poiché non è possibile riassegnare il thispuntatore, sarebbe di tipo const A* const nel constcaso di.
Taylor Hansen

2
@TaylorHansen thisè un prvalue di tipo puntatore. I valori dei tipi non di classe non sono mai qualificati per cv.

21

Secondo lo standard C ++ (9.2.3.2 membri dati statici)

1 Un membro dati statico non fa parte dei suboggetti di una classe ...

E (9.2.2.1 Il puntatore this)

1 Nel corpo di una funzione membro non statica (9.2.1), la parola chiave this è un'espressione prvalue il cui valore è l'indirizzo dell'oggetto per cui viene chiamata la funzione. Il tipo di questo in una funzione membro di una classe X è X *. Se la funzione membro è dichiarata const, il tipo di questo è const X * , ...

E infine (9.2.2 Funzioni membro non statiche)

3 ... se la ricerca del nome (3.4) risolve il nome nell'espressione id in un membro non statico non di tipo di qualche classe C e se l'espressione id è potenzialmente valutata o C è X o una classe base di X, l'espressione id viene trasformata in un'espressione di accesso ai membri della classe (5.2.5) usando (* this) (9.2.2.1) come espressione postfissa a sinistra di. operatore.

Così in questa definizione di classe

class A 
{
  public:   
    static int a; 

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

il membro di dati statici anon è un oggetto secondario di un oggetto del tipo di classe e del puntatorethis non viene utilizzato per accedere al membro di dati statici. Pertanto, qualsiasi funzione membro, costante non statica o non costante o una funzione membro statica può modificare il membro dati perché non è una costante.

In questa definizione di classe

class A 
{
  public:   
    int a; 

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

il membro dati non statico aè un oggetto secondario di un oggetto del tipo di classe. Per accedervi in ​​una funzione membro viene utilizzata una sintassi di accesso membro di questa sintassi. Non è possibile utilizzare un puntatore costante thisper modificare il membro dati. E il puntatore this è effettivamente di tipo const A *all'interno della funzione setperché la funzione è dichiarata con il qualificatoreconst . Se la funzione non avesse il qualificatore, in questo caso il membro dati potrebbe essere cambiato.


13

Il fatto è che se una funzione membro di una classe Aè const, il tipo di thisè const X*, e quindi impedisce che i membri dati non statici vengano alterati (cfr, ad esempio, standard C ++ ):

9.3.2 Il puntatore this [class.this]

Nel corpo di una funzione membro non statica (9.3), la parola chiave this è un'espressione prvalue il cui valore è l'indirizzo dell'oggetto per cui viene chiamata la funzione. Il tipo di questo in una funzione membro di una classe X è X *. Se la funzione membro è dichiarata const, il tipo di questo è const X *, ...

Se aè un membro dati non statico, a=10è uguale a this->a = 10, che non è consentito se il tipo di thisè const A*e anon è stato dichiarato come mutable. Quindi, poiché void set() constfa il tipo di thisessere const A*, questo accesso non è consentito.

Se aè un membro dati statico, al contrario, a=10non coinvolge thisaffatto; e fintanto che di static int aper sé non è stato dichiarato come const, l'istruzione a=10è consentita.


1

La constqualificazione su una funzione di membro significa che non è possibile modificare non-mutable, non-static membri di dati di classe .

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.