martedì 9 settembre 2014

Nascondimento per nome e per firma dei metodi ereditati in C++

Creiamo tre generazioni in C++

#include "iostream"
using namespace std;

class Nonno{
public:
	void metodo(){
		cout << "io sono il metodo senza parametri" << endl;
		getchar();
	}
};

class Padre: public Nonno{
public:
	void metodo(char * parametro){
		cout << "io sono il metodo con un parametro" << endl;
		getchar();
	}
};

class Figlio: public Padre{
public:
	void metodo(char * parametro, char * parametro2){
		cout << "io sono il metodo con due parametri" << endl;
		getchar();
	}
};


void main(){

	Nonno * Mario = new Nonno();
	Padre * Pasquale = new Padre();
	Figlio * Nicola = new Figlio();


}
Il nonno sapeva fare il metodo senza parametri, il padre inventò il metodo con un parametro, il figlio il metodo con due parametri.
Ora chiediamo a ciascuno di eseguire il metodo secondo la sua invenzione:
void main(){

	Nonno * Mario = new Nonno();
	Padre * Pasquale = new Padre();
	Figlio * Nicola = new Figlio();

	Mario->metodo();
	Pasquale->metodo("parametro");
	Nicola->metodo("parametro","parametro");

}
io sono il metodo senza parametri

io sono il metodo con un parametro

io sono il metodo con due parametri


Fin qui tutto bene.
Ma adesso chiediamo al figlio Nicola di fare le cose alla maniera di suo nonno:
void main(){

	Nonno * Mario = new Nonno();
	Padre * Pasquale = new Padre();
	Figlio * Nicola = new Figlio();

	Mario->metodo();
	Pasquale->metodo("parametro");
	Nicola->metodo();

}
1>------ Inizio compilazione: Progetto: test15, Configurazione: Debug Win32 ------
1>  foglio1.cpp
1>c:\users\antonello\documents\visual studio 2010\projects\test15\test15\foglio1.cpp(37): error C2660: 'Figlio::metodo': la funzione non accetta 0 argomenti
1>C:\Program Files (x86)\MSBuild\Microsoft.Cpp\v4.0\Platforms\Win32\Microsoft.Cpp.Win32.Targets(153,5): error MSB6006: "CL.exe" terminato con il codice 2.
========== Compilazione: 0 completate, 1 non riuscite, 0 aggiornate, 0 ignorate ==========


Ecco: Il figlio non ha più il metodo del nonno!

Vediamo se ce l'ha il padre:
void main(){

	Nonno * Mario = new Nonno();
	Padre * Pasquale = new Padre();
	Figlio * Nicola = new Figlio();

	Mario->metodo();
	Pasquale->metodo();


}
1>------ Inizio compilazione: Progetto: test15, Configurazione: Debug Win32 ------
1>  foglio1.cpp
1>c:\users\antonello\documents\visual studio 2010\projects\test15\test15\foglio1.cpp(36): error C2660: 'Padre::metodo': la funzione non accetta 0 argomenti
========== Compilazione: 0 completate, 1 non riuscite, 0 aggiornate, 0 ignorate ==========

Ecco: neanche il padre ce l'ha!
Questo perché in C++ vale il nascondimento per nome, ossia quando in una classe derivata viene implementato un metodo con lo stesso nome di un metodo ereditato vengono nascosti tutti i metodi ereditati con lo stesso nome, indipendentemente dalla firma!.
Dunque il Padre, creando un nuovo metodo con lo stesso nome, ha nascosto tutto ciò che ha ereditato dal Nonno, e non lascia più al Figlio una beneamata mazza di quello che aveva ereditato!
Stessa cosa fa il figlio creando il suo nuovo metodo.


C'è un artifizio per trasformare il nascondimento per nome in un nascondimento per firma:
#include "iostream"
using namespace std;

class Nonno{
public:
	void metodo(){
		cout << "io sono il metodo senza parametri" << endl;
		getchar();
	}
};

class Padre: public Nonno{
public:
	using Nonno::metodo;
	void metodo(char * parametro){
		cout << "io sono il metodo con un parametro" << endl;
		getchar();
	}
};

