sabato 4 ottobre 2014

I Puntatori

I Puntatori: 

02/10/2014
Cosa sono i ‘Puntatori’?
I Puntatori sono delle variabili, quindi parlando di puntatori parleremo di un nuovo tipo di variabile; da un punto di vista pratico sono delle variabili particolari perché al contrario dei tipi di variabili visti fino ad ora non contengono un dato ma un indirizzo di memoria di un'altra variabile.  
Possiamo avere puntatori a qualsiasi tipo di variabile:

Tipo variabile:                                               Tipo variabile Puntatore:
            int a;                                                   int *a;
            float b;                                                float *b;
            char c;                                                char *c;
            double d;                                            double *d;                                                                

La dichiarazione di una variabile puntatore deve includere il tipo della variabile a cui il puntatore punta.

Con i puntatori abbiamo due nuove istruzioni da utilizzare: ‘&’ e ‘*’
L' operatore & fornisce l'indirizzo di una variabile:
             a=b;   //non posso assegnare ad “a” il contenuto di “b” perché “a” è una variabile di tipo
             puntatore mentre “b” è una variabile di tipo intero
            a=&b;   //assegna al puntatore a l’indirizzo di b
L' operatore * da' il contenuto dell'oggetto a cui punta un puntatore.
            a=&b;
            Cout<<”   “ <<*a<<endl;   //visualizzerà il dato contenuto all’indirizzo a cui punta la variabile
            a;

Vediamo un esempio pratico:

#include <iostream>
using namespace std;

int main()
{
    int *a;   //dichiarazione della variabile puntatore "a"
    int b;   //dichiarazione della variabile intera "b"

    b=7;   //assegno alla variabile b il valore 7
    a=&b;   //assegno alla variabile puntatore "a" l'indirizzo della variabile intera "b"

    cout<<endl<<"Il contenuto della variabile di tipo puntatore 'a' e': "<<a<<endl<<"Il dato a cui punta la variabile di tipo puntatore 'a' e': " <<*a<<endl;  
//visualizzo in output il contenuto della variabile puntatore "a" (che sarà un indirizzo) e il dato contenuto all'indirizzo a cui punta la variabile puntatore "a" (che sarà il valore 7 assegnato alla variabile “b”)
    cout<<endl<<endl<<"Il contenuto della variabile di tipo intero 'b' e': "<<b<<endl<<"L'indirizzo della variabile di tipo intero 'b' e': " <<&b<<endl;  
//visualizzo in output il contenuto della variabile intera "b" (che sarà il valore assegnato 7) e il suo indirizzo in memoria (che nel nostro esempio sarà lo stesso contenuto nella variabile puntatore “a”)

    return 0;
}



*!* Per la macchina una variabile è il suo indirizzo in memoria
*!* I tipi delle variabili rappresentano una proprietà, una delle proprietà che rappresentano è quanto spazio occupano in memoria/quanto ne viene allocato
*!* Il puntatore contiene un indirizzo di memoria, lo spazio dipende dal tipo di architettura.
4bit = 16 indirizzi (2^4)
1 byte = 1 indirizzo
1KB di RAM = 1024 byte = 1024 indirizzi
1KB = 2^10


Fonti:
Prof. Alemanno
http://www.science.unitn.it/~fiorella/guidac/guidac025.html

mercoledì 1 ottobre 2014

Esercizio 29/09/2014 - L'Omonimia dei metodi nel campo dell'Ereditarietà Informatica

L'Omonimia dei metodi nel campo dell'Ereditarietà Informatica

Lo scopo di questa prova è quello di verificare il funzionamento dei metodi all'interno delle classi a cui viene applicato il concetto di Ereditarietà:
Scriveremo un codice molto semplice in cui da una Classe Padre di nome "Generica" ricaveremo una Classe Figlio di nome "Dettaglio"; nella Classe Padre è presente un metodo per la visualizzazione della variabile "a" chiamato "stampa()", nella Classe Figlio (ricavata con modificatore public) avremo invece un metodo per la visualizzazione di una variabile "b" chiamato "stampa1()".
Nell'esempio vedremo come dall'istanza dell'oggetto di nome "Figlio" di Classe "Dettaglio" si possa utilizzare il metodo "stampa()" ereditato e "stampa1()" specifico della nuova Classe:

