Membri static
Normalmente istanze diverse della stessa classe non condividono direttamente
risorse di memoria, l'unica possibilita` sarebbe quella di avere puntatori che
puntano allo stesso indirizzo, per il resto ogni nuova istanza riceve nuova
memoria per ogni attributo. Tuttavia in alcuni casi e` desiderabile che alcuni
attributi fossero comuni a tutte le istanze; per utilizzare un termine tecnico,
si vuole realizzare una comunicazione ad ambiente condiviso. Si pensi ad esempio
ad un contatore che indichi il numero di istanze di una certa classe in un certo
istante...
Per rendere un attributo comune a tutte le istanze occorre dichiararlo static :
class MyClass {
public:
MyClass();
/* ... */
private:
static int Counter;
char * String;
/* ... */
};
Gli attributi static possono in pratica essere visti come elementi
propri della classe, non dell'istanza. In questo senso non e` possibile inizializzare
un attributo static tramite la lista di inizializzazione del costruttore,
tutti i metodi (costruttore compreso) possono accedere sia in scrittura che
in lettura all'attributo, ma non si puo` inizializzarlo tramite un costruttore:
MyClass::MyClass() : Counter(0) { // Errore!
/* ... */
}
Il motivo e` abbastanza ovvio, qualunque operazione sul membro static
nel corpo del costruttore verrebbe eseguita ogni volta che si istanzia la classe,
una inizializzazione eseguita tramite costruttore verrebbe quindi ripetuta piu`
volte rendendo inutili i membri statici.
L'inizializzazione di un attributo static va eseguita successivamente
alla sua dichiarazione ed al di fuori della dichiarazione di classe:
class MyClass {
public:
MyClass();
/* ... */
private:
static int Counter;
char * String;
/* ... */
};
int MyClass::Counter = 0;
Successivamente l'accesso a un attributo static avviene come se
fosse un normale attributo, in particolare l'idea guida dell'esempio era quella
di contare le istanze di classe MyClass esistenti in un certo momento;
i costruttori e il distruttore sarebbero stati quindi piu` o meno cosi`:
MyClass::MyClass() : /* inizializzazione
membri */
/* non static */
{
++Counter; //
Ok, non e` una inizializzazione
/* ... */
}
MyClass::~MyClass() {
--Counter; //
Ok!
/* ... */
}
Oltre ad attributi static e` possibile avere anche metodi static ;
la keyword static in questo caso vincola il metodo ad accedere
solo agli attributi statici della classe, un accesso ad un attributo non static
costituisce un errore:
class MyClass {
public:
static int GetCounterValue();
/* ... */
private:
static int Counter = 0;
/* ... */
};
int MyClass::GetCounterValue() {
return Counter;
}
Si noti che nella definizione della funzione membro statica la keyword static
non e` stata ripetuta, essa e` necessaria solo nella dichiarazione (anche in
caso di definizione inline ). Ci si puo` chiedere quale motivo ci
possa essere per dichiarare un metodo static , ci sono essenzialmente
tre giustificazioni:
- maggiore controllo su possibili fonti di errore: dichiarando un metodo
static ,
chiediamo al compilatore di accertarsi che il metodo non acceda ad altre categorie
di attributi;
- minor overhead di chiamata: i metodi non
static per sapere
a quale oggetto devono riferire, ricevono dal compilatore un puntatore all'istanza
di classe per la quale il metodo e` stato chiamato; i metodi static
per loro natura non hanno bisogno di tale parametro e quindi non richiedono
tale overhead;
- i metodi
static oltre a poter essere chiamati come un normale
metodo, associandoli ad un oggetto (con la notazione del punto), possono essere
chiamati come una normale funzione senza necessita` di associarli ad una particolrare
istanza, ricorrendo al risolutore di scope come nel seguente esempio:
MyClass Obj;
int Var1 = Obj.GetCounterValue(); //
Ok!
int Var2 = MyClass::GetCounterValue(); // Ok!
Non e` possibile dichiarare static un costruttore o un distruttore.
|