prof. Nunzio Brugaletta
C++: programmazione e oggetti

EnneBi - Programmazione
Avanti - Indietro - Inizio

Estensione delle strutture: le classi

I membri di una struttura possono anche essere funzioni oltre che dati. Per una biblioteca che effettua operazioni di prestito ai soci, un libro, per esempio, non è solo un insieme di attributi ma anche una cosa che può essere prestata:

namespace biblioteca{
  struct libro {                                                          
    string titolo;
    string autore;
    string editore;
    float prezzo;
    bool presente;

    bool prestitoOk()	/*1*/
    {    	             
      bool esito=false;
      if (presente){
        presente   = false;  	/*2*/ 
        esito = true;
      };
      return esito;
    };
  };
}

Nella 1 viene definita la funzione per effettuare il prestito di un libro: tale funzione setta a false il valore del membro presente e ritorna un valore logico sul risultato dell’operazione effettuata (se il libro è già stato prestato l’operazione non può avere luogo). La funzione è inserita nella struttura per intendere che è una proprietà distintiva del libro, così come il titolo o l’autore. L'accesso al membro presente, nella 2, non necessita dell'operatore :: perché si trova nella stesso namespace così come dell'operatore punto, poiché avviene dentro la struttura stessa.

...
biblioteca::libro lib1;	/*1*/
...
cout << "Inserire titolo :";
getline(cin,lib1.titolo);	/*2*/

cout << "Titolo :" << lib1.titolo << endl;
if(!lib1.prestitoOk())	/*3*/
  cout << "Libro gia\' prestato" << endl;
else
  cout << "Prestito effettuato" << endl;
...

Il frammento di programma riportato, dopo aver dichiarato nella 1 una variabile di tipo libro, chiede il titolo di un libro e ne effettua il prestito. Allo stesso modo come nella 2 si ha accesso alla variabile membro titolo di lib1, nella 3 si ha accesso alla funzione membro prestitoOk riferita sempre a lib1. Detta funzione modifica il valore presente di lib1.

Le classi sono uno degli elementi fondamentali della programmazione orientata agli oggetti (OOP). Una classe è un tipo di dato definito dall’utente che ha un proprio insieme di dati e di funzioni (Abstract Data Type).

// esempio non funzionante !!

class libro {  
  string titolo;
  string autore;
  string editore;
  float prezzo;
  bool presente;

  bool prestitoOk()
  {
    bool esito=false;
    if (presente){
      presente   = false;
      esito = true;
    };
    return esito;
  };
};

In questo modo viene definita la classe libro. Un tipo con attributi e comportamenti (le funzioni definite nella classe).

La definizione di libro, tranne che per la sostituzione della parola chiave struct con la parola chiave class, sembra identica a quella adottata precedentemente, solo che ora, come d’altra parte messo in evidenza dalla riga di commento, c’è una differenza sostanziale: il compilatore se si tenta di accedere ad un attributo dell’oggetto, fornisce un errore che evidenzia la non visibilità dello stesso. Ciò è dovuto alle regole di visibilità dei vari elementi: se, infatti, non si specifica altrimenti, la visibilità è limitata solo all’interno della classe, per esempio la funzione prestitoOk può accedere a presente.

In generale in una classe possono essere specificati tre livelli di visibilità:

class libro {
public:
  ...
protected:
  ...
private:
  ...
};

Nella sezione public si specificano i membri accessibili agli altri membri della classe, alle istanze della classe e alle classi discendenti (quelle che si definiscono a partire da libro e che ne ereditano le proprietà).

Nella sezione protected si specificano i membri accessibili agli elementi della classe, alle classi discendenti ma non alle istanze della classe. È la definizione assunta per default ed è quindi questo il motivo perché nell’esempio proposto non erano visibili i vari membri. Nelle strutture invece la definizione di default è public ed è questo che ha garantito l'accesso ai membri negli esempi riportati in precedenza.

Nella sezione private si specificano i membri che devono essere accessibili solamente agli altri membri della stessa classe.

Le sezioni possono essere disposte in modo qualsiasi, figurare più volte nella definizione della classe e non è obbligatorio inserirle tutte.

La possibilità di definire diversi livelli di mascheramento dell’informazione (data hiding) è una delle caratteristiche fondamentali della programmazione ad oggetti. Aiuta, infatti, a creare una interfaccia della classe che, nascondendo l’implementazione, mostra l’oggetto definito in maniera da evidenziarne le proprietà e i comportamenti. Mettere assieme in una classe le proprietà e le funzioni è un’altra delle caratteristiche fondamentali della OOP: l’incapsulamento. In questo modo ogni oggetto della classe non ha solo caratteristiche ma anche comportamenti esattamente come nella realtà: se si gestisce una biblioteca, un libro, non è solo un oggetto che ha, per esempio, il titolo “Pinocchio” ma è anche oggetto di prestito e restituzione. Una classe contiene i dati e tutto il necessario per usare i dati; il programma che usa la classe non ha bisogno di sapere com’è fatta.

Nella OOP, in ragione del mascheramento dei dati, questi normalmente vengono dichiarati nella sezione protected (scelta effettuata in questi appunti per il motivo di rendere disponibili i dati alle classi discendenti), o nella sezione private, e si accede ad essi utilizzando i metodi presenti nella parte public. Questa, si può dire, è una regola generale: è l’interfaccia della classe che mette a disposizione gli strumenti per accedere ai dati. In tal modo può essere, per vari motivi, modificata la struttura interna dei dati della classe senza che cambi l’uso degli oggetti della classe.



Avanti - Indietro - Inizio

http://ennebi.solira.org
ennebi@solira.org