Array di oggetti c++

di il
15 risposte

Array di oggetti c++

Salve a tutti. Ho iniziato la programmazione a oggetti in c++. Ho studiato il concetto di definizione di una classe, information hiding, inizializzazione dei dati membro con costruttori (di default, per copia, e alternativo cioè con parametri), distruttori. Ora ho cercato di svolgere un esercizio semplice che recita così:

Creare una classe chiamata impiegato che contenga come membri dato il nome e il numero di impiegato, e come funzioni membro Leggeredati() e Vederedati(); la prima legge i dati dalla tastiera e la seconda li visualizza sullo schermo. Scrivere un programma che utilizzi la classe, creando un array di tipo impiegato e poi riempiendolo con i dati corrispondenti a 50 impiegati. Una volta riempito l'array, visualizzare i dati di tutti gli impiegati.

Il problema è molto semplice. Ho fatto ciò che mi chiede l'esercizio - anche se nel mio esercizio ho evitato di fare un array di 50 elementi ma ne ho messo solo 5 - ma nel momento in cui finisco di inserire i dati del secondo impiegato, il programma termina con una serie di valori messi a caso. CIoè acquisisce correttamente solo il primo impiegato. Trattando di un array, e non di 5 oggetti indipendenti può darsi che abbia mancato qualcosa? Sintatticamente il compilatore non mi dà nessun errore! Incollo il codice:

#include <iostream>

using namespace std;

class impiegato {
      private:
             char nome[20];
             int numimpiegato;
      public:
             void Leggeredati();
             void Vederedati();
};

void impiegato :: Leggeredati()
{
      cin.getline (nome,20);
      cin >> numimpiegato;
}
  
void impiegato :: Vederedati ()
{
      cout << nome << endl;
      cout << numimpiegato << endl;
}

int main ()
{   
    impiegato a[5];
    
    for (int i=0; i<5; i++)
    {
         cout << "Digita nome e numero impiegato " << i+1 << " :" << endl;
         a[i].Leggeredati();
    }
    
    for (int i=0; i<5; i++)
    {
         cout << endl << endl;
         a[i].Vederedati();
    }
        
    cout << endl << endl;  
    system ("PAUSE");
    return 0;
}