#include <iostream>
using namespace std;
class Generica{   //dichiarazione della classe Padre Generica
        public:   // con public rendo i metodi accessibili dal main()
        Generica() { a=5; };   //costruttore della Classe Padre Generica
        void stampa() { cout << "Stampa da metodo Padre: " << a << endl; };   
//metodo Padre per visualizzare la variabile a
        private:   // con private rendo i metodi inaccessibili dal main()
        int a;   //dichiarazione dell'attributo intero a
        };

class Dettaglio : public Generica{   
//dichiarazione della classe Figlio Dettaglio con modificatore public dalla classe Padre Generica
        private:   // con private rendo i metodi inaccessibili dal main()
        int b;   //dichiarazione dell'attributo intero b
        public:
        Dettaglio() { b=7; };      //costruttore della Classe Figlio Dettaglio
        void stampa1()   { cout << "Stampa da metodo Figlio: " <<  b << endl; };   
//metodo Figlio per visualizzare la variabile b
        };

int main()
 {
    Dettaglio Figlio;   //istanza dell'oggetto Fiflio di Classe Dettaglio
    Figlio.stampa();   //richiamo metodo stampa Padre
    Figlio.stampa1();   //richiamo metodo stampa1 Figlio
  return 0;

}

Vediamo l'Output così ottenuto:


Come possiamo vedere, in questo caso, viene visualizzato sia l'output dato dal metodo "stampa()" dato dalla Classe Padre, sia l'output dato dal metodo "stampa1()" dato dalla Classe Figlio.
Ora con lo stesso codice andremo a modificare il nome del metodo della Classe Figlio "Dettaglio" utilizzando lo stesso nome del metodo della Classe Padre "Generica" e cioè per entrambi i metodi utilizzeremo il nome stampa():

#include <iostream>
using namespace std;
class Generica{   //dichiarazione della classe Padre Generica
        public:   // con public rendo i metodi accessibili dal main()
        Generica() { a=5; };   //costruttore della Classe Padre Generica
        void stampa() { cout << "Stampa da metodo Padre: " << a << endl; };   //metodo Padre per visualizzare la variabile a
        private:   // con private rendo i metodi inaccessibili dal main()
        int a;   //dichiarazione dell'attributo intero a
        };

class Dettaglio : public Generica{   //dichiarazione della classe Figlio Dettaglio con modificatore public dalla classe Padre Generica
        private:   // con private rendo i metodi inaccessibili dal main()
        int b;   //dichiarazione dell'attributo intero b
        public:
        Dettaglio() { b=7; };      //costruttore della Classe Figlio Dettaglio
        void stampa()   { cout << "Stampa da metodo Figlio: " <<  b << endl; };   //metodo Figlio per visualizzare la variabile b
        };

int main()
 {
    Dettaglio Figlio;   //istanza dell'oggetto Fiflio di Classe Dettaglio
    Figlio.stampa();   //richiamo metodo stampa Padre
    Figlio.stampa();   //richiamo metodo stampa Figlio
  return 0;
}

Vediamo l'Output così ottenuto:


Come evidenziato dalla nostra prova nel momento in cui esiste un metodo della Classe Padre, che viene ereditato nella Classe Figlio, se nella Classe Figlio si andrà a dichiarare un altro metodo con lo stesso nome del metodo ereditato ("stampa()" nel nostro esempio), il compilatore riterrà opportuno fare riferimento al metodo con lo stesso nome più recente e quindi quello presente all'interno della Classe Figlio; da qui l'Output che viene visualizzato produce due volte lo stesso risultato, facendo fede allo stesso metodo stampa() contenuto all'interno della Classe Figlio Dettaglio.

*!* E' importante ricordare che solo l'oggetto si trova nella memoria RAM, non la Classe

