sabato 9 agosto 2014

Ripasso sui membri privati della classe genitrice.

Ripassiamo queste eventualità, cercando di schematizzare:
  1. la classe Genitrice ha una proprietà privata;
    1. accesso da un metodo della classe Genitrice;
    2. accesso da un metodo della classe Derivata
    3. accesso da un metodo della classe Derivata che overridda un metodo della classe Genitrice.
  2. la classe Genitrice ha una proprietà privata e la classe Derivata ha una proprietà con lo stesso nome:
    1. accesso da un metodo della classe Genitrice;
    2. accesso da un metodo della classe Derivata;
    3. accesso da un metodo della classe Derivata che overridda un metodo della classe Genitrice.
Ripassiamo queste:

La classe Genitrice ha una proprietà privata: ne saggiamo l'accesso da un metodo della classe Genitrice
#include "iostream"
using namespace std;


class Genitrice{
  char * proprieta;
public:
 Genitrice(){
 proprieta="io sono la proprieta' della genitrice";
 }
void metodoGen(){
 cout << "io sono il metodo della genitrice, " << proprieta << endl;
 getchar();
 }
};

class Derivata:public Genitrice{
public:
 Derivata():Genitrice(){
 }
};

void main(){
 Genitrice Gen;
 Derivata der;
 Gen.metodoGen();
} 
io sono il metodo della genitrice, io sono la proprieta' della genitrice


Dicendo "io sono il metodo della genitrice" si esprime il fatto che è stato chiamato il metodo della classe Genitrice; dicendo "io sono la proprietà della genitrice" si esprime il fatto che il metodo ha messo a video la proprietà della classe Genitrice.
La classe Genitrice ha una proprietà privata: ne saggiamo l'accesso da un metodo della classe Derivata
#include "iostream"
using namespace std;


class Genitrice{
  char * proprieta;
public:
 Genitrice(){
 proprieta="io sono la proprieta' della genitrice";
 }
void metodoGen(){
 cout << "io sono il metodo della genitrice, " << proprieta << endl;
 getchar();
 }
};

class Derivata:public Genitrice{
public:
 Derivata():Genitrice(){
 }
 void metodoDer(){
  cout << "Io sono il metodo della derivata, " << proprieta << endl;
 }

};

void main(){
 Genitrice Gen;
 Derivata der;
 der.metodoDer();
} 
1>c:\users\antonello\documents\visual studio 2010\projects\test1\test1\foglio.cpp(22): error C2248: 'Genitrice::proprieta': impossibile accedere a private membro dichiarato nella classe 'Genitrice'
Ecco, in questo caso, essendo la proprietà privata della classe Genitrice, il metodo della classe Derivata non la vede.
Ma dal momento che il metodo della classe Genitrice è ereditato dalla classe Derivata, posso chiamare questo metodo anche dalla classe Derivata:
void main(){
 Genitrice Gen;
 Derivata der;
 der.metodoGen();
}
io sono il metodo della genitrice, io sono la proprieta' della genitrice


Ho dovuto togliere il metodo metodoDer() in quanto avevo un codice di errore in quanto la definizione del metodo fa riferimento a una proprietà inaccessibile.
La classe Genitrice ha una proprietà privata: ne saggiamo l'accesso da un metodo della classe Derivata che overridda un metodo con lo stesso nome della classe Genitrice.
#include "iostream"
using namespace std;


class Genitrice{
  char * proprieta;
public:
 Genitrice(){
 proprieta="io sono la proprieta' della genitrice";
 }
void metodo(){
 cout << "io sono il metodo della genitrice, " << proprieta << endl;
 getchar();
 }
};

class Derivata:public Genitrice{
public:
 Derivata():Genitrice(){
 }
 void metodo(){
 cout << "io sono il metodo della derivata, " << proprieta << endl;
 getchar();
 }

};

void main(){
 Genitrice Gen;
 Derivata der;
 der.metodo();
}
1>c:\users\antonello\documents\visual studio 2010\projects\test1\test1\foglio.cpp(22): error C2248: 'Genitrice::proprieta': impossibile accedere a private membro dichiarato nella classe 'Genitrice'
Era ovvio: già nella definizione del metodo l'intellisense dà errore per membro inaccessibile.
Dunque la classe Derivata non può overriddare: se si elimina la definizione del metodo nella classe Derivata è:
io sono il metodo della genitrice, io sono la proprieta' della genitrice



