Per definire una classe in C++ utilizziamo la parola riservata class. Essa ci permette di definire l'interfaccia della classe, ovvero le proprietà e i metodi che gli oggetti metteranno a disposizione (esporranno) all'esterno.
Oltre a ciò nel blocco che segue class
dichiariamo anche gli elementi protetti e privati dei nostri oggetti.
Subito dopo class
indichiamo il nome della classe (ovvero il nome del tipo) e procediamo alla definizione della sua struttura.
Vediamo un esempio in cui definiamo una classe e indichiamo con i commenti una possibile organizzazione degli elementi:
class tipo
{
public:
/*
var1;
var2;
var3;
funzione membro 1
funzione membro 2
*/
protected:
/*
var4;
funzione membro 3;
*/
private:
/*
var5;
funzione membro 4;
funzione membro 5;
*/
};
Potremmo scrivere la definizione dell'interfaccia e l'implementazione dei metodi direttamente nello stesso file, ma è buona norma di inserire la definizione di una classe (l'interfaccia) in un file detto di header (intestazione, con estensione .h
) e le implementazioni dei metodi della classe in file con estensione .cpp
.
Vediamo un esempio di una semplice classe C++
// Semplice esempio di una classe C++
class Cliente
{
public:
char nome[20];
char cognome[20];
char indirizzo[30];
void inserisci_nome( );
void inserisci_cognome( );
void inserisci_indirizzo( );
};
In questa classe abbiamo definito sia gli attributi, sia le funzioni membro come public
, ovvero accessibili dall'esterno e in ogni punto del programma.
Salviamo questa definizione di interfaccia in un file chiamato cliente.h
e creiamo un nuovo file, che chiamiamo cliente.cpp
, in cui scriviamo l'implementazione dei metodi.
Il file cliente.cpp
potrebbe essere fatto così:
#include <iostream.h>
include "cliente.h"
void Cliente::inserisci_nome( )
{
cout << Inserire il nome del dipendente: ";
cin >> nome;
cout << endl;
}
void Cliente::inserisci_cognome( )
{
cout << Inserire il cognome del dipendente: ";
cin >> cognome;
cout << endl;
}
void Cliente::inserisci_indirizzo( )
{
cout << Inserire l' indirizzo del dipendente: ";
cin >> indirizzo;
cin >> get(newline); //elimina il Carriage Return
}
main()
{
Cliente cliente;
cliente.inserisci_nome( );
cliente.inserisci_cognome( );
cliente.inserisci_indirizzo( );
cout << "Il nome del cliente inserito è: " << cliente.nome << endl;
cout << "Il cognome del cliente inserito è: " << cliente.cognome << endl;
cout << "L' indirizzo del cliente inserito è: " << cliente.indirizzo << endl;
}
Avrete certamente notato la particolare sintassi utilizzata nel file Cliente.cpp
relativamente alla implementazione delle funzioni membro. Essa segue la regola:
tipo_restituito nome_classe::nome_metodo( eventuali parametri)
dove l'operatore :: viene denominato operatore di scope.
Inoltre, come si può vedere facilmente dalla funzione main, ogni volta che si fa riferimento ad un attributo o ad una funzione membro di un oggetto, va utilizzata la sintassi:
oggetto.attributo;
oggetto.metodo();
Puntatori e operatore new
Supponiamo ora di creare lo stesso programma, ma cambiando il main nel seguente modo:
main()
{
Cliente* cliente;
cliente = new Cliente( );
cliente->inserisci_nome( );
cliente->inserisci_cognome( );
cliente->inserisci_indirizzo( );
cout << "Il nome del cliente inserito è: " << cliente->nome << endl;
cout << "Il cognome del cliente inserito è: " << cliente->cognome << endl;
cout << "L' indirizzo del cliente inserito è: " << cliente->indirizzo << endl;
delete cliente;
}
In questo caso nella funzione main definiamo un oggetto della classe Cliente
servendoci però di un puntatore. In questo caso entrano in gioco due keyword fondamentali
- new, che alloca la memoria necessaria all'instanziazione dell'oggetto e ne ritorna la relativa locazione di memoria.
- delete, che servirà per liberare la memoria utilizzata per l'oggetto, una volta che non ci servirà più
Avendo a che fare con un puntatore all'oggetto, cambierà anche la modalità con la quale facciamo riferimento ai suoi metodi o ai suoi attributi (o proprietà). In questo caso infatti, invece del punto utilizziuamo l'operatore freccia (->
):
oggetto->attributo;
oggetto->metodo();
I modificatori: private, public, protected
Se non specifichiamo nessun modificatore per un metodo o per un attributo all'interno di una classe, questi si intendono automaticamente private
. Ad esempio:
class Cliente
{
char nome[20];
char cognome[20];
char indirizzo[30];
public:
void inserisci_nome( );
void inserisci_cognome( );
void inserisci_indirizzo( );
};
gli identificatori: nome
, cognome
e indirizzo
, che si trovano subito dopo la dichiarazione del nome della classe, saranno attributi private
e, come tali, utilizzabili soltanto all'interno della classe stessa.
Dobbiamo quindi fare attenzione e ricordare di inserire i modificatori di visibilità per metodi e attributi di una classe. Per non trovarci in una situazione simile a questa:
class Cliente
{
char nome[20];
char cognome[20];
char indirizzo[30];
void inserisci_nome( );
void inserisci_cognome( );
void inserisci_indirizzo( );
};
In questo caso infatti la classe Cliente
sarebbe assolutamente inutilizzabile dall'esterno visto che tutti i suoi dati e metodi sono privati (non abbiamo specificato alcun modificatore di accesso). Per fortuna questo sarebbe chiaramente un errore e anche il compilatore ce lo farebbe notare.