Classi derivate

di il
13 risposte

Classi derivate

Sto studiando le classe derivate ma non riesco a capire questo concetto che cerco di spiegare con il seguente codice
#include <iostream>
#include <vector>
using namespace std;

class Persona {
public:
	int a;
	string nome;
	string cognome;
	int eta;
	Persona() { cout << "costruttore classe persona" << a << endl; }
	void stampa() { cout << "richiamo metodo classe Persona " << a << endl << endl; }
};

class Studente: public Persona {
public:
	int esami;
	int facolta;
	Studente() { cout << "costruttore classe studente" << a << endl; }
	void stampa() { cout << "richiamo metodo classe Studente " << a << endl << endl; }
};

class Prova: public Studente {
public:
	Prova() { cout << "costruttore classe Prova" << a << endl; }
	void stampa() { cout << "richiamo metodo classe Prova " << a << endl << endl; }
};

int main() {
	Persona* pp = NULL;
	Studente* ps = NULL;
	pp = new Persona;
	ps = new Studente;

	cout << endl << endl;

	pp->a = 10;
	ps->a = 99;
	pp->stampa();
	ps->stampa();

	pp = ps;
	pp->stampa() << " " << pp->a;		// richiama il metodo Persona
}
Il mio dubbio:

perchè nell'ultima riga pp->stampa() richiama il metodo stampa della classe Persona ma stampa invece il valore di a che fa parte della classe Studente.
pp è un puntatore alla classe Persona ed immagino che il metodo richiamato faccia riferimento al tipo del puntatore (Persona) e non all'effettivo oggetto (Studente) puntato ma non capisco quale sia la logica di accesso al valore 'a' all'interno del metodo richiamato... mi sarei aspetto un 10 come output invece stampa 99.
Grazie