L'overriding zittisce il metodo della classe genitrice.

venerdì 8 agosto 2014

Prove sull'overriding delle proprietà protected.

Bene.
Adesso, invece del public mettiamoci il protected: credo che sia esattamente la stessa cosa del public, visto che una proprietà protected è visibile dalla classe derivata.

Ricominciamo:
Proprietà protected overridata:
#include "iostream"
using namespace std;


class Genitrice{
protected:
	char * proprieta;
public:
 
 Genitrice(){
  proprieta="sono la proprieta' della genitrice";
 }
 void metodo(){
  cout << proprieta << endl;
  getchar();
 }
};

class Derivata:public Genitrice{
protected:
	 char * proprieta;
public:

 Derivata():Genitrice(){
  proprieta="sono la proprieta' della derivata";
 }

 void metodo(){
  cout << proprieta << endl;
  getchar();
 }

};

void main(){
 Genitrice gen;
 Derivata der;
 gen.metodo();
 der.metodo();

}
sono la proprieta' della genitrice

sono la proprieta' della derivata


Proprietà protected overridata letta con un metodo della classe genitrice e uno diverso della classe derivata:
#include "iostream"
using namespace std;


class Genitrice{
protected:
	char * proprieta;
public:
 
 Genitrice(){
  proprieta="sono la proprieta' della genitrice";
 }
 void metodoGen(){
  cout << proprieta << endl;
  getchar();
 }
};

class Derivata:public Genitrice{
protected:
	 char * proprieta;
public:

 Derivata():Genitrice(){
  proprieta="sono la proprieta' della derivata";
 }

 void metodoDer(){
  cout << proprieta << endl;
  getchar();
 }

};

void main(){
 Genitrice gen;
 Derivata der;
 gen.metodoGen();
 der.metodoDer();

}
sono la proprieta' della genitrice

sono la proprieta' della derivata


Leggiamole usando metodoGen ereditato dalla classe derivata, e il risultato dovrebbe essere lo stesso:
void main(){
 Genitrice gen;
 Derivata der;
 der.metodoGen();
 der.metodoDer();

}
infatti...
sono la proprieta' della genitrice

sono la proprieta' della derivata




Togliamo la proprietà dalla classe derivata:
#include "iostream"
using namespace std;


class Genitrice{
protected:
	char * proprieta;
public:
 
 Genitrice(){
  proprieta="sono la proprieta' della genitrice";
 }
 void metodoGen(){
  cout << proprieta << endl;
  getchar();
 }
};

class Derivata:public Genitrice{


public:

 Derivata():Genitrice(){

 }

 void metodoDer(){
  cout << proprieta << endl;
  getchar();
 }

};

void main(){
 Genitrice gen;
 Derivata der;
 gen.metodoGen();
 der.metodoGen();
 der.metodoDer();

}
sono la proprieta' della genitrice

sono la proprieta' della genitrice

sono la proprieta' della genitrice


Chiamandole direttamente:
void main(){
 Genitrice gen;
 Derivata der;
 cout << gen.proprieta << endl;
 cout << der.proprieta << endl;
 getchar();

} 
1>c:\users\antonello\documents\visual studio 2010\projects\test1\test1\foglio.cpp(38): error C2248: 'Genitrice::proprieta': impossibile accedere a protected membro dichiarato nella classe 'Genitrice'
Ecco: la differenza è solo che la proprietà protected non può essere chiamata dall'esterno della classe derivata in quanto si comporta come una proprietà privata quando chiamata dall'esterno.

Prove sull'overriding delle proprietà pubbliche di una classe.

Overridiamo una proprietà pubblica...

#include "iostream"
using namespace std;


class Genitrice{
 
public:
 char * proprieta;
 Genitrice(){
  proprieta="sono la proprieta' della genitrice";
 }
 void metodo(){
  cout << proprieta << endl;
  getchar();
 }
};

class Derivata:public Genitrice{
 
public:
 char * proprieta;
 Derivata():Genitrice(){
  proprieta="sono la proprieta' della derivata";
 }

 void metodo(){
  cout << proprieta << endl;
  getchar();
 }

};

void main(){
 Genitrice gen;
 Derivata der;
 gen.metodo();
 der.metodo();

}

sono la proprieta' della genitrice

sono la proprieta' della derivata