class Figlio: public Padre{
public:
	void metodo(char * parametro, char * parametro2){
		cout << "io sono il metodo con due parametri" << endl;
		getchar();
	}
};


void main(){

	Nonno * Mario = new Nonno();
	Padre * Pasquale = new Padre();
	Figlio * Nicola = new Figlio();

}
Il Padre non nasconde più i metodi ereditati dal Nonno quando crea un nuovo metodo con lo stesso nome.
Ovviamente se crea un nuovo metodo con la stessa firma questo nasconderà quello ereditato con la stessa firma, ma non nasconderà più quelli ereditati con lo stesso nome e con firma diversa.

Proviamo:
void main(){

	Nonno * Mario = new Nonno();
	Padre * Pasquale = new Padre();
	Figlio * Nicola = new Figlio();

	Mario->metodo();
	Pasquale->metodo();
	Pasquale->metodo("parametro");
	Nicola->metodo();
}
Ed ecco:
1>------ Inizio compilazione: Progetto: test15, Configurazione: Debug Win32 ------
1>  foglio1.cpp
1>c:\users\antonello\documents\visual studio 2010\projects\test15\test15\foglio1.cpp(39): error C2660: 'Figlio::metodo': la funzione non accetta 0 argomenti
========== Compilazione: 0 completate, 1 non riuscite, 0 aggiornate, 0 ignorate ==========

...ma se chiadiamo al Padre di svolgere questa funzione ereditata dal Nonno:
io sono il metodo senza parametri

io sono il metodo senza parametri

io sono il metodo con un parametro


esso continua ad averla proprio in virtù di quella riga che ha evitato il nascondimento per nome.

Mettiamo questa riga anche nel Figlio:
#include "iostream"
using namespace std;

class Nonno{
public:
	void metodo(){
		cout << "io sono il metodo senza parametri" << endl;
		getchar();
	}
};

class Padre: public Nonno{
public:
	using Nonno::metodo;
	void metodo(char * parametro){
		cout << "io sono il metodo con un parametro" << endl;
		getchar();
	}
};

class Figlio: public Padre{
public:
	using Padre::metodo;
	void metodo(char * parametro, char * parametro2){
		cout << "io sono il metodo con due parametri" << endl;
		getchar();
	}
};


void main(){

	Nonno * Mario = new Nonno();
	Padre * Pasquale = new Padre();
	Figlio * Nicola = new Figlio();

	Mario->metodo();
	Pasquale->metodo();
	Pasquale->metodo("parametro");
	Nicola->metodo();
} 
Et voila! Anche il Figlio svolgerà la funzione ereditata dal Nonno!
io sono il metodo senza parametri

io sono il metodo senza parametri

io sono il metodo con un parametro

io sono il metodo senza parametri


Se però il Padre non usa quella riga, cosa accade?
#include "iostream"
using namespace std;

class Nonno{
public:
	void metodo(){
		cout << "io sono il metodo senza parametri" << endl;
		getchar();
	}
};

class Padre: public Nonno{
public:
	void metodo(char * parametro){
		cout << "io sono il metodo con un parametro" << endl;
		getchar();
	}
};

class Figlio: public Padre{
public:
	using Padre::metodo;
	void metodo(char * parametro, char * parametro2){
		cout << "io sono il metodo con due parametri" << endl;
		getchar();
	}
};


void main(){

	Nonno * Mario = new Nonno();
	Padre * Pasquale = new Padre();
	Figlio * Nicola = new Figlio();

}
 
proviamo a chiedere al figlio di svolgere la funzione:
void main(){

	Nonno * Mario = new Nonno();
	Padre * Pasquale = new Padre();
	Figlio * Nicola = new Figlio();


	Nicola->metodo();
}
1>------ Inizio compilazione: Progetto: test15, Configurazione: Debug Win32 ------
1>  foglio1.cpp
1>c:\users\antonello\documents\visual studio 2010\projects\test15\test15\foglio1.cpp(37): error C2661: 'Padre::metodo': nessuna funzione in overload accetta 0 argomenti
========== Compilazione: 0 completate, 1 non riuscite, 0 aggiornate, 0 ignorate ==========


Ecco come un Padre degenere che non ha conservato l'eredità del Nonno lascia in mezzo a una strada il Figlio!

Nessun commento:

Posta un commento