13 Risposte

  • Re: Classi derivate

    Non capisco cosa hai scritto ma dovrebbe essere
    
    pp->stampa();
    cout << " " << pp->a;		
    
    dato che stampa è un metodo void

    E utilizza la classe Persona regolarmente.
  • Re: Classi derivate

    oregon ha scritto:


    Non capisco cosa hai scritto ma dovrebbe essere
    oops pardon! un errore di distrazione.

    E utilizza la classe Persona regolarmente.
    Non comprendo perchè venga stampato il valore di a uguale a 99 che è quello appartenente alla classe Studente.
    a vale 10 nella classe Persona.
  • Re: Classi derivate

    I concetti alla base di quello che non capisci sono:

    - ereditarieta'
    - polimorfismo
    - metodo virtuale
    - override (sovvrascrittura)



    https://it.wikipedia.org/wiki/Funzione_virtual
    https://it.wikipedia.org/wiki/Overrid

    La cosa si complica in C++ perche' OLTRE a metodi virtuali (definiti mediante la keyword "virtual") ci sono anche i NORMALI metodi che DIPENDONO dalla struttura dati a cui fa riferimento IL TIPO DI PUNTATORE, E NON dal TIPO dell'oggetto PUNTATO!!!! E questo e' ESATTAMENTE il tuo caso!

    Nelle ultime righe tu assegni a "pp" un oggetto di tipo Studente, MA il puntatore e' di tipo PERSONA. "pp->a" stampa 99, perche' stai usando l'oggetto che in "a" contiene 99, MA usi il metodo della classe Persona perche' il metodo NON E" virtuale e il puntatore e' un puntatore A Persona!
  • Re: Classi derivate

    zio_mangrovia ha scritto:


    Non comprendo perchè venga stampato il valore di a uguale a 99 che è quello appartenente alla classe Studente.
    a vale 10 nella classe Persona.
    pp = ps…
  • Re: Classi derivate

    migliorabile ha scritto:


    La cosa si complica in C++ perche' OLTRE a metodi virtuali (definiti mediante la keyword "virtual") ci sono anche i NORMALI metodi che DIPENDONO dalla struttura dati a cui fa riferimento IL TIPO DI PUNTATORE, E NON dal TIPO dell'oggetto PUNTATO!!!! E questo e' ESATTAMENTE il tuo caso!
    Grazie per la conferma, mi sono letto molta documentazione in proposito ma immagino non sia ancora sufficiente quindi sono passato al pratico facendo dei test in C++ ... però mi sfugge ancora un concetto:
    la famosa variabile 'a' che si è ribellata al programmatore e lo sta tenendo in ostaggio per gli argomenti successivi!
    Ok che l'utilizzo delle funzioni virtuali ti permette di richiamare un metodo in base al tipo di oggetto puntato (se non erro si parla quindi di polimorfismo) ma come dice anche tu il mio caso non usa funzioni virtuali, quindi il metodo richiamato dipende dal tipo di puntatore.
    Il mio dilemma è l'accesso al valore di a. Se viene richiamato il metodo Persona::stampa() perchè il valore stampato è 99 se questo valore è relativo a Studente::a ?
    Quali dei link indicati devo leggere più approfonditamente per trovare la risposta?
  • Re: Classi derivate

    _Achille ha scritto:


    pp = ps…
    Questi sono puntatori, non costruttori di copia... l'oggetto puntato da 'ps' viene puntato anche da pp.
    Non capisco cosa vuoi dire...
  • Re: Classi derivate

    Cambia le ultime parti del codice così
    
    	pp->a = 10;
    	cout << "pp " << (Persona *)pp << endl;
    	ps->a = 99;
    	cout << "ps " << (Studente *)ps << " ps->a " << ps->a << endl;
    
    	pp = ps;
    	cout << "pp " << (Persona *)pp << " pp->a " << pp->a << endl;
    	
    	return 0;
    
    e ti renderai conto che dopo pp = ps; esiste solo il puntatore a Studente.
  • Re: Classi derivate

    oregon ha scritto:


    Cambia le ultime parti del codice così
    e ti renderai conto che dopo pp = ps; esiste solo il puntatore a Studente.
    Provo subito!
  • Re: Classi derivate

    Ho deciso di fare come gli struzzi !
    Non ho parole !

    struzzo.jpg
    struzzo.jpg

  • Re: Classi derivate

    zio_mangrovia ha scritto:


    _Achille ha scritto:


    pp = ps…
    Questi sono puntatori, non costruttori di copia... l'oggetto puntato da 'ps' viene puntato anche da pp.
    Non capisco cosa vuoi dire...
    Innanzitutto non interverrebbe nessun costruttore ma l’operatore =, implicitamente definito sia per lvalue reference che per rvalue della stessa classe (e quindi non definito per un lvalue Studente).

    Secondo devi capire che un conto è un valore statico che effettivamente appartiene ad una classe, e un conto è una variabile d’istanza che dipende appunto dall’istanza stessa. Se scrivi: [CODE] Persona *pPersona = new Persona; Studente *pStudente = new Studente; // notare dichiarazione e inizializzazione insieme // e nessun uso di NULL aka (void *)0, in C++ si usa nullptr pStudente->varIstanza = 5; pPersona = pStudente; Allora è abbastanza chiaro che:
    1. Hai commesso un errore di memory leak
    2. Ora pPersona punta ad un oggetto pStudente, e tramite l’operatore -> può accedere ai campi comuni tra i due (in questo caso varIstanza è il tuo a) e varIstanza vale appunto 5.
  • Re: Classi derivate

    _Achille ha scritto:


    [CODE] Persona pPersona = new Persona; Studente pStudente = new Studente; // notare dichiarazione e inizializzazione insieme // e nessun uso di NULL aka (void *)0, in C++ si usa nullptr pStudente->varIstanza = 5; pPersona = pStudente;
    Grazie delle delucidazioni, ma non ho chiaro queste prime righe:
    Persona pPersona = new Persona;
    Studente pStudente = new Studente;
    destra dell'uguale viene restituito un puntatore ad una classe mentre a sinistra abbiamo un oggetto di tipo class, come è possibile?
    Non dovrebbe esserci a sinistra anche un asterisco per indicare che trattasi di un puntatore a class?
  • Re: Classi derivate

    migliorabile ha scritto:


    La cosa si complica in C++ perche' OLTRE a metodi virtuali (definiti mediante la keyword "virtual") ci sono anche i NORMALI metodi che DIPENDONO dalla struttura dati a cui fa riferimento IL TIPO DI PUNTATORE, E NON dal TIPO dell'oggetto PUNTATO!!!! E questo e' ESATTAMENTE il tuo caso!
    Nelle ultime righe tu assegni a "pp" un oggetto di tipo Studente, MA il puntatore e' di tipo PERSONA. "pp->a" stampa 99, perche' stai usando l'oggetto che in "a" contiene 99, MA usi il metodo della classe Persona perche' il metodo NON E" virtuale e il puntatore e' un puntatore A Persona!
    Spiegazione a dir poco eccellente. Grazie
  • Re: Classi derivate

    zio_mangrovia ha scritto:


    _Achille ha scritto:


    [CODE] Persona pPersona = new Persona; Studente pStudente = new Studente; // notare dichiarazione e inizializzazione insieme // e nessun uso di NULL aka (void *)0, in C++ si usa nullptr pStudente->varIstanza = 5; pPersona = pStudente;
    Grazie delle delucidazioni, ma non ho chiaro queste prime righe:
    Persona pPersona = new Persona;
    Studente pStudente = new Studente;
    destra dell'uguale viene restituito un puntatore ad una classe mentre a sinistra abbiamo un oggetto di tipo class, come è possibile?
    Non dovrebbe esserci a sinistra anche un asterisco per indicare che trattasi di un puntatore a class?
    Ops mio errore, correggo
Devi accedere o registrarti per scrivere nel forum
13 risposte