Ho messo pubblica una proprietà e l'ho ridefinita nella classe derivata.
Se istanzio la classe genitrice viene letta la proprietà della classe genitrice, mentre se istanzio la classe derivata, che overridda il metodo, questo legge la proprietà della classe derivata e non più quella della genitrice.
Anziché overriddare il metodo, creo due metodi con nome diverso che mettano a video la proprietà, un nome nella classe genitrice e uno nella classe derivata.
#include "iostream"
using namespace std;


class Genitrice{
 
public:
 char * proprieta;
 Genitrice(){
  proprieta="sono la proprieta' della genitrice";
 }
 void metodoGen(){
  cout << proprieta << endl;
  getchar();
 }
};

class Derivata:public Genitrice{
 
public:
 char * proprieta;
 Derivata():Genitrice(){
  proprieta="sono la proprieta' della derivata";
 }

 void metodoDer(){
  cout << proprieta << endl;
  getchar();
 }

};

void main(){
 Genitrice gen;
 Derivata der;
 gen.metodoGen();
 der.metodoDer();

}
sono la proprieta' della genitrice

sono la proprieta' della derivata


Anche così il comportamento è lo stesso.
Dunque un metodo della classe genitrice vede la proprietà della classe genitrice, mentre un metodo della classe derivata vede la proprietà overriddata della classe derivata.

Essendo la proprietà pubblica, possiamo anche chiamarla direttamente:
#include "iostream"
using namespace std;


class Genitrice{
 
public:
 char * proprieta;
 Genitrice(){
  proprieta="sono la proprieta' della genitrice";
 }
 void metodoGen(){
  cout << proprieta << endl;
  getchar();
 }
};

class Derivata:public Genitrice{
 
public:
 char * proprieta;
 Derivata():Genitrice(){
  proprieta="sono la proprieta' della derivata";
 }

 void metodoDer(){
  cout << proprieta << endl;
  getchar();
 }

};

void main(){
 Genitrice gen;
 Derivata der;
 cout << gen.proprieta << endl;
 getchar();
 cout << der.proprieta << endl;
 getchar();

} 
sono la proprieta' della genitrice

sono la proprieta' della derivata




Adesso proviamo a eseguire il metodo della classe genitrice dalla genitrice e dalla derivata e vediamo quale proprietà vede:
#include "iostream"
using namespace std;


class Genitrice{
 
public:
 char * proprieta;
 Genitrice(){
  proprieta="sono la proprieta' della genitrice";
 }
 void metodoGen(){
  cout << proprieta << endl;
  getchar();
 }
};

class Derivata:public Genitrice{
 
public:
 char * proprieta;
 Derivata():Genitrice(){
  proprieta="sono la proprieta' della derivata";
 }

 void metodoDer(){
  cout << proprieta << endl;
  getchar();
 }

};

void main(){
 Genitrice gen;
 Derivata der;
 gen.metodoGen();
 der.metodoGen();
}
sono la proprieta' della genitrice

sono la proprieta' della genitrice


Vede sempre la proprietà della classe genitrice anche quando viene eseguito dalla classe derivata.


Se togliamo la proprietà dalla classe derivata, anche da questa si dovrebbe avere accesso a quella della classe genitrice.
Proviamo:
#include "iostream"
using namespace std;


class Genitrice{
 
public:
 char * proprieta;
 Genitrice(){
  proprieta="sono la proprieta' della genitrice";
 }
 void metodoGen(){
  cout << proprieta << endl;
  getchar();
 }
};

class Derivata:public Genitrice{
 
public:

 Derivata():Genitrice(){
  
 }

 void metodoDer(){
  cout << proprieta << endl;
  getchar();
 }

};

void main(){
 Genitrice gen;
 Derivata der;
 gen.metodoGen();
 der.metodoDer();

}
sono la proprieta' della genitrice

sono la proprieta' della genitrice


Da qui possiamo comprendere meglio:
Dunque, una proprietà pubblica può essere ereditata dalla classe derivata, ma overridata. Nel caso sia overridata, però, la classe genitrice vede sempre la proprietà "sua", anche quando il metodo della classe genitrice venga chiamato dalla classe derivata.
Proviamo a evocarlo direttamente.
void main(){
 Genitrice gen;
 Derivata der;
 cout << gen.proprieta << endl;
 getchar();
 cout << der.proprieta << endl;
 getchar();
}
sono la proprieta' della genitrice

