uni
Le classi vengono usate per definire strutture dati personalizzate ma rispetto agli Struct, i cui membri sono pubblici, i suoi membri sono privati di default.
class nomeClasse {
private:
//dati membro
public:
//dati membro
//funzioni membro
};
Oltre a private: e public: vi è uno stato intermedio: protected:
un membro protetto è come un membro private solo che è anche accessibile alle classi derivate e alle funzioni amiche.
Inoltre la visibilità di un membro viene anche cambiata dalla parola chiave static Static.
Le funzioni membro oltre che essere dichiarate all’interno della classe, possono essere dichiarate al di fuori di essa tramite l’operatore di risoluzione di visibilità Altri operatori.
Un oggetto appartenente ad una classe si chiama oggetto classe o istanza della classe.
Una classe individua un campo di visibilità.
Se all’interno di una classe viene utilizzato un identificatore dichiarato anche all’esterno della classe, la dichiarazione in classe nasconde quella esterna.
All’esterno della classe si può accedere ai membri interni ad una classe tramite l’operatore di risoluzione di visibilità applicato al nome della classe se questi membri sono:
1. funzione membro
2. un tipo se dichiarato public
3. statici
Quindi l’operatore non può essere applicato a campi dati non statici.
Ad oggetti classe costanti possono solo essere applicate funzioni membro costanti: tipo identificatore() const;
Puntatore this
Nel corpo di una funzione membro,ci si riferisce alla corrente istanza della classe a cui la funzione viene applicata tramite il puntatore predefinito this.
Classe funzione(parametri) {
corpo
return *this;
}
//oppure anche
Classe& funzione(ecc) {
return *this;
}
Classi annidate
Nella dichiarazione di una classe si può dichiarare un’altra classe, in questo caso per accedere ai membri della classe annidata è necessario utilizzare due operatori di risoluzione di visibilità. Comunque nessuna delle due classi ha diritto di accedere ai membri privati dell’altra.
Costruttore
Un costruttore è una funzione membro il cui nome è il nome della classe. Se definito viene chiamato tutte le volte che viene invocata una istanza di classe, subito dopo essere stata riservata la memoria per i campi dati.
È possibile definire più costruttori, uno che ammette argomenti ed uno di default, che viene chiamato senza argomenti.
Un altro modo per fare ciò è semplicemente fornire degli argomenti di default: Classe(tipo nome = valore, tipo altronome = altrovalore);
.
Questi due metodi non possono essere utilizzati contemporaneamente.
I costruttori vengono chiamati:
1. per oggetti statici all’inizio del programma
2. per oggetti automatici quando viene incontrata la definizione
3. per oggetti dinamici quando viene incontrato l’operatore new. Memoria Dinamica
4. per oggetti membro di altri oggetti, quando questi ultimi vengono costruiti.
Un campo dati con l’attributo const viene inizializzato nel momento in cui viene definito il primo oggetto appartenente alla classe.
Lista di inizializzazione
L’inizializzazione dei membri può essere fatta tramite una lista di inizializzazione del costruttore: Classe(tipo identificatore, tipo identificatore) : membro(argomento), membro(argomento) {corpo}
In una classe si possono dichiarati riferimenti non inizializzati purché siano inizializzati con la lista di inizializzazione.
Se qualche classe secondaria prevede argomenti formali allora deve essere definito un costruttore anche per la classe principale e questo deve possedere una lista di inizializzazione.
Quindi ricapitolando una lista si rende necessario per:
1. costanti
2. classi secondarie
3. riferimenti
Costruttore di Copia
Il costruttore di copia predefinito è una funzione che agisce fra due oggetti della stessa classe effettuando una ricopiatura membro a membro dei campi dati.
Viene applicato:
1. quando un oggetto classe viene inizializzato con un altro oggetto della stessa classe
2. quando un oggetto classe viene passato come argomento ad una funzione
3. quando una funzione restituisce (return) come valore un oggetto classe
Deve essere ridefinito per le classe che utilizzano memoria libera.
Se non si ridefinisce l’operatore di copia e non si vuole che venga nemmeno utilizzato quello standard, occorre inserire la sua dichiarazione nella parte privata. In questo caso però non si possono avere funzioni che abbiamo come argomenti un oggetto classe o come risultato valore del tipo della classe.
Distruttore
Questo è una funzione membro invocata automaticamente quando un oggetto termina il suo tempo di vita. Un distruttore non ha argomenti. Un distruttore è obbligatorio quando il costruttore alloca memoria nello heap Memoria Dinamica.
I distruttori vengono chiamati:
1. per oggetti statici al termine del programma
2. per oggetti automatici all’uscita dal blocco in cui sono definiti
3. per oggetti dinamici quando viene incontrato l’operatore delete
4. per oggetti membro di altri oggetti quando questi ultimi vengono distrutti.
Gli oggetti con stesso tempo di vita vengono distrutti nell’ordine inverso a quello in cui sono definiti.
Funzioni friend
Una funzione è friend di una classe se una sua dichiarazione preceduta dalla parola chiave friend viene inserita nella dichiarazione di tale classe. Questa può ora accedere ai campi pubblici e privati della classe tramite i selettori di membro.
Overloading di Operatori
Può capitare che servano essere definite alcune operazioni su tipi di dato astratto.
Si rende quindi necessaria la ridefinizione di questi operatori.
L’overloading di un operatore ha la forma di una definizione di una funzione, il cui identificatore è costituito dalla parola chiave operator seguita dall’operatore che si vuole ridefinire.
Tutti gli operatori di assegnamento restituiscono un riferimento all’oggetto.
ATTENZIONE: le versioni predefinite degli operatori assicurano alcune equivalenze, per esempio ++x
= x += 1
. Quando si ridefinisce un operatore le equivalenze non valgono automaticamente.
ATTENZIONE: se si vuole che il primo operando possa essere qualsivoglia e non l’oggetto a cui si applica l’operatore (ovvero simmetria tra gli operatori) si devono utilizzare funzioni globali (quindi devono essere friend).
Operatore di assegnamento:
L’operatore predefinito esegue una copia membro a membro ma va ridefinito se vi sono allocazioni dinamiche.
L’operatore di assegnamento deve deallocare la memoria dinamica dell’operando di sinistra e riallocarla uguale all’operando di destra.
Problema dell’Aliasing: evitare di sprecare operazioni se i due operandi sono già uguali.
Ottimizzare se le due memorie dinamiche hanno già la stessa dimensione.
Si possono ridefinire tutti gli operatori tranne:
1. operatore di risoluzione di visibilità ::
2. operatore di selezione di membro .
3. operatore di selezione di membro tramite puntatore a membro .*