/* Ora vedremo di creare una classe piu' completa, che abbia anche delle
 * funzioni (metodi), oltre ai dati.
 * Occorre aver chiaro che gli oggetti si mandano "messaggi" proprio perche'
 * i loro dati gli appartengono, sono privati, e non possono essere "toccati"
 * direttamente dagli oggetti esterni.
 * Questo per il concetto di "information hiding" (nascondere i dati) e
 * "incapsulation" (unire dati e funzioni in un unica "capsula").
 * I dati locali, a cui non si puo' accedere direttamente da un'altro
 * oggetto, sono modificabili solo tramite gli opportuni metodi, i quali
 * saranno "pubblici". La regola OOP vuole che i dati di un oggetto possano
 * essere consultati SOLO tramite l'apposito metodo.
 * E' possibile definire variabili come globali, ma sconsigliato.
 * Ecco dunque l'iter che si segue per operare su una variabile privata di
 * un oggetto: si spedisce il MESSAGGIO relativo a cio' che si chiede,
 * l'oggetto invoca il METODO che corrisponde a quel messaggio, il quale
 * cambia il suo stato interno (accedendo alla variabile, ad esempio), ed
 * eventualmente restituisce dei dati, se richiesti.
 * Vediamo dunque come si definiscono i metodi in una classe. Si devono
 * innanzitutto dichiarare i loro prototipi nella parte pubblica:
 *
 * class animale {	   // Definisco la classe animale
 *     float lunghezza;    // Questa parte e' PRIVATE di default
 *     int numerozampe;
 *  public:		// La parte che segue e' PUBLIC (visibile da tutti)
 *     void mettilungh(float i);  // Questi sono i prototipi delle funzioni
 *     void mettizampe(int l);    // (o metodi) della nostra classe.
 *     float leggilungh(void);
 *     int leggizampe(void);
 *  };
 *
 * I prototipi sono analoghi a quelli normali: si indicano i parametri
 * in entrata e uscita. Il codice effettivo delle funzioni si dichiara in
 * questo modo:
 *
 * void animale::mettilungh(float i)
 * {
 *   lunghezza = i;   // Scrive il valore nella variabile privata "lunghezza".
 * }
 *
 * L'unica differenza rispetto alla definizione delle normali funzioni, e'
 * che occorre aggiungere l'appartenenza ad una classe, precedendo il nome
 * della funzione con "nomeclasse::". Il segno :: e' detto operatore di
 * determinazione di visibilita' (scope resolution operator), e in questo
 * caso dichiara che il metodo mettilungh e' nel campo di visibilita' della
 * classe animale. In questo modo, e' possibile definire 2 funzioni con lo
 * stesso nome, ma appartenenti a diverse classi, ad esempio:
 *
 * void automezzo::numeroruote(int i) { ... }
 * void ciclo::numeroruote(int i) { ... }
 *
 * Ora instanziamo un automezzo e un ciclo:
 *
 * automezzo ferrari;
 * ciclo graziella;
 *
 * E accediamo alle 2 funzioni numeroruote, che non hanno niente a che
 * vedere tra loro:
 *
 * ferrari.numeroruote(4);
 * graziella.numeroruote(2);
 *
 * Vedremo dopo come, grazie al polimorfismo, potremo dare lo stesso nome
 * a metodi diversi (con diversi parametri I/O) appartenenti anche alla
 * stessa classe.
 * Da notare che se un metodo di una classe e' chiamato da un metodo della
 * stessa classe, non necessita di essere preceduto dall'operatore punto:
 * dall'esterno della classe si usa ferrari.numeroruote(), dal suo interno
 * si usa numeroruote() semplicemente. In questo sorgente comunque non ci
 * sono chiamate tra funzioni all'interno della stessa classe.
 * Vediamo quindi l'uso di una classe con dati privati e metodi pubblici.
 */

#include <iostream.h>    // Header necessario per usare CIN e COUT
			 // Questo e' un commento C++ ad una sola linea

class animale {	        // Definisco la classe animale
    float lunghezza;    // Questa parte e' PRIVATE di default
    int numerozampe;
 public:		// La parte che segue e' PUBLIC (visibile da tutti)
    void mettilungh(float i);  // Questi sono i prototipi delle funzioni
    void mettizampe(int l);    // (o metodi) della nostra classe.
    float leggilungh(void);
    int leggizampe(void);
 };


// Ora scriviamo le funzioni (metodi) della classe animale:

/*-------------------------------------------------------------------------* 
 * mettilungh: definisce la lunghezza dell'animale.
 *             parametri: in entrata la lunghezza in formato float.
 *-------------------------------------------------------------------------*/