sono la proprieta' della genitrice


In pratica non ci sono molte novità...
L'unica cosa notevole, che non mi risultava molto immediata, è che un metodo della classe genitrice vede la proprietà della classe genitrice, non overridata.
Cominciamo a entrare in confidenza con il meccanismo... lo sto spremendo come un limone (quando ho tempo di concentrarmi con calma!)

mercoledì 6 agosto 2014

L'immagine delle scatole per capire bene l'ereditarietà in C++

Dunque...
La classe genitrice è come una scatola compresa entro una scatola più grande che è la classe derivata.
La classe derivata sarà di necessità più grande della genitrice, contenendola.

Immagino la genitrice come una scatola di vetro in parte opaco e in parte trasparente, a seconda che la classe derivata abbia o no accesso ai suoi membri
class Genitrice{
 char * privata;
public:
 Genitrice(){
  privata="sono privata";
 }
 void metodo(){
  cout << privata << endl;
  getchar();
 }
};
Ecco, qui il membro privata non è visibile all'esterno, ma è visibile dall'interno della classe, anche quando questa è compresa in una "scatola" più grande che è la classe derivata.
Dato che il metodo metodo è visibile anche dall'ambiente della scatola più grande, si può fare leva su di esso per agire sul membro privata che è invisibile dall'ambiente della scatola più grande.

Provo a sbizzarrirmi un po'...

#include "iostream"
using namespace std;


class Genitrice{
 char * privata;
public:
 Genitrice(){
  privata="sono privata";
 }
 void metodo(){
  cout << privata << endl;
  getchar();
 }
};

class Derivata:public Genitrice{
public:
 Derivata():Genitrice(){}
 void altrometodo(){
  cout << "altro metodo" << endl;
  getchar();
 }

};




void main(){
 Genitrice gen;
 Derivata der;
 der.metodo();
}
Ecco: la classe derivata non overridda il metodo metodo, per cui quando si chiama il metodo della classe derivata si fa riferimento al contenuto della scatola più piccola che si trova nella parte visibile di essa, il quale ha accesso a tutti i membri della scatola più piccola, e quindi anche alla variabile privata, che si trova nella parte opaca della scatola più piccola.

Adesso, invece, overriddiamo metodo: questo si può paragonare a un taglio operato sulla scatola più piccola, dove viene troncata la parte trasparente dove risiede il metodo metodo e al posto di essa viene messo un analogo metodo metodo appartenente però all'ambiente della scatola più grande, e che quindi non ha accesso alla parte opaca della scatola più piccola.
#include "iostream"
using namespace std;


class Genitrice{
 char * privata;
public:
 Genitrice(){
  privata="sono privata";
 }
 void metodo(){
  cout << privata << endl;
  getchar();
 }
};

class Derivata:public Genitrice{
public:
 Derivata():Genitrice(){}
 void metodo(){
  cout << privata << endl;
  getchar();
 }
 void altrometodo(){
  cout << "altro metodo" << endl;
  getchar();
 }

};




void main(){
 Genitrice gen;
 Derivata der;
 der.metodo();
} 
Ottengo l'errore già con l'intelliSense...

Ecco l'output, comunque:
1>c:\users\antonello\documents\visual studio 2010\projects\test1\test1\foglio.cpp(21): error C2248: 'Genitrice::privata': impossibile accedere a private membro dichiarato nella classe 'Genitrice'
Certo: perché adesso il metodo metodo si trova nell'ambiente della scatola esterna, e non ha più accesso al membro privata della parte opaca della scatola più piccola, dove invece aveva accesso il metodo non overriddato in quanto appartenente alla scatola più piccola.

martedì 5 agosto 2014

Accesso a membri privati della classe genitrice da metodi della classe genitrice ma non della classe derivata.

Scopro un'altra cosa che non mi era mai venuta in mente.
Una classe derivata non può accedere con metodi suoi ai membri privati della classe genitrice.
Con metodi ereditati, invece, vi può accedere!

Ecco:
#include "iostream"
using namespace std;


class Genitrice{
 char * privata;
public:
 Genitrice(){
  privata="sono privata";
 }
 void metodo(){
  cout << privata << endl;
  getchar();
 }
};

class Derivata:public Genitrice{
public:
 Derivata():Genitrice(){}

};