Fonti:
Prof. Alemanno

Giacomo Marchesi

domenica 28 settembre 2014

Ereditarietà

Il concetto di Ereditarietà Informatica

In informatica l'ereditarietà è uno dei concetti fondamentali, essa costituisce infatti il secondo principio fondamentale della programmazione ad oggetti.

In generale si può definire come un meccanismo che consente di creare nuove classi che siano basate su altre già definite in precedenza; a seconda del linguaggio di programmazione, l'ereditarietà può essere ereditarietà singola o semplice (ogni classe può avere al più una superclasse diretta) o multipla (ogni classe può avere più superclassi dirette).



Concetto di ereditarietà nel mondo reale:

È semplice poter osservare esempi di ereditarietà nel mondo reale. Ad esempio, esistono al mondo centinaia di tipologie diverse di mammiferi: cani, gatti, uomini, balene e così via. Ognuna di tali tipologie di mammiferi possiede alcune caratteristiche che sono strettamente proprie (ad esempio, soltanto l’uomo è in grado di parlare) mentre esistono, d’altra parte, determinate caratteristiche che sono comuni a tutti i mammiferi (ad esempio, tutti i mammiferi hanno il sangue caldo e nutrono i loro piccoli).
Nel mondo Object Oriented, potremmo riportare tale esempio definendo un oggetto Mammifero che inglobi tutte le caratteristiche comuni ad ogni mammifero. Da esso, poi, deriverebbero gli altri oggetti figlio: Cane, Gatto, Uomo, Balena, etc.
L’oggetto cane, per citarne uno, erediterà, quindi, tutte le caratteristiche dell’oggetto mammifero ma a sua volta conterrà delle caratteristiche aggiuntive, distintive di tutti i cani come ad esempio: ringhiare o abbaiare.
Il paradigma OOP, ha quindi carpito l’idea dell’ereditarietà dal mondo reale e lo stesso concetto viene applicato ai sistemi software che utilizzano tale tecnologia.
Come possiamo passare l’eredità da padre a figlio?
Abbiamo parlato di Classe Padre e Classe Figlio, l’ereditarietà consente alla classe Figlio di ereditare ogni membro della classe Padre, e poi aggiungere e modificare le cose secondo le nuove funzionalità da realizzare. Avendo la necessità di utilizzare tutti i membri di una classe padre senza doverli dichiarare di nuovo, ci basterà mettere una sola dichiarazione nell'header della classe figlio:

class pesce_rosso : public pesce
{
    ...
};

In tal caso, la classe derivata si chiama pesce_rosso. La classe base ha visibilità pubblica e si chiama pesce.

*!* Quando una classe eredita da un'altra, ne eredita tutti i membri. Questo porta a due problemi:
proteggere i membri di una classe in modo che i suoi potenziali figli non siano in grado di accederli.
far sì che una classe figlia impedisca l'accesso da parte del mondo esterno alla parte ereditata dalla sua classe padre.

Ereditarietà privata, protetta o pubblica:

Il meccanismo di ereditarietà, pur essendo abbastanza semplice, richiede una certa attenzione per non cadere in errori perchè dipende dallo standard della classe base.
Gli attibuti ed i membri che vengono ereditati dalla classe base possono cambiare la loro visibilità nella classe figlio, in base allo specificatore/modificatore d’accesso con il quale si esegue l’ereditarietà stessa, nel dettaglio:

Se lo specificatore d’accesso è public:
i public restano public
i protected restano protected
i private non possono essere trasferiti


Se lo specificatore d’accesso è private:
i public diventano private
i protected diventano private
i private non possono essere trasferiti


Se lo specificatore d’accesso è protected:
i public diventano protected
i protected restano protected
i private non possono essere trasferiti


Tabella riassuntiva:

*!* Durante l’ereditarietà un accesso può restringersi o restare uguale ma mai ampliarsi.

Esempio di codice:

#include <iostream>
using namespace std;
class persona{   //dichiarazione della classe persona
        public:   // con public rendo i metodi accessibili dal main()
        persona();   //costruttore senza passaggio di parametri
       ~persona();   //distruttore
        void visualizzaAnagrafica();   //metodo per visualizzare dati Anagrafica
        char nome[15];   //dichiarazione stringa nome
        char cognome[15];   //dichiarazione stringa cognome
        int eta;   //dichiarazione variabile eta
        };


persona::persona()   //definizione del costruttore senza passaggio di parametri
{
cout <<" Inserisci Nome: ";
cin >> nome;   //salvo l'input da utente nella stringa nome
cout << endl <<" Inserisci Cognome: ";
cin >> cognome;   //salvo l'input da utente nella stringa cognome
cout << endl <<" Inserisci eta': ";
cin >> eta;   //salvo l'input da utente nella variabile eta
cout << endl;
}

class personaEstipendio : public persona {   //creo Classe Figlio personaEstipendio da Classe Padre persona con metodo "public"
        public:
        personaEstipendio();   //costruttore personaestipendio senza passaggio di parametri
       ~personaEstipendio();   //distruttore
        void visualizzaLavorativa();   //metodo per visualizzare dati Lavorativi
        private:
        char tipoContratto[15];
        int importoStipendio;
        };

personaEstipendio::personaEstipendio()   //definizione del costruttore senza passaggio di parametri
{
cout <<" Inserisci il tipo di contratto lavorativo: ";
cin >> tipoContratto;   //salvo l'input da utente nella stringa tipoContratto
cout << endl <<" Inserisci importo stipendio: ";
cin >> importoStipendio;   //salvo l'input da utente nella variabile importoStipendio
}

void persona::visualizzaAnagrafica()   //definizione metodo visualizza della Classe Padre
{ cout << endl << " Dati dipendente: "<< nome <<" - " <<cognome <<" - " <<eta <<endl;   //visualizzo i dati inseriti dall'utente
}

void personaEstipendio::visualizzaLavorativa()   //definizione metodo visualizza della Classe Figlio
{ cout <<" Dati Contratto: tipo di Contratto "<< tipoContratto <<" Importo percepito " <<importoStipendio <<endl;   //visualizzo i dati inseriti dall'utente
}

persona :: ~persona()   //definizione del distruttore per comprendere funzionamento
{
   cout << "sono il distruttore Padre";
}

personaEstipendio :: ~personaEstipendio()   //definizione del distruttore per comprendere funzionamento
{
   cout << "sono il distruttore Figlio";
}

main()
 {
  char menu;
  do{
  cout << "PROVE DI EREDITARIETA':\nData una Classe Padre con dati anagrafici persona si crei una Classe Figlio \nche contenga anche dati lavorativi";
  cout << endl << endl;
  cout << "Inserimento da istanza oggetto Padre:";
  cout << endl << endl;
  persona anagrafica;   //istanzio l'oggetto anagrafica di classe Padre tramite costruttore senza passaggio di parametri
  cout << "Inserimento da istanza oggetto Figlio:";
  cout << endl << endl;
  personaEstipendio lavorativa;   //istanzio l'oggetto lavorativa di classe Figlio tramite costruttore senza passaggio di parametri
  cout << endl;
  cout << "Visualizzo oggetto PADRE:";
  cout << endl;
  anagrafica.visualizzaAnagrafica();   //chiamata al metodo visualizza dell'oggetto Padre anagrafica
  cout << endl;
  cout << "Visualizzo oggetto FIGLIO:";
  cout << endl;
  lavorativa.visualizzaAnagrafica();   //chiamata al metodo visualizzaAnagrafica dell'oggetto Figlio
  lavorativa.visualizzaLavorativa();   //chiamata al metodo visualizzaLavorativa dell'oggetto Figlio
  cout << endl;
        cout << "Vuoi ripetere il programma? ";
        cout << endl;
        cin >> menu;
  }while((menu=='s')||(menu=='S'));   //se l'utente non vuole ripetere il programma, fine
  cout << endl << endl << endl;
  return 0;
}