void animale::mettilungh(float i)
{
  lunghezza = i;   // Scrive il valore nella variabile privata "lunghezza".
}

/*-------------------------------------------------------------------------*
 * mettizampe: definisce il numero di zampe dell'animale.
 *             parametri: in entrata il num. di zampe in formato int.
 *-------------------------------------------------------------------------*/

void animale::mettizampe(int l)
{
  numerozampe = l; // Scrive il valore nella variabile privata "numerozampe".
}

/*-------------------------------------------------------------------------*
 * leggilungh: legge e restituisce la lunghezza dell'animale.
 *             parametri: in uscita la lunghezza in formato float.
 *-------------------------------------------------------------------------*/

float animale::leggilungh(void)
{
  return lunghezza;
}

/*-------------------------------------------------------------------------*
 * leggizampe: legge e restituisce il num. di zampe dell'animale.
 *             parametri: in uscita il num. di zampe in formato int.
 *-------------------------------------------------------------------------*/

int animale::leggizampe(void)
{
  return numerozampe;
}

///////////////////////////////////////////////////////////////////////////
//                            Il main...
///////////////////////////////////////////////////////////////////////////

int main(void)
{

 float temp;	// Variabile temporanea che usiamo per le lunghezze.
 int temp2;	// Idem, per il num. zampe.

// Ora possiamo dichiarare alcuni oggetti di tipo animale e usarli:

 animale cane1,cane2,millepiedi;	// ecco che istanzio 3 animali...
					// ossia creo degli esemplari dalla
					// classe "astratta".

// Non possiamo accedere direttamente ai dati come abbiamo fatto prima,
// con cane1.numerozampe = 4; eccetera. Ora dobbiamo mandare un messaggio
// all'oggetto chiedendogli di modificare la sua variabile.

 cane1.mettizampe(4);		// Chiamiamo il metodo mettizampe() di cane1
 cane2.mettizampe(4);           // e quello di cane2, per variare le loro
 millepiedi.mettizampe(1000);	// variabili private. Stesso per millepiedi

// Gli altri parametri li chiediamo all'utente.

  cout << "\nLunghezza cane 1? ";   // Stampa la frase come un printf()
  cin >> temp;                      // Legge il valore come scanf()
  cane1.mettilungh(temp);           // Passa a mettilungh la variabile temp
  cout << "Lunghezza cane 2? ";	    // Stampa la frase come un printf()
  cin >> temp;    		    // Legge il valore come scanf()
  cane2.mettilungh(temp);	    // Passa a mettilungh la variabile temp
  cout << "Lunghezza millepiedi? "; // Stampa la frase come un printf()
  cin >> temp;    		    // Legge il valore come scanf()
  millepiedi.mettilungh(temp);	    // Passa a mettilungh la variabile temp
  cout << "Num. esatto piedi del millepiedi? ";  // Stampa la frase.
  cin >> temp2;    		                 // Legge il valore.
  millepiedi.mettizampe(temp2);     // Passa a mettizampe la variabile temp2

// Ora visualizziamo lo stato degli animali, usando i loro metodi di lettura.

  cout << "\nStato del cane1: zampe = " << cane1.leggizampe();
  cout << ", lunghezza = " << cane1.leggilungh();
  cout << "\nStato del cane2: zampe = " << cane2.leggizampe();
  cout << ", lunghezza = " << cane2.leggilungh();
  cout << "\nStato del millepiedi: zampe = " << millepiedi.leggizampe();
  cout << ", lunghezza = " << millepiedi.leggilungh() << "\n";

  return 0;	// main() restituisce 0
}

/* Avrete notato come ogni metodo (funzione) sia preceduto da un campo di
 * commento in cui si definisce chiaramente il suo scopo, e in particolare
 * i parametri in entrata ed uscita. Il programma funziona anche senza
 * commenti, ma con essi diventa comprensibile anche ad altri, e a noi,
 * nel caso si rispolverasse dopo anni, una volta dimenticato tutto.
 * Purtroppo molti non commentano assolutamente i listati, e cio' lo credo
 * un errore grave quanto quelli che causano malfunzionamenti.
 * In questo esempio abbiamo fatto un passo avanti nella OOP, ma si puo'
 * benissimo fare una cosa simile in C standard, accedendo alle variabili
 * di strutture solo tramite funzioni, e non direttamente. Fino ad un
 * certo punto, infatti, si puo' programmare ad oggetti anche in C
 * standard, se si seguono le regole della buona programmazione, ossia
 * dividendo il programma in funzioni, e accedendo ai dati solamente dalle
 * funzioni ad essi relative, senza mai accederci dal main() o da funzioni
 * distanti "tipologicamente".
*/