15 Risposte

  • Re: Array di oggetti c++

    
    void impiegato :: Leggeredati()
    {
          cin.getline (nome,20);
          cin >> numimpiegato;
          cin.ignore(256,'\n');
    }
    
  • Re: Array di oggetti c++

    Quindi dovevo svuotare il buffer! Skynet puoi dirmi se è preferibile usare la cin.sync() o cin.ignore come hai fatto tu? Perchè ho provato con cin.sync e funziona lo stesso. Poi perchè hai messo 256, ignora 256 caratteri? Grazie.
  • Re: Array di oggetti c++

    Sync scarta tutti i caratteri non letti, con ignore puoi specificare quanti ne vuoi scartare. A te la scelta. 256 era il primo numero che mi è venuto in mente. Lo stream scarta o fino a 256 caratteri o fino a quando non trova un '\n' (quel che trova prima insomma).
  • Re: Array di oggetti c++

    Grazie skynet. Sto prendendo confidenza con gli oggetti, e svolgendo un altro esercizio non riesco a far partire una funzione. L'esercizio dice:

    Creare una classe che abbia membri dato di tipo int per ore, minuti e secondi. Un costruttore inizializzerà questi dati a 0, mentre un altro li inizializzerà a valori predefiniti. Una funzione membro dovrà visualizzare l'ora nel formato 11:59:59. Un'altra funzione membro sommerà due oggetti di tipo ora passati come argomenti. Una funzione principale main () deve creare due oggetti inizializzati e un terzo non inizializzato. Sommare i due valori inizializzati e lasciare il risultato nell'oggetto non inizializzato. Da ultimo visualizzare il valore risultante.

    Da quanto ho capito io devo creare un oggetto non inizializzato g che ovviamente avrà il formato dell'ora 0:0:0. E altri due oggetti inizializzati che chiamo s e t inizializzati a certi valori. Ad esempio:

    ora g;
    ora s(10,5,4);
    ora t(20,10,9);
    faccio la somma delle ora minuti e secondi di s e t (30, 15, 9), l'associo all'oggetto g e poi visualizzo 30:15:9. Il problema sta nella funzione che dovrebbe sommare i costruttori dei due oggetti. Ho provato a farlo ma escono degli errori. Avevo pensato si potesse fare con un costruttore di copia ma l'esercizio mi chiede esplicitamente di sviluppare una funzione specifica. Comunque ora incollo il codice, magari mi dici dove sta l'errore:
    
    #include <iostream>
    
    using namespace std;
    
    class ora {
          private:
                 int ore;
                 int minuti;
                 int secondi;
          public:
                 ora();
                 ora(int a, int b, int c);
                 void visualizzare_data();
                 void somma_oggetti (ora p, ora s);
    };
    
    ora :: ora() // costruttore che inizializza a 0 tutti i dati membro
    {
          ore=0;
          minuti=0;
          secondi=0;
    }
      
    ora :: ora (int a, int b, int c) /* costruttore che inizializza a certi valori le variabili ore,
                                        minuti e secondi */
    {
          ore=a;
          minuti=b;
          secondi=c;
    }
    
    void ora :: visualizzare_data() // Visualizza ora come ore:minuti:secondi
    {
         cout << ore << ":" << minuti << ":" << secondi << endl;
    }
    
    void ora :: somma_oggetti (ora p, ora s) // Dovrebbe sommare due oggetti
    {
         int h=p.ore+s.ore;
         int m=p.minuti+s.minuti;
         int se=p.secondi+s.secondi;
    }
    
    int main ()
    {   
        ora g; // oggetto non inizializzato
        
        ora s(10,5,4); // due oggetti inizializzati
        ora t(20,10,9);
        
        g=g.somma_oggetti(s,t);
        cout << "L'ora di g risulta -> ";
        g.visualizzare_data();
           
        cout << endl << endl;  
        system ("PAUSE");
        return 0;
    }
    
  • Re: Array di oggetti c++

    Questo è l'inizializzator, quello che stai facendo tu è assegnazione
    
    ora :: ora() // costruttore che inizializza a 0 tutti i dati membro
    : ore(0)
    , minuti(0)
    , secondi(0)
    {
    }
    
    anche quì:
    
    ora :: ora (int a, int b, int c) /* costruttore che inizializza a certi valori le variabili ore,
                                        minuti e secondi */
    : ore(a)
    , minuti(b)
    , secondi(c)
    {
    }
    
    l'errore tuo sta quà:
    g=g.somma_oggetti(s,t); come vedi tu ritorni una classe ti tipo ora tramite la funzione somma_oggetti ma sta funzione è definita come void. la soluzione potrebbe essere:
    
    ora & ora :: somma_oggetti (ora p, ora s) // Dovrebbe sommare due oggetti
    {
         ore = p.ore+s.ore;
         minuti = p.minuti+s.minuti;
         secondi = p.secondi+s.secondi;
        return *this;
    }
    
    Non è un codice provato quindi potrebbero essere dei errori. Anzi gli errori ci sono perche non hai accesso ai membri privati delle classi p ed s. Quindi devi fare tre getter del tipo:
    
    int ora::getHour(void)
    {
       return ore;
    }
    
    int ora::getMinute(void)
    {
       return minuti;
    }
    
    int ora::getSeconds(void)
    {
       return secondi;
    }
    
    
    la tua funzione diventerebbe:
    
    ora & ora :: somma_oggetti (ora p, ora s) // Dovrebbe sommare due oggetti
    {
         ore = p.getHour()+s.getHour();
         minuti = p.getMinute()+s.getMinute();
         secondi = p.getSeconds()+s.getSeconds();
        return *this;
    }
    
  • Re: Array di oggetti c++

    Infatti io l'avevo pensato che la funzione prendendo due oggetti di tipo ora restituisse anche il tipo ora però poi ho messo void perchè non capivo cosa volesse dirmi il compilatore nel messaggio di errore che generava quando scrivevo il seguente prototipo nella classe:
    ora somma_oggetti (ora p, ora s);
    invece devo mettere la &;
    ora & somma_oggetti (ora p, ora s);
    Voglio farti alcune domande perchè ho aggiustato come mi ha suggerito e funziona il programma, ma non ho capito alcune cose. Perchè si mette la & dopo che ho specificato il tipo di ritorno ora. La & è un "riferimento al tipo"?
    Ad esempio se io scrivo:
    int n=75;
    int& r=n;
    cout << r << n;
    io ottengo due valori uguali per r ed n. In altre parole io creo un sinonimo di n ma r ed n sono la stessa variabile! Vale lo stesso per gli oggetti? scrivendo ora& sto creando un riferimento al tipo ora, un alias? E perchè? Per il fatto che è definito nella classe?

    2 domanda: La funzione ha un'espressione che non ho ancora studiato: return *this. Che significa? Informandomi, ho letto che this è un puntatore alla classe ( nome_classe *this) quindi mi viene da pensare che return *this mi ritorna il tipo ora, giusto? Sicuramenti this si utilizza per gestire le eccezioni (cosa che non ho visto ancora) ma restando nell'ambito delle classi e dell'OOP, serve per altre cose? Grazie mille ancora.
  • Re: Array di oggetti c++

    Allora inizia dal main.
    
    ora g; // oggetto non inizializzato, in realtà crea l'oggetto con tutti i membri = 0
    ....
    
    g=g.somma_oggetti(s,t);
    stai dicendo a g di aggiornare i suoi variabili e di farti tornare l'oggetto ora ( g ) in una variabile di tipo ora. Casualmente (o perche l'hai voluto) lo stai faccendo ritornare alla stessa variabile. Siccome non hai definito l'operatore = (che sta x assegnazione) dentro la classe ora, il compilatore ti ha creato uno per te. Nel tuo caso va bene ma ci sono casi in quì conviene definire tu stesso l'operatore di assegnazione.
    
    Tornando a noi.
    
    ora & ora :: somma_oggetti (ora p, ora s)
    
    ti ritorna una classe per riferimento (alias della classe ora).
    la parola chiave this sta a indentificare la classe stessa in cui ci troviamo quindi per far tornare la nostra classe x riferimento (operatore & definito nella dichiarazione della funzione) dobbiamo far tornare *this che nel aritmetica dei puntatori sarebbe *(ora * const). Quindi facilitandoti il compito, pensa la classe "ora" come un int *. Supponiamo che la funzione fosse definita così:
    
    (int *) & somma_oggetti(int *p, int *s)
    
    il return *this si traduce in *(int *).
    int *a = (int *) & somma_oggetti(int p, int s) si traduce in:
    int *a = &*(int *) <==> int *a = (int *). E' un pò complicato ma ci farai l'abbitudine.
    In pocche parole:
    *this ritorna la classe stessa x riferimento.

    Per concludere ha + senso dichiarare la funzione somma_oggetti così:
    
    ora & ora :: somma_oggetti (const ora & p, const ora & s)
    
    Questo per 2 motivi:
    1. non stai modificando le varibili p ed s e quindi è meglio specificare il const
    2. passa le varibili per riferimento così il compilatore non esegue una copia temporanea delle stesse faccendoti guadagnare in velocità di esecuzione.

    Edit: ho sbagliato l'esempio. Adesso dovrebbe essere corretto.
  • Re: Array di oggetti c++

    Skynet un'altra perplessità, tu dici:
    Non è un codice provato quindi potrebbero essere dei errori. Anzi gli errori ci sono perche non hai accesso ai membri privati delle classi p ed s. Quindi devi fare tre getter del tipo:

    Perchè non ho accesso ai membri privati della classe. Gli oggetti che ho definito (non creati perchè di per sè la classe non alloca nessuna memoria, solo quando definisco un'istanza della classe creo un oggetto e alloco memoria) fanno parte della stessa classe e quindi per definizione io ho accesso sia a membri pubblici che privati della classe. Perchè c'è bisogno dei getter? Tra parentesi anche senza getter il compilatore non mi dà nessun warning sul fatto che non possa accedere a membri privati e il programma parte bene. Se fosse scorretto il compilatore non me lo dovrebbe segnalare? Grazie
  • Re: Array di oggetti c++

    Ho fatto un altro esercizio e funziona, però vorrei capire, sentendo il tuo parere, se stilisticamente e da un punto di vista logico sia scritto in modo esatto. Secondo me no! E poi ti spiego perchè. La traccia è questa:

    Si vuole realizzare una classe vettore3d che permetta di manipolare vettori di tre coordinate x, y e z secondo le seguenti regole:

    1. Ci sarà solo una funzione costruttore e sarà in linea
    2. Ci sarà una funzione membro uguale che permette di sapere se due vettori hanno le loro componenti o coordinate uguali. La dichiarazione di uguale si realizzerà utilizzando: a) trasmissione per valore; b) trasmissione per indirizzo; c) trasmissione per riferimento.

    Ora lasciando stare per un attimo le varie modalità di trasmissione, e dicendoti che nel programma che ho fatto non ho messo i getter, come nel precedente, il codice che ho scritto è questo:
    
    #include <iostream>
    
    using namespace std;
    
    class vettore3d {
          private:
                 int x;
                 int y;
                 int z;
          public:
                 vettore3d(int a, int b, int c);
                 bool uguale (const vettore3d &p, const vettore3d &s);
    };
    
    inline vettore3d :: vettore3d (int a, int b, int c) : x(a), y(b), z(c) {}
    
    bool vettore3d :: uguale (const vettore3d &p, const vettore3d &s)
    {
            if ((p.x==s.x) && (p.y==s.y) && (p.z==s.z))
            return true;
            else return false;
    }
    
    int main ()
    {   
        int a, b, c, d, e ,f;
        
        cout << "Coordinata x, y e z primo vettore: ";
        cin >> a >> b >> c;
        cout << "Coordinata x, y e z secondo vettore: ";
        cin >> d >> e >> f;
        
        vettore3d primo(a,b,c);
        vettore3d secondo(d,e,f);
        vettore3d risultato(0,0,0);
        
        if (risultato.uguale(primo,secondo))
        cout << endl << "I vettori sono uguali";
        else
        cout << endl << "I vettori sono diversi";
           
        cout << endl << endl;  
        system ("PAUSE");
        return 0;
    }
    
    Come già detto, il programma scritto in questo modo funziona! Ma da quanto ho imparato un programma che funziona non necessariamente è scritto per bene. E i miei dubbi nascono proprio nel main, perchè per quanto concerne la classe e i metodi secondo me sono scritti bene, a parte il fatto di non aver utilizzato i getter perchè vorrei capirli un pò meglio (vd post precedente). Nel main io dichiaro due oggetti primo e secondo e gli passo dei parametri. E fin qui no problem...Poi dichiaro un terzo oggetto di "appoggio" per poter accedere ai membri, o meglio alla funzione membro uguale. Il fatto è che il programma funziona anche se invece di risultato.uguale(primo,secondo) nell'if scrivo primo.uguale(primo,secondo) oppure secondo.uguale(primo,secondo). Perchè?
  • Re: Array di oggetti c++

    Si vede che ero cotto. Tu stai aggendo con oggetti appartenenti alla stessa classe quindi non hai bisogno dei getter perche la classe stessa può accedere ai suoi membri privati. Chissà cosa pensavo cmq il tuo raggionamento è corretto. Prova questo programma e vedrai cosa intendevo io.
    
    #include <iostream>
    
    using namespace std;
    
    class vettore3d {
    private:
    	int x;
    	int y;
    	int z;
    public:
    	vettore3d(int a, int b, int c);
    };
    
    inline vettore3d :: vettore3d (int a, int b, int c) : x(a), y(b), z(c) {}
    
    bool uguale (const vettore3d &p, const vettore3d &s)
    {
    	if ((p.x==s.x) && (p.y==s.y) && (p.z==s.z))
    		return true;
    	else return false;
    }
    
    int main ()
    {   
    	int a, b, c, d, e ,f;
    
    	cout << "Coordinata x, y e z primo vettore: ";
    	cin >> a >> b >> c;
    	cout << "Coordinata x, y e z secondo vettore: ";
    	cin >> d >> e >> f;
    
    	vettore3d primo(a,b,c);
    	vettore3d secondo(d,e,f);
    	vettore3d risultato(0,0,0);
    
    	if (uguale(primo,secondo))
    		cout << endl << "I vettori sono uguali";
    	else
    		cout << endl << "I vettori sono diversi";
    
    	cout << endl << endl; 
    	system ("PAUSE");
    	return 0;
    }
    
    
    adesso la funzione uguale è una funzione fuori dalla classe e non hai accesso ai membri privati. Siccome non ho provato il codice di prima intendevo questo come caso generico ma ribadisco il tuo concetto è corretto. Se stai aggendo nella stessa classe hai accesso ai membri private com'è giusto che sia.
  • Re: Array di oggetti c++

    Puoi invece scrivere l'operatore == nella tua classe e fare le comparazione nel if senza creare un terzo oggetto x il risultato.
    
    #include <iostream>
    
    using namespace std;
    
    class vettore3d {
    private:
    	int x;
    	int y;
    	int z;
    public:
    	vettore3d(int a, int b, int c);
    	bool operator==(const vettore3d & rhs)
    	{
    		return (x == rhs.x) && (y == rhs.y) && (z == rhs.z);
    	}
    };
    
    inline vettore3d :: vettore3d (int a, int b, int c) : x(a), y(b), z(c) {}
    
    int main ()
    {   
    	int a, b, c, d, e ,f;
    
    	cout << "Coordinata x, y e z primo vettore: ";
    	cin >> a >> b >> c;
    	cout << "Coordinata x, y e z secondo vettore: ";
    	cin >> d >> e >> f;
    
    	vettore3d primo(a,b,c);
    	vettore3d secondo(d,e,f);
    	
    	if (primo == secondo)
    		cout << endl << "I vettori sono uguali";
    	else
    		cout << endl << "I vettori sono diversi";
    
    	cout << endl << endl; 
    	system ("PAUSE");
    	return 0;
    }
    
    
  • Re: Array di oggetti c++

    
    Il fatto è che il programma funziona anche se invece di risultato.uguale(primo,secondo) nell'if scrivo primo.uguale(primo,secondo) oppure secondo.uguale(primo,secondo). Perchè?
    
    Il programma funziona perche tu stai usando una funzione della classe x comparare due oggetti di tipo classe (non neccessariamente primo e secondo) e sta funzione ti ritorna un bool. vedi il caso di questo codice:
    
    if (risultato.uguale(primo,secondo))
    
    tu stai usando la funzione dell'istanza risultato della classe vector3d e sta funzione sta comparando due oggetti passati come parametro. E' corretto come codice (non da errori) ma non è il modo giusto per farlo. E' come se io usassi un oggetto di appoggio se voglio comparare due oggetti tra di loro. Infine definendo l'operatore == dentro la classe tutto diventa naturale.
    if(primo == secondo) . non hai bisogno di una funzione che fa le comparazioni in quanto l'operatore è già una funzione adibito a quello scopo.
  • Re: Array di oggetti c++

    Ti faccio notare anche che questi due pezzi di codice sono equivalenti:
    
    
    class vettore3d {
          private:
                 int x;
                 int y;
                 int z;
          public:
                 vettore3d(int a, int b, int c);
    };
    
    inline vettore3d :: vettore3d (int a, int b, int c) : x(a), y(b), z(c) {}
    
    e
    
    class vettore3d {
    private:
    	int x;
    	int y;
    	int z;
    public:
    	vettore3d(int a, int b, int c) : x(a) , y(b) , z(c)	{};
    };
    
    un costructor sviluppato nella classe stessa è uguale allo sviluppo del constructor fuori dalla classe dichiarandolo come inline.
    Infine la direttiva inline è un suggerimento x il compilatore che può bennissimo fregarsene perche si crede più sveglio del programmatore quindi non bisogna fare riferimento.
  • Re: Array di oggetti c++

    Grazie skynet per le delucidazioni. Per quanto riguarda il costruttore definito con la parola chiave inline o meno, questa cosa al sapevo ma il libro dice che quando metto inline è più "sicuro" che il compilatore la tratterà effettivamente come inline, piuttosto che svilupparla all'interno della classe, ma queste evidentemente sono questioni di lana caprina. Invece per la ridefinizione degli operatori è abb. chiaro anche se devo guardarmi per bene l'argomento dato che in quasi tutti i manuali, le eccezioni e l'overloading sono argomenti che rientrano nella parte "avanzata" del linguaggio. Piuttosto svolgendo un altro esercizio in cui bisogna definire una funzione "amica" della classe, c'ho una perplessità. Ora incollo il codice:
    
    #include <iostream>
    
    using namespace std;
    
    class Punto {
          private:
                  int x,y;
          public:
                  Punto (int abs, int ord) // Costruttore sovraccaricato che effettua assegnazioni
                  {
                        x = abs;
                        y = ord;
                  }
                  friend void visualizzare (Punto p); /* Funzione amica della classe Punto. In
                                                         questo modo posso accedere ai membri privati
                                                         ella classe, e trattarla come fosse una 
                                                         funzione indipendente. */
    };
    
    void visualizzare (Punto p)
    {
         cout << "Le coordinate del punto sono (" << p.x << ", " << p.y << ")";
    }
    
    int main ()
    {
        int a, b;
        cout << "Inserisci le coordinate x e y: " << endl;
        cin >> a >> b;
        Punto s(a,b); // Genero un oggetto statico di tipo Punto e gli passo le due coord. a e b
        Punto *p = new Punto(s); // Copio l'oggetto s nell'oggetto p generato dinamicamente
        
        visualizzare (*p); // Chiamo la funzione amica
        
        delete p; // Libero la memoria (chiamo il distruttore di default)
        
        cout << endl << endl;   
        system ("PAUSE");
        return 0;
    } 
    
    In pratica questo codice definisce una classe Punto con un costruttore, ed una funzione amica molto semplice che dovrebbe visualizzarmi le coordinate del punto. Poi nel main genero due oggetti, uno staticamente e l'altro dinamicamente in cui ci copio l'oggetto statico. Poi chiamo la funzione visualizzare e dealloco. Ora per definizione una funzione amica di una classe, può accedere ai suoi membri privati. Se noti alla funzione amica gli ho passato l'oggetto p. La domanda è questa: come mai il compilatore mi dà un errore se alla funzione visualizzare non gli passo nessun argomento? Io mi sono dato questa risposta ossiia che l'oggetto mi serve come mezzo per accedere ai campi della classe. Infatti se scrivessi cout << x lui mi dice x undeclared. E' così? Grazie
Devi accedere o registrarti per scrivere nel forum
15 risposte