Visualizzazione post con etichetta ereditarietà. Mostra tutti i post
Visualizzazione post con etichetta ereditarietà. Mostra tutti i post

giovedì 27 dicembre 2012

Chiamata e superamento delle Funzioni membro classi Base

Non si viene bloccati su ogni membro funzione delle classi di base ereditati dalle classi derivate così come sono. Ma si possiede l'opzione di una personalizzazione di come vengano ereditate le funzioni membro e come esse lavorino nelle classi derivate. E' possibile superarle attraverso nuove definizioni all'interno delle classi derivate. Si può esplicitare una chiamata alla classe di base da ogni funzione membro della classe derivata.

Presentare il programma Capo superiore

Il programma Capo superiore dimostra la chiamata ed il superamento delle funzioni membro della classe di base in una classe derivata. Il programma crea un nemico che infastidisce il giocatore e lo attacca. In seguito il programma crea un Capo mediante una classe derivata. Anche il Capo infastidisce il giocatore e lo attacca, ma la cosa interessante è che il suo modo di approcciarsi ed attaccare viene modificato rispetto al Nemico (rendendolo più resistente). Questi cambiamenti sono ottenuti mediante il superamento della funzione derivata rispetto alla funzione della classe di base.
//Capo superiore
//dimostra la chiamata ed il superamento delle funzioni membro di base
#include <iostream>
using namespace std;
class Nemico
{
          public: Nemico(int danno = 5): m_Danno(danno){}
                     void Fastidio() const { cout << “Il nemico vuole combatterti.\n”; }
                     void Attacco const
                    { cout << “Attacco infligge” << m_Danno << “ punti danno.\n”;}
         private: int m_Danno;
};
class Capo: public Nemico
{
          public:
                   Capo(int danno= 20): Nemico(danno){} //chiamata al costruttore di base con argomento
                   void Fastidio() const { cout << “Il capo vuole mettere fine alla tua esistenza.\n”; }
                  void Attacco() const
                         { Nemico::Attacco();
                            cout << “Ride di te.\n”; }
};
int main()
{
   cout << “Crea un nemico.\n”;
   Nemico nemico1;
   nemico1.Fastidio();
   nemico1.Attacco();

   cout << “\n Crea un capo. \n”;
   Capo capo1;
   capo1.Fastidio();
   capo1.Attacco();

return 0;
}

domenica 23 dicembre 2012

Controllo accesso sotto Ereditarietà

Quando viene derivata una classe da un'altra è possibile controllare quanto accesso la classe derivata ha sui membri della classe di base. Per la stessa ragione, si vuole fornire sono la quantità di accesso necessario ai membri della classe base, nel resto del programma, che possa servire alla classe derivata. Non è una coincidenza se vengono utilizzati gli stessi modificatori di accesso visti in precedenza (public, private e protected).

Presentare il programma Semplice Capo 2.0

Il programma Semplice Capo 2.0 è un'altra versione del programma visto in precedenza. Ma in questa nuova versione, la quale fornisce gli stessi risultati all'utente, ma il codice è leggermente diverso in quanto sono state messe delle restrizioni sui membri della classe base.
//Semplice Capo 2.0
//Dimostrazione del controllo di accesso con ereditarierà
 #include <iostream>
 using namespace std;
 class Nemico
 {
     public:
               Nemico(): m_Danno(10){}
               void Attacco const
               { cout << “Attacco infligge” << m_Danno << “ punti danno.\n”;}
    protected: int m_Danno;
};
class Capo: public Nemico
{
    public:
              Capo():m_MultiDanno(3){}
              void AttaccoSpeciale() const
             { cout << “Attacco Speciale infligge” << (m_MultiDanno * m_Danno);
               cout << “ punti danno.\n”;}
   private: int m_MultiDanno;
};

int main()
{
   cout << “Crea un nemico.\n”;
   Nemico nemico1;
   nemico1.Attacco();
  
  cout << “\n Crea un capo. \n”;
  Capo capo1;
  capo1.Attacco();
  capo1.AttaccoSpeciale();
return 0;
}

Presentare il programma Semplice Capo

