Polimorfismo

Il polimorfismo è una opportunità per le diverse classi di oggetti, relazionate attraverso l'ereditarietà, per rispondere in vari modi quando si chiama lo stesso elemento della funzione. Contribuisce a creare un meccanismo universale che descrive il comportamento non solo della classe base, ma anche delle classi discendenti.

Continuiamo a sviluppare una classe base CShape ,e definiamo un membro della funzione GetArea(), designato per calcolare l'area di una forma. In tutte le classi discendenti, prodotto per eredità dalla classe base, ri-definiamo questa funzione secondo le regole del calcolo dell'area di una forma particolare.

Per un quadrato (classe CSquare), l'area è calcolata attraverso i suoi lati, per un cerchio (classe CCircle), l'area si esprime attraverso il suo raggio, ecc. Siamo in grado di creare un array per memorizzare gli oggetti di tipo CShape, in cui entrambi gli oggetti di una classe base e quelli di tutte le classi discendenti possono essere memorizzati. Inoltre siamo in grado di chiamare la stessa funzione per ogni elemento della matrice.

Esempio:

//--- Base class
class CShape
  {
protected
   int            m_type;                // Tipo di forma
   int            m_xpos;                // X - coordinata del punto base
   int            m_ypos;                // Y - coordinata del punto base
public:
   void           CShape(){m_type=0;};   // costruttore, type=0
   int            GetType(){return(m_type);};// restituisce il tipo della forma
virtual
   double         GetArea(){return (0); }// restituisce l'area della forma
  };

Ora, tutte le classi derivate hanno un membro di funzione getArea(), che restituisce un valore pari a zero. L'implementazione di questa funzione in ogni discendente varierà.

//--- La classe derivata Circle
class CCircle : public CShape            // Dopo i due punti si definisce la classe base
  {                                      // da cui viene fatta l'eredità
private:
   double         m_radius;              // raggio del cerchio
 
public:
   void           CCircle(){m_type=1;};  // costruttore, type=1 
   void           SetRadius(double r){m_radius=r;};
   virtual double GetArea(){return (3.14*m_radius*m_radius);}// area del cerchio
  };

Per la classe Square la dichiarazione è la stessa:

//--- La classe derivata Square
class CSquare : public CShape            // Dopo i due punti si definisce la classe base
  {                                      // da cui viene fatta l'eredità
private:
   double          m_square_side;        // lato del quadrato
 
public:
   void            CSquare(){m_type=2;}; // costruttore, type=1
   void            SetSide(double s){m_square_side=s;};
   virtual double  GetArea(){return (m_square_side*m_square_side);}// area del quadrato
  };

Per calcolare l'area del quadrato e del cerchio, abbiamo bisogno dei valori corrispondenti di m_radius e m_square_side, così abbiamo aggiunto la funzione setRadius e SetSide() nella dichiarazione della classe corrispondente.

Si presume che oggetti di tipo diverso (CCircle e CSquare) derivati da uno tipo base CShape sono utilizzati nel nostro programma. Il polimorfismo consente di creare un array di oggetti della classe base CShape, ma quando si dichiara questo array, questi oggetti sono ancora sconosciuti ed il loro tipo non è definito.

La decisione su quale tipo di oggetto sarà contenuto in ogni elemento della matrice sarà presa direttamente durante l'esecuzione del programma. Ciò comporta la creazione dinamica di oggetti di classi corrispondenti, e quindi la necessità di utilizzare puntatori agli oggetti invece degli oggetti.

Il nuovo operatore viene utilizzato per la creazione dinamica di oggetti. Ognuno di questi oggetti deve essere individualmente ed esplicitamente eliminato utilizzando l'operatore delete. Quindi noi dichiariamo un array di puntatori di tipo CShape, e creiamo un oggetto di un tipo adatto per ogni elemento (nome_nuovaClasse), come illustrato nello script di esempio seguente:

//+--------------------------------------------------------------------------------+
//| Funzione di avvio del programma Script                                         |
//+--------------------------------------------------------------------------------+
voidOnStart()
  {
//--- Dichiara un array di puntatori a oggetti del tipo base
   CShape *shapes[5];   // Un array di puntatori all'oggetto CShape
 
//--- Qui si riempie l'array con gli oggetti derivati
//--- Dichiarazione di un puntatore all'oggetto di tipo CCircle
   CCircle *circle=new CCircle();
//--- Impostazione proprietà dell'oggetto con il puntatore del cerchio
   circle.SetRadius(2.5);
//--- Piazza il valore del puntatore in shapes[0]
   shapes[0]=circle;
 
//--- Crea un altro oggetto CCircle e scrive il suo puntatore in shapes[1]
   circle=new CCircle();
   shapes[1]=circle;
   circle.SetRadius(5);
 
//--- Qui "dimentichiamo" intenzionalmente di impostare un valore per shapes[2]
//circle=new CCircle();
//circle.SetRadius(10);
//shapes[2]=circle;
 
//--- Imposta NULL per l'elemento che non è utilizzato
   shapes[2]=NULL;
 
//--- Crea un oggetto CSquare e scrivere il suo puntatore in shapes[3]
   CSquare *square=new CSquare();
   square.SetSide(5);
   shapes[3]=square;
 
//--- Crea un oggetto CSquare e scrivere il suo puntatore in shapes[4]
   square=new CSquare();
   square.SetSide(10);
   shapes[4]=square;
 
//--- Abbiamo un array di puntatori, otteniamo la sua grandezza
   int total=ArraySize(shapes);
//--- Passaggio in un ciclo attraverso tutti i puntatori dell'array
   for(int i=0; i<5;i++)
     {
      //--- Se il puntatore in corrispondenza dell'indice specificato è valido
      if(CheckPointer(shapes[i])!=POINTER_INVALID)
        {
         //--- Log the type and square of the shape
         PrintFormat("The object of type %d has the square %G",
               shapes[i].GetType(),
               shapes[i].GetArea());
        }
      //--- Se il puntatore ha il tipo POINTER_INVALID
      else
        {
         //--- Notifica un errore
         PrintFormat("Le forme[%d] dell'oggetto non sono state inizializzate! Il suo puntatore è %s",
                     i,EnumToString(CheckPointer(shapes[i])));
        }
     }
 
//--- Dobbiamo eliminare tutti gli oggetti dinamici creati
   for(int i=0;i<total;i++)
     {
//--- Possiamo eliminare solo gli oggetti con puntatori di tipo POINTER_DYNAMIC
      if(CheckPointer(shapes[i])==POINTER_DYNAMIC)
        {
         //--- Notifica di eliminazione
         PrintFormat("Elimina forme[%d]",i);
         //--- Elimina un oggetto dal suo puntatore
         delete shapes[i];
        }
     }
  }

Si prega di notare che quando si elimina un oggetto utilizzando l'operatore delete, il tipo del suo puntatore deve essere controllato. Solo gli oggetti con il puntatore POINTER_DYNAMIC possono essere eliminati usando delete. Per i puntatori di altro tipo, verrà restituito un errore.

Ma oltre la ridefinizione delle funzioni durante la ereditarietà, il polimorfismo include anche l' implementazione di una e le stesse funzioni con diversi set di parametri all'interno di una classe. Ciò significa che la classe può avere funzioni diverse con lo stesso nome, ma con un diverso tipo e/o insieme di parametri. In questo caso, il polimorfismo è attuato mediante l'overload di funzione.

Vedi anche

Standard Library