void main(){
 Genitrice gnt;
 gnt.metodo();
 Derivata drv;
 drv.metodo();
}
Ecco:
sono privata

sono privata


Invocando nella classe derivata il metodo ereditato dalla classe genitrice, esso vede il membro privato della classe genitrice.
Adesso overriddo il metodo:
#include "iostream"
using namespace std;


class Genitrice{
 char * privata;
public:
 Genitrice(){
  privata="sono privata";
 }
 void metodo(){
  cout << privata << endl;
  getchar();
 }
};

class Derivata:public Genitrice{
public:
 Derivata():Genitrice(){}
 void metodo(){
  cout << privata << endl;
  getchar();
 }

};




void main(){
 Genitrice gnt;
 gnt.metodo();
 Derivata drv;
 drv.metodo();
}
Ecco, adesso la classe derivata overridda il metodo, ripetendolo esattamente uguale, ma appartenente ad essa, non alla classe genitrice.
1>c:\users\antonello\documents\visual studio 2010\projects\test1\test1\foglio.cpp(21): error C2248: 'Genitrice::privata': impossibile accedere a private membro dichiarato nella classe 'Genitrice'
Ecco, come volevasi dimostrare!

La variabile di classe genitrice, eguagliata alla classe derivata, contiene le proprietà della classe derivata?

Bene.
Ho una classe genitrice, non astratta: qualcosa che può generare eredi, ma che può esistere anche di per sè.

Dal momento che si può eguagliare una variabile di un tipo classe a un oggetto di una classe derivata, voglio vedere cosa è in comune fra la variabile di classe genitrice e la variabile di classe derivata.

Creo una classe genitrice di tipo "Medico" che sarebbe il medico generico, il quale non è un'idea astratta, ma può esistere nella realtà, quindi è da definire con una classe non astratta.
La classe derivata è "Radiologo", il quale possiede una variabile "specialita", non posseduta dalla classe genitrice, e mentre il Medico diagnostica visitando il Radiologo overloada il metodo con "referta le radiografie".

Istanziamo il Radiologo e poi creiamo una variabile di tipo Medico, che eguagliamo a Radiologo, per vedere se contiene la variabile "specialita".
#include "iostream"
using namespace std;


class Medico{
public:
 
 

 void diagnostica(){
  cout << "visita" << endl;
  getchar();
 }
};

class Radiologo:public Medico{

 
public:
 char * specialita;
 Radiologo(){
  specialita="radiologia";
 }
 void diagnostica(){
  cout << "referta le radiografie" << endl;
  getchar();
 }
};


void main(){
 Radiologo Pippo;
 cout << Pippo.specialita << endl;
 getchar();
 Medico mdc;
 mdc=Pippo;
 cout << mdc.specialita << endl;
 getchar();
} 
1>c:\users\antonello\documents\visual studio 2010\projects\test1\test1\foglio.cpp(37): error C2039: 'specialita': non è un membro di 'Medico'
Dunque la variabile di classe genitrice, eguagliata a quella di classe derivata, non contiene le proprietà della classe derivata.

sabato 2 agosto 2014

Seguiamo l'esempio di Wikipedia per quanto riguarda il polimorfismo.
Abbiamo una classe astratta Animale, e due classi derivate da questa, Cane e Gatto.
Creiamole...
#include "iostream"
using namespace std;

class Animale{
public:
	virtual void CosaMangia()=0;
};

class Cane: public Animale{
public:
	void CosaMangia(){
		cout << "Osso" << endl;
		getchar();
	}
};

class Gatto: public Animale{
public:
	void CosaMangia(){
		cout << "Pesce" << endl;
		getchar();
	}
};
Ecco: proviamo a istanziare...
void main(){
	Animale * mioAnimale;
	mioAnimale= new Cane();
	mioAnimale->CosaMangia();
	delete mioAnimale;
	mioAnimale=new Gatto();
	mioAnimale->CosaMangia();
	delete mioAnimale;

}
Ecco l'output:
Osso

Pesce




Ora dovrei costruire una funzione che prende come parametro un puntatore di tipo Animale...

void funzione(Animale * animal){
	animal->CosaMangia();
}

void main(){
	Cane * mioCane=new Cane();
	Gatto * mioGatto=new Gatto();
	funzione(mioCane);
	funzione(mioGatto);
}
E funziona:
Osso

Pesce