User Tools

Site Tools


appunti3s:polimorfismo

Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Next revision
Previous revision
appunti3s:polimorfismo [2013/06/17 21:07]
127.0.0.1 external edit
appunti3s:polimorfismo [2020/06/08 22:19] (current)
Line 1: Line 1:
 +====== Polimorfismo ======
 +Nel caso in cui l'//ereditarietà// venga usata __insieme__ ai //puntatori// le classi possono comportarsi in modo ambiguo. In che senso ambiguo?
  
 +===== Usando Puntatori a... =====
 +
 +L'[[appunti3s:ereditarietà1|ereditarietà]] stabilisce che:
 +  * un oggetto di tipo classe Derivata deve essere (allo stesso tempo) anche del tipo Base
 +    * cioè che i puntatori (o reference) che uso per oggetti della Base possano puntare anche oggetti della Derivata
 +
 +Perché questo è possibile, mentre non è possibile l'inverso?
 +
 +Nel seguente esempio la classe Derivata è "derivata" da una classe Base (la classe Base è contenuta nella Derivata). 
 +<code>
 +class Base
 +{....};
 +
 +class Derivata : public Base 
 +{....};
 +</code>
 +
 +{{:appunti3s:ereditarieta1.png?|}}
 +
 +Si può creare //pBase// e //pDeriv//, rispettivamente, un puntatore ad un oggetto di Base e ad un oggetto di Derivata. Si nota che i due puntatori puntano a due aree di dimensione diversa (e colore diverso).
 +
 +{{:appunti3s:ereditarieta2.png?|}}
 +
 +Se si immagina di scambiare il contenuto delle aree puntate dai puntatori, ad una prima impressione potrebbe sembrare che lo scambio sarebbe corretto solo se l'area puntata (tratteggiata) fosse abbastanza grande per contenere il nuovo oggetto. Invece le cose stanno esattamente al contrario...
 +  - Per utilizzare il puntatore per la classe Base //pBase// su un oggetto della Derivata, si devono e si possono "tagliare" le informazioni all'oggetto della Derivata che non esistono nella classe Base.
 +  - Per utilizzare il puntatore per la classe Derivata  //pDeriv// su un oggetto della Base, si dovrebbero "aggiungere" delle informazioni all'oggetto della classe Base che esisterebbero in un oggetto della classe Derivata, ma cosa si potrebbe aggiungere???? Non ci si può inventare le informazioni che non esistono
 +
 +{{:appunti3s:ereditarieta3.png?|}}
 +
 +Poiché, nella relazione di ereditarietà, un puntatore della classe Base può puntare anche un oggetto della classe Derivata, SE nel programma uso i puntatori agli oggetti, ALLORA potrebbe generarsi un'ambiguità durante le chiamate delle funzioni. 
 +Come in questo esempio: 
 +<code>
 +void Base::fun()
 +{
 +   //...
 +}
 +
 +void Derivata::fun()
 +{
 +   //...
 +}
 +
 +int main()
 +{
 +   Base* pBase = new Base();
 +   Derivata* pDeriv = new Derivata();
 +   pBase = pDerivata;   // scambio dell'oggetto puntato
 +   pBase->fun();        // quale funzione chiama? Base::fun() oppure Derivata::fun()
 +                        // il puntatore è di tipo Base*, l'oggetto puntato è di tipo Derivata
 +
 +}
 +</code>
 +
 +===== Early binding =====
 +Questo tipo di ambiguità, in C++, viene risolta al momento della compilazione, invocando la funzione della classe **del puntatore** Base::fun().
 +Questa soluzione è più efficiente e si chiama //early binding// (o anche static binding).
 +
 +===== Late binding =====
 +Viceversa, se dichiaro la funzione //virtual//, allora viene chiamata quella della Derivata (late binding).
 +<code>
 +virtual void Base::fun()
 +{
 +   //...
 +}
 +
 +virtual void Derivata::fun()
 +{
 +   //...
 +}
 +
 +int main()
 +{
 +   Base* pBase = new Base();
 +   Derivata* pDeriv = new Derivata();
 +   pBase = pDerivata;   // scambio dell'oggetto puntato
 +   pBase->fun();        // quale funzione chiama? Base::fun() oppure Derivata::fun()
 +                        // la funzione BASE::fun() è virtual quindi 
 +                        // ora non conta il tipo di puntatore ma l'oggetto puntato
 +}
 +</code>
 +
 +È Il tipo di oggetto che invoca la funzione //virtual// a determinare quale versione di tale funzione deve essere usata. 
 +Quest'ultimo sistema, insieme alle [[appunti3s:polimorfismo&#classe_astratta|classi astratte]], consente di creare delle generiche classi Base, con delle funzioni membro virtuali che verranno implementate dalle classi da loro derivate. Tutto questo SENZA modificare il vecchio codice della classe Base. Il late binding è più flessibile ma meno efficiente rispetto al early binding.
 +
 +Quando progetto una classe, se voglio che nelle chiamate di funzione comandi il tipo di puntatore, invece del dell'oggetto puntato, non uso //virtual//.
 +
 +L'ambiguità ovviamente non esiste se non uso i puntatori. (esempio: unOggetto.unMetodo();)
 +  * Le funzioni "__definite__" //virtual// nella classe Base __possono__ essere "__ridefinite__" nella classe Derivata. In caso contrario esse rimangono //virtual// anche nella classe Derivata, senza obbligo di ripetere la parola //virtual// 
 +  * I costruttori NON possono essere //virtual//
 +  * La funzione membro //virtual// della classe Derivata può richiamare quella della Base usando l'operatore <code>::</code>
 +  * Le funzioni membro //virtual//, quando sono chiamate dentro un costruttore/distruttore, sono quelle della Base
 +
 +
 +====Classe astratta====
 +
 +Vedere anche relazione di [[appunti3s:relazioni_tra_classi#realizzazione]]
 +
 +Questo tipo di classe si usa quando la classe non deve rappresentare concetti concreti e/o quando __non__ si devono realizzare mai oggetti di questo tipo. Grazie all'uso delle classi astratte insieme al polimorfismo si possono realizzare delle librerie facilmente espandibili con nuove classi
 +
 +  * Nella //classe astratta// deve esserci almeno una funzione membro //virtuale pura//. <code>void fun(intx) = 0;</code>
 +  * Nella //classe astratta// non viene //definita// nessuna delle sue funzioni membro.
 +  * Una classe Derivata da una //classe Base astratta//, è a sua volta //classe astratta//, se la funzione //virtuale pura// __non__ viene implementata nella Derivata.
appunti3s/polimorfismo.txt · Last modified: 2020/06/08 22:19 (external edit)