Cerca nel sito:
ricerca
avanzata

Frasi Celebri...

Lo scrittore ? un uomo la cui intelligenza non basta per smettere di scrivere.

G?nter Grass 

Sondaggio:

A tuo giudizio, riaprire le "casechiuse" ?...

Un modo per combattere la criminalit?
Un insulto alle donne
Una cosa da fare al pi? presto
L'ennesima stupidaggine di questo governo
Una cosa che non mi interessa

visualizza risultati


 

Membri const e mutable

Oltre ad attributi di tipo static, e` possibile avere attributi const; in questo caso pero` l'attributo const non e` trattato come una normale costante: esso viene allocato per ogni istanza come un normale attributo, tuttavia il valore che esso assume per ogni istanza viene stabilito una volta per tutte all'atto della creazione dell'istanza stessa e non potra` mai cambiare durante la vita dell'oggetto. Il valore di un attributo const, infine, va settato tramite la lista di inizializzazione del costruttore:


  class MyClass {
    public:
      MyClass(int a, float b);
      /* ... */

    private:
      const int ConstMember;
      float AFloat;
  };

  MyClass::MyClass(int a, float b)
         : ConstMember(a), AFloat(b) { };


Il motivo per cui bisogna ricorrere alla lista di inizializzazione e` semplice: l'assegnamento e` una operazione proibita sulle costanti, l'operazione che si compie tramite la lista di inizializzazione e` invece concettualmente diversa (anche se per i tipi primitivi e` equivalente ad un assegnamento), la cosa diverra` piu` evidente quando vedremo che il generico membro di una classe puo` essere a sua volta una istanza di una generica classe.

E` anche possibile avere funzioni membro const analogamente a quanto avviene per le funzioni membro statiche. Dichiarando un metodo const si stabilisce un contratto con il compilatore: la funzione membro si impegna a non accedere in scrittura ad un qualsiasi attributo della classe e il compilatore si impegna a segnalare con un errore ogni tentativo in tal senso. Oltre a cio` esiste un altro vantaggio a favore dei metodi const: sono gli unici a poter essere eseguiti su istanze costanti (che per loro natura non possono essere modificate). Per dichiarare una funzione membro const e` necessario far seguire la lista dei parametri dalla keyword const, come mostrato nel seguente esempio:


  class MyClass {
    public:
      MyClass(int a, float b) : ConstMember(a),
                                AFloat(b) {};

      int GetConstMember() const {
        return ConstMember;
      }

      void ChangeFloat(float b) {
        AFloat = b;
      }

    private:
      const int ConstMember;
      float AFloat;
  };

  int main(int, char* []) {
    MyClass A(1, 5.3);
    const MyClass B(2, 3.2);

    A.GetConstMember();     // Ok!
    B.GetConstMember();     // Ok!
    A.ChangeFloat(1.2);     // Ok!
    B.ChangeFloat(1.7);     // Errore!
    return 0;
  }


Si osservi che se la funzione membro GetConstMember() fosse stata definita fuori dalla dichiarazione di classe, avremmo dovuto nuovamente esplicitare le nostre intenzioni:


  class MyClass {
    public:
      MyClass(int a, float b) : ConstMember(a),
                                AFloat(b) {};

      int GetConstMember() const;

      /* ... */
  };

  int MyClass::GetConstMember() const {
    return ConstMember;
  }


Avremmo dovuto cioe` esplicitare nuovamente il const (cosa che non avviene con le funzioni membro static).
Come per i metodi static, non e` possibile avere costruttori e distruttori const (sebbene essi vengano utilizzati per costruire e distruggere anche le istanze costanti).

Talvolta puo` essere necessario che una funzione membro costante possa accedere in scrittura ad uno o piu` attributi della classe, situazioni di questo genere sono rare ma possibili (si pensi ad un oggetto che mappi un dispositivo che debba trasmettere dati residenti in ROM attraverso una porta hardware, solo metodi const possono accedere alla ROM...). Una soluzione potrebbe essere quella di eseguire un cast per rimuovere la restrizione del const, ma una soluzione di questo tipo sarebbe nascosta a chi usa la classe.
Per rendere esplicita una situazione di questo tipo e` stata introdotta la keyword mutable, un attributo dichiarato mutable puo` essere modificato anche da funzioni membro costanti:


  class AccessCounter {
    public:
      AccessCounter();
      const double GetPIValue() const;
      const int GetAccessCount() const;

    private:
      const double PI;
      mutable int Counter;
  };

  AccessCounter::AccessCounter() : PI(3.14159265),
                                   Counter(0) {}

  const double AccessCounter::GetPIValue() const {
    ++Counter;       // Ok!
    return PI;
  }

  const int AccessCounter::GetAccessCount() const {
    return Counter;
  }


L'esempio (giocattolo) mostra il caso di una classe che debba tenere traccia del numero di accessi in lettura ai suoi dati, senza mutable e senza ricorrere ad un cast esplicito la soluzione ad un problema simile sarebbe stata piu` artificiosa e complicata.

 

successivo
–«  INDICE  »–

 

 

 

 
Powered by paper&pencil (carta&matita ) - Copyright © 2001-2019 Cataldo Sasso