/* Oltre ai metodi, possiamo sovrapporre (overload) anche i costruttori.
 * Supponiamo di voler rendere facoltativi i parametri del costruttore della
 * classe animale:
 *
 * class animale {	   // Definisco la classe animale
 *     ...
 *  public:		 // La parte che segue e' PUBLIC (visibile da tutti)
 *     animale(void);                  // Costruttore: nessun parametro
 *     animale(int zamp);              // Costruttore: 1 par.: int zamp
 *     animale(int zamp, float lungh); // Costruttore: 2 par.: zamp, lung
 *     ~animale(void);                 // Distruttore
 *     ...
 *  };
 *
 * // Ecco il costruttore senza parametri
 *
 * animale::animale(void)
 * {
 *   lunghezza = 0;
 *   numerozampe = 0;
 * }
 *
 * // Ecco il costruttore con 1 parametro: int zamp
 *
 * animale::animale(int zamp)
 * {
 *   lunghezza = 0
 *   numerozampe = zamp;                 // Il num. zampe lo metto subito
 * }
 *
 * // Ecco il costruttore con 2 parametri: int zamp, float lung
 *
 * animale::animale(int zamp, float lung)
 * {
 *   lunghezza = lung;
 *   numerozampe = zamp;
 * }
 *
 * Ecco infine le possibili dichiarazioni:
 *
 * animale cane();
 * animale cane(4);	       // Definisco subito che ha 4 zampe
 * animale cane(4,40.5)        // Definisco subito 4 zampe e lungh. 40.5 cm
 *
 * Questo rende piu' flessibile l'inizializzazione del nostro oggetto.
 * Dato che questa e' solo una applicazione del polimorfismo ai costruttori,
 * niente di veramente nuovo, nel listato e' sfruttata una nuova possibilita'
 * permessa dal C++: la dichiarazione "al volo" di variabili all'interno di
 * un blocco, anziche' solo al suo inizio. Cio' e' illegale in C.
 * Un momento! Gli oggetti (classi), allora, non possono essere dichiarati
 * in un qualsiasi punto del listato, anziche' solo all'inizio?
 * Si! Basta chiamare i costruttori dove piu' ci pare.. o meglio al momento
 * che l'oggetto ci servira'. Questo permette di assegnare all'oggetto
 * (tramite il costruttore con parametri) dei valori che sappiamo solo in
 * un certo punto del listato, e non all'inizio.
 * Per esempio, possiamo creare l'oggetto animale quando sappiamo il numero
 * delle sue zampe, e non all'inizio, quando non lo sappiamo e non possiamo
 * fare altro che inizializzare tutto a zero, aspettando che il valore
 * venga immesso dal metodo mettizampe().
 * In questo listato quindi "mixeremo" e inizializzeremo dinamicamente sia
 * le variabili che le classi, sfruttando la nuova liberta' permessa dal C++.
 */

#include     // 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)
    animale(void);                  // Costruttore: nessun parametro
    animale(int zamp);              // Costruttore: 1 par.: int zamp
    animale(int zamp, float lungh); // Costruttore: 2 par.: zamp, lung
    ~animale(void);                 // Distruttore
    void mettilungh(float i);       // I prototipi dei metodi della
    void mettizampe(int l);         // nostra classe.
    float leggilungh(void);
    int leggizampe(void);
 };


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

// Ecco il costruttore senza parametri

 animale::animale(void)
 {
   lunghezza = 0;
   numerozampe = 0;
 }

// Ecco il costruttore con 1 parametro: int zamp

 animale::animale(int zamp)
 {
   lunghezza = 0;
   numerozampe = zamp;           // Il num. zampe lo metto subito
 }

 // Ecco il costruttore con 2 parametri: int zamp, float lung

 animale::animale(int zamp, float lung)
 {
   lunghezza = lung;
   numerozampe = zamp;
 }

 // Ecco il distruttore

animale::~animale(void)
{
   cout << "animale distrutto\n";
}

/*-------------------------------------------------------------------------*
 * 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)
{

// Da notare che iniziamo il programma senza aver dichiarato ne' classi,
// ne' variabili!! Chiediamo all'utente di darci le informazioni.

  cout << "Num. zampe cane 1? ";    // Stampa la frase.

// Oooops! ci serve la variabile temp2! No prob., si puo' dichiarare ora.

  int temp2;	// Variabile temporanea che usiamo per il num. zampe. Da
		// notare che la abbiamo definita dopo un'istruzione, e
		// non all'inizio. Questo e' illegale in C, ma legale in C++

  cin >> temp2;    		    // Legge il valore.

// 2*Ooops! E l'oggetto? dichiariamone uno al volo, vah...

  animale cane1;      // Istanzio cane1, senza passare parametri al costr.

  cane1.mettizampe(temp2);         // Passa a mettizampe la variabile temp2
  cout << "Lunghezza cane 1? ";    // Stampa la frase come un printf()
  float temp;                      // Var. temporanea per la lunghezza.
  cin >> temp;                     // Legge il valore come scanf()
  cane1.mettilungh(temp);          // Passa a mettilungh la variabile temp

// Veniamo al secondo oggetto. Le variabili temp e temp2 ormai ci sono gia'.
// Qua comunque siamo piu' "furbi", perche' passiamo direttamente al
// costruttore il num. di zampe, evitando di chiamare mettizampe().

  cout << "Num. zampe cane 2? ";    // Stampa la frase come un printf()
  cin >> temp2;    		    // Legge il valore come scanf()
  cout << "Lunghezza cane 2? ";   // Stampa la frase come un printf()
  cin >> temp;                      // Legge il valore come scanf()
  animale cane2(temp2);	// Istanzio cane2, passando al cost. il num. zampe
  cane2.mettilungh(temp);           // Passa a mettilungh la la lunghezza.

// Il millepiedi lo definiamo in un sol colpo usando il costruttore con 2
// parametri, definito prima sovrapponendolo (overload) agli altri 2.

 animale millepiedi(1000,3);   // Istanzio millepiedi, passando il num.
			       // zampe e la lunghezza al costruttore.

// Ora visualiziamo 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
}

/* A questo punto si potrebbero "overloadare" anche i metodi, permettendo
 * di inserire altri dati, facoltativamente... se volete fatelo voi.
 * Per quanto riguarda la nuova dichiarazione delle variabili, possibile
 * anche nel punto del listato dove sono utilizzate, e' evidente lo spirito
 * Object Oriented dell'incapsulation di codice e' dati.
 * Inoltre cio' rende possibile l'inizializzazione dinamica, ossia e'
 * possibile assegnare alla variabile che si crea il risultato di una
 * espressione calcolata precedentemente, magari diversa ogni volta:
 *
 * cout << "Lunghezza di 2 Pippi? ";  // Stampa la frase come un printf()
 * cin >> temp;    		      // Legge il valore come scanf()
 * int pippo = temp/2;	      // Creo un int e lo inizializzo dinamicamente
 *
 * La variabile pippo e' creata e inizializzata con un valore diverso per
 * ogni esecuzione del programma (dipende da cosa scrive l'utente).
 * Lo stesso vale per i costruttori parametrici delle classi.
 */