Il programma Semplice Capo dimostra il concetto di ereditarietà. In esso, viene definita una classe di nemici inferiori, Nemico. Da questa classe viene derivata una nuova classe per i Capi più resistenti che il giocatore deve affrontare. Quindi viene istanziato un oggetto Nemico e richiamata la sua funzione membro Attacco(). Di seguito viene istanziato un oggetto Capo, del quale è possibile richiamare la funzione Attacco(), in quanto eredita la funzione membro da Nemico. Infine viene richiamata la funzione membro AttaccoSpeciale() definita solo per la classe Capo. Mentre la classe Nemico non ha accesso a questa funzione in quanto esclusiva del capo.
//Semplice Capo

//Dimostrazione ereditarietà

   #include <iostream>

   using namespace std;

   class Nemico

   {

          public: int m_Danno;

          Nemico(): m_Danno(10){}

          void Attacco const

          { cout << “Attacco infligge” << m_Danno << “ punti danno.\n”;}

   };

 class Capo: public Nemico

 {

          public: int m_MultiDanno;

         Capo():m_MultiDanno(3){}

         void AttaccoSpeciale() const

         { cout << “Attacco Speciale infligge” << (m_MultiDanno * m_Danno);

            cout << “ punti danno.\n”;}

  };

int main()

{

   cout << “Crea un nemico.\n”;

   Nemico nemico1;

   nemico1.Attacco();



   cout << “\n Crea un capo. \n”;

   Capo capo1;

   capo1.Attacco();

   capo1.AttaccoSpeciale();

return 0;

}

sabato 22 dicembre 2012

Ereditarietà e polimorfismo

Le classi sono un esempio perfetto per rappresentare entità nel gioco che hanno attributi e comportamenti. Ma le entità nei giochi sono spesso correlate tra loro. In questi post saranno introdotti i concetti di ereditarietà e polimorfismo, i quali permettono di esprimere tali collegamenti e possono far costruire classi di gioco ancora più semplici ed intuitive. I concetti espressi saranno:
  • Derivare una classe da un'altra
  • Usare i dati membro e funzioni di una classe ereditata
  • maneggiare i membri della classe di base
  • Definire funzioni virtuali per abilitare il polimorfismo
  • Definire funzioni virtuali pure per le classi astratte
  • Suddividere il codice in file multipli

Introdurre l'Ereditarietà

Uno degli elementi chiave della OOP è l'ereditarietà, la quale permette di derivare una classe nuova da una esistente. Quando viene fatto, la nuova classe eredita (ottiene) i dati membro e le funzioni membro della classe esistente. E' come ottenere qualcosa che funziona con un lavoro gratuito della classe esistente. L'ereditarietà è molto utile quando si vuole creare una versione più specializzata di una classe esistente poiché si vogliono solo aggiungere nuovi dati membro e funzioni per estenderla. Un esempio è, immaginiamo di avere la classe Nemico che definisce un avversario nel gioco, la quale ha una funzione membro Attacco() e il dato membro m_Danno. Da questa si vuole ricavare la classe Capo, per un capo dei Nemici. Questo significa che la classe Capo possiede automaticamente una funzione Attacco() e un dato m_Danno senza dover scrivere del codice. Tuttavia per rendere il capo più resistente, viene aggiunta la funzione AttaccoSpeciale() e il membro dati Multi_Danno alla classe Capo. Uno dei maggiori vantaggi dell'ereditarietà è la possiiblità di riutilizzo delle classi già scritte. Il quale si riassume nei benefici:
  • Minore lavoro. Non è necessario definire funzionalità già possedute. Una volta che una classe definisce funzioni di base per le altre classi, il codice non deve essere riscritto di nuovo.
  • Meno errori. Un classe priva di bachi, può essere riutilizzata senza doverne cercare altri nel nuovo codice.
  • Un codice più leggero. Poiché le funzionalità di base delle classi esistono nel programma, non si deve ripercorrere lo stesso codice più volte, rendendo la scrittura del programma più leggera e facile da comprendere.
Molte entità nei giochi chiamano a gran voce l'ereditarietà delle classi. Che si tratti di uno squadrone di nemici, o una serie di veicoli comandati dall'utente, o un inventario di armi che il giocatore possiede. Tutti possono essere definiti come un gruppo di elementi connessi tra loro, risulta in una programmazione più veloce.