prof. Nunzio Brugaletta
C++: programmazione e oggetti

EnneBi - Programmazione
Avanti - Indietro - Inizio

Progetto e uso di una classe step by step. Costruttori

Applicare la OOP alla risoluzione di un determinato problema vuol dire innanzi tutto individuare le classi interessate (quali sono i dati) e i metodi che devono avere (che operazioni si richiedono sui dati). Utilizzando una similitudine si può pensare al problema da risolvere come ad una piece teatrale: ci sono dei personaggi, ognuno con le proprie caratteristiche e comportamenti, che interagiscono fra loro. Il problema da risolvere è la piece da recitare, i personaggi (tratteggiati ognuno dalle proprie caratteristiche) sono le classi e sono interpretati da attori (le istanze della classe: gli oggetti) che, per il fatto di interpretare determinati personaggi, sanno cosa fare e come comportarsi perché ciò fa parte dell'interpretazione di quel determinato personaggio.

Viene ora riproposto, come primo esempio, il programma per conoscere il totale della fattura di cui siano date le righe che la compongono, ognuna individuata da una determinata quantità e dal prezzo unitario dell'oggetto venduto. Questa volta il problema viene affrontato utilizzando il paradigma OOP.

Le domande da porsi per affrontare il problema sono due: quali sono i dati coinvolti, che tipo di operazioni sono richieste per quei dati. Nel problema proposto si possono identificare due entità:

class riga{ 
public: 
  void nuova(int, float); 
  float totriga(); 
  friend ostream& operator<<(ostream&, const riga&); 	/*1*/
protected: 
  int qv; 
  float pu; 
}; 

ostream& operator<<(ostream& output, const riga& r)	/*2*/
{ 
  output << "Quantita\' venduta: " << r.qv 
         << " Prezzo unitario: " << r.pu << endl; 
  return output; 
}; 

// metodo per inserimento di una nuova riga 

void riga::nuova(int q, float p)	/*3*/
{ 
  qv = q; 
  pu = p; 
}; 

// metodo per il calcolo del totale della riga 

float riga::totriga()	/*3*/
{ 
  float tr; 
  tr = (float) qv*pu; 
  return tr; 
}; 

A questo punto la definizione delle classi, in conseguenza delle richieste del programma da sviluppare, è completa: il codice di ogni classe si inserisce, ognuno, per esempio nel namespace elabfat e si registra in un file. Il file c_fattura contiene la definizione della classe fattura, il file c_riga quello della classe riga. I file saranno inclusi nel sorgente del programma che dovrà utilizzare le classi in esse definite.

Prima di procedere oltre è opportuno rispondere ad una eventuale osservazione sulla mancanza, nella definizione della classe, di implementazione di eventuali altri metodi per elaborazioni diverse che potrebbero essere necessario effettuare. In questi casi, infatti, non è possibile conoscere i dati inseriti che sono conservati in variabili private.

Intanto si può osservare che, per lo sviluppo del programma proposto, non è necessario alcun altro metodo. Inoltre il non prevedere alcun metodo, probabilmente utile per un utilizzo futuro, e in altri contesti, della classe, non toglie generalità; si possono implementare nuovi metodi o, addirittura, modificare quelli esistenti utilizzando l'ereditarietà, così come si tratterà in seguito.

#include <iostream>
#include “c_fattura”	/*1*/
#include “c_riga”	/*1*/
using namespace std;

int main()
{
  int qvend,i;
  float pzunit;
  elabfat::riga r;	/*2*/
  elabfat::fattura f;	/*2*/

  // elaborazione righe fattura

  for(i=1;;i++){	/*3*/	
    cout << "Riga n. " << i << endl;	/*4*/	
    cout << "Quantita\'_venduta prezzo_unitario (0 0 per finire) ";
    cin >> qvend >> pzunit;

    if((qvend<=0) || (pzunit<=0))	/*5*/
      break;	

    r.nuova(qvend,pzunit);	/*6*/
    cout << r;	/*7*/	
    f.aggiorna(r.totriga());	/*8*/	
  };

  // stampa fattura

  cout << f;	/*9*/

  return 0;
}

Essendo semplice e leggibile il programma non è stato suddiviso in funzioni.

Con le 1 si includono nel file le definizioni della classi. Così da poter, nelle 2, dichiarare istanze delle classi. Il nome del file da includere è racchiuso fra doppi apici ad intendere che si trova nella stessa directory dove è registrato anche il file che contiene il programma che lo includerà. Le parentesi angolari, che racchiudono per esempio iostream, stanno invece a significare che il file si trova nella directory standard, dei file include, in cui va a cercare il compilatore.

La struttura 3 è un ciclo senza fine (non c'è infatti alcuna condizione di controllo) da cui si esce (5) se si inserisce un valore negativo o nullo in una delle due variabili: non ha infatti senso una riga di fattura con tali valori. Il ciclo for è utilizzato per poter far visualizzare, nella 4, la numerazione delle righe.

Dopo aver acquisito i dati dall'input, nella 6 si richiama il metodo nuova per la conservazione dei dati e nella 8 si richiama totriga per l'aggiornamento del totale della fattura.

Nelle 7 e 8 si stampano, rispettivamente, una riga della fattura e la fattura stessa per quello che questo significa, ed è definito nella ridefinizione dell'operatore di inserimento per i vari tipi di oggetti.



Avanti - Indietro - Inizio

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