PDA

View Full Version : [c++] polimorfismo help


microinfo
18-05-2012, 18:03
raga cosa significa:
La gerarchia di classi deve inoltre fornire l’overloading degli operatori di flusso << e >>. Si vuole che l’utente possa utilizzare << e >> apparentemente in maniera polimorfa.

allora io ho fatto l'overloading di input e output normalmente su tutte le classi, ma vorrei sapere come posso fare il polimorfismo? esempio presa questa gerarchia
documento->ci
->patente
vorrei fare ad esempio nella classe patente:
ostream &operator<<(ostream& out , patente &z){
documento::<<operator();
out<<"Il numero della patente e': "<<z.num<<"ed è valida per i "<<z.tipo<<endl;
return out;
}

nel senso che quando vado a fare
patente p(23,"auto");
cout<<p;

mi stampi non solo il numero e il tipo di patente ma anche il cout dei dati nella classe documento, cioè penso questo si debba fare...
io ad esempio facevo cosi per la funzione classica print, ma ora con l'overloading non so come muovermi...

[Kendall]
20-05-2012, 11:45
raga cosa significa:
La gerarchia di classi deve inoltre fornire l’overloading degli operatori di flusso << e >>. Si vuole che l’utente possa utilizzare << e >> apparentemente in maniera polimorfa.

allora io ho fatto l'overloading di input e output normalmente su tutte le classi, ma vorrei sapere come posso fare il polimorfismo? esempio presa questa gerarchia
documento->ci
->patente
vorrei fare ad esempio nella classe patente:
ostream &operator<<(ostream& out , patente &z){
documento::<<operator();
out<<"Il numero della patente e': "<<z.num<<"ed è valida per i "<<z.tipo<<endl;
return out;
}

nel senso che quando vado a fare
patente p(23,"auto");
cout<<p;

mi stampi non solo il numero e il tipo di patente ma anche il cout dei dati nella classe documento, cioè penso questo si debba fare...
io ad esempio facevo cosi per la funzione classica print, ma ora con l'overloading non so come muovermi...

Ciao, allora in c++ gli operatori ">>" e "<<" non possono essere implementati direttamente in maniera virtuale (per sfruttare il polimorfismo) in quanto sono definite come funzioni friend della tua classe (questo perchè sono metodi che si applicano agli oggetti cin e cout e non all'istanza della tua classe, della quale necessitano solo dell'accesso ai membri privati, da questo l'impiego di friend function). Detto questo, in parte si può simulare un comportamento polimorfico definendo un metodo virtuale, per esempio un print, che fa il lavoro di stampa, e un read per la lettura, che agiscono pertanto in maniera polimorfica essendo virtuali. Fatto questo implementi per ogni classe e sottoclasse l'overloading degli operatori in questione, richiamando al loro interno le funzioni print (per l'operatore <<) e read (per l'operatore >>). In questa maniera seppur la chiamata esterna è una normale chiamata, all'interno si utilizza però una chiamata polimorfica.

Detto questo, in un caso reale, io userei direttamente i metodi print e read senza insistere nell'overloading dei due operatori in oggetto. Ancor meglio utilizzerei un metodo toString() che mi costruisce direttamente una stringa ed è pertanto decisamente più polifunzionale.

P.S: Quando implementi l'overloading dei due operatori ricordati di non passare mai l'oggetto della tua classe documento (e relative sottoclassi) per valore ma sempre per riferimento. Questa cosa è fondamentale perchè passando il metodo attuale per valore, poi il metodo formale del metodo viene costruito tramite il costruttore per copia andando a perdere tutte le informazioni aggiuntive delle sottoclassi. Passando per riferimento invece il metodo va a lavorare sulla stessa istanza del parametro attuale (con quindi tutte le informazioni aggiuntive rispetto alla classe base).

microinfo
20-05-2012, 19:19
quindi se ho capito bene tu intendi dire di fare una cosa del genere:
ad esempio per output..
classe padre:
ostream &operator<<(ostream& out , padre &z){
return z.print(out,z);
}
virtual ostream& padre::print(ostream& out, padre &z) {
return out << "Sono il padre: "<<z.nome;
}

classe figlio:
ostream &operator<<(ostream& out , figlio &z){
return z.print(out,z);
}
virtual ostream& figlio::print(ostream& out, figlio &z) {
padre::print(); //uso polimorfismo
return out << "ed io il figlio: "<<z.nome;
}

che dici dovrebbe andare?

[Kendall]
20-05-2012, 20:08
quindi se ho capito bene tu intendi dire di fare una cosa del genere:
ad esempio per output..
classe padre:
ostream &operator<<(ostream& out , padre &z){
return z.print(out,z);
}
virtual ostream& padre::print(ostream& out, padre &z) {
return out << "Sono il padre: "<<z.nome;
}

classe figlio:
ostream &operator<<(ostream& out , figlio &z){
return z.print(out,z);
}
virtual ostream& figlio::print(ostream& out, figlio &z) {
padre::print(); //uso polimorfismo
return out << "ed io il figlio: "<<z.nome;
}

che dici dovrebbe andare?

Bene o male è corretta. Dalla funzione print però elimina tra gli argomenti le istanze delle classi padre e figlio. Sono metodi di classe virtuali e non statici, quindi già si applicano alle istanze, con la sintassi che anche tu hai utilizzato (z.print(out)). Tra l'altro nell'overide del metodo virtuale, controlla la chiamata di print(...), manca qualcosa ;) ...
Per il resto, sviste a parte, mi sembra corretto.

microinfo
20-05-2012, 20:21
ho alcuni problemi:
istream &operator>>(istream& in, carta &z){
return z.set(in);
}
ostream &operator<<(ostream& out, carta &z){
return z.print(out);
}
ostream& print(ostream& out) {
out<<"Il personaggio della carta e': "<<personaggio<<" ed appartiene alla serie: "<<serie<<endl;
return out;}

istream& set(istream& in) {
cout<<"Inserisci il nome della carta: ";
in>>personaggio;
cout<<endl;
cout<<"Inserisci la serie a cui appartiene: ";
in>>serie;
return in;}

##########
class carta:public item{
friend ostream &operator<<(ostream&, carta &);
friend istream &operator>>(istream&, carta &);
public:
carta(char*,float,char*,char*);
~carta(){delete[] personaggio;delete[] serie;}

friend ostream& print(ostream&);
friend istream& set(istream&);
protected:
char* personaggio;
char* serie;
};

perchè mi dice che la classe carta non ha membro print e set?
e poi che personaggio e serie non è dichiarto nello scope (funzione print e set) :(

[Kendall]
20-05-2012, 23:12
ho alcuni problemi:
istream &operator>>(istream& in, carta &z){
return z.set(in);
}
ostream &operator<<(ostream& out, carta &z){
return z.print(out);
}
ostream& print(ostream& out) {
out<<"Il personaggio della carta e': "<<personaggio<<" ed appartiene alla serie: "<<serie<<endl;
return out;}

istream& set(istream& in) {t
cout<<"Inserisci il nome della carta: ";
in>>personaggio;
cout<<endl;
cout<<"Inserisci la serie a cui appartiene: ";
in>>serie;
return in;}

##########
class carta:public item{
friend ostream &operator<<(ostream&, carta &);
friend istream &operator>>(istream&, carta &);
public:
carta(char*,float,char*,char*);
~carta(){delete[] personaggio;delete[] serie;}

friend ostream& print(ostream&);
friend istream& set(istream&);
protected:
char* personaggio;
char* serie;
};

perchè mi dice che la classe carta non ha membro print e set?
e poi che personaggio e serie non è dichiarto nello scope (funzione print e set) :(

Perchè print e set sono dichiarate come funzioni friend, e di conseguenza non sono funzioni membro. Devi togliere quell'identificatore. Riguardo allo scope, quando definisci i metodi non indichi il loro scope,pertanto vengono considerate funzioni con scope global (nel quale personaggio e serie non sono definiti). basta definire con lo scope carta:: le funzioni, identificandole così come le funzioni membro dichiarate nella tua classe carta

microinfo
21-05-2012, 00:05
hai ragione che stupido...ora mi rimane l'ultimo problema richiamare il padre..
istream &operator>>(istream& in, carta &z){
return z.set(in);
}
ostream &operator<<(ostream& out, carta &z){
return z.print(out);
}
ostream& carta::print(ostream& out) {
item::print(out);
out<<"Il personaggio della carta e': "<<personaggio<<" ed appartiene alla serie: "<<serie<<endl;
return out;}

istream& carta::set(istream& in) {
cout<<"Inserisci il nome della carta: ";
in>>personaggio;
cout<<endl;
cout<<"Inserisci la serie a cui appartiene: ";
in>>serie;
return in;}

ecco come ho modificato, funziona :) grazie
approfitto per farti un altra domanda, riguardo il polimorfismo, non ho ben capito a che serve usare virtual, io di polimorfismo mi limito solo a richiamare ad esempio una stessa funzione del padre nel figlio cosi item::print(out); (sempre se questo è polimorfismo) altro non so..

[Kendall]
21-05-2012, 00:34
hai ragione che stupido...ora mi rimane l'ultimo problema richiamare il padre..
istream &operator>>(istream& in, carta &z){
return z.set(in);
}
ostream &operator<<(ostream& out, carta &z){
return z.print(out);
}
ostream& carta::print(ostream& out) {
item::print(out);
out<<"Il personaggio della carta e': "<<personaggio<<" ed appartiene alla serie: "<<serie<<endl;
return out;}

istream& carta::set(istream& in) {
cout<<"Inserisci il nome della carta: ";
in>>personaggio;
cout<<endl;
cout<<"Inserisci la serie a cui appartiene: ";
in>>serie;
return in;}

ecco come ho modificato, funziona :) grazie
approfitto per farti un altra domanda, riguardo il polimorfismo, non ho ben capito a che serve usare virtual, io di polimorfismo mi limito solo a richiamare ad esempio una stessa funzione del padre nel figlio cosi item::print(out); (sempre se questo è polimorfismo) altro non so..

No, non è questo il polimorfismo, assolutamente. Il polimorfismo implica che, se definisco una funzione virtuale, e nel momento in cui un in un puntatore o in una variabile riferimento della classe base "punto" ad una istanza della classe figlio, ilmetodo invocato è comunque quello della classe figlio. Esempio:


Base * oggetto = new Derived();
oggetto->show();


Se Base è la classe base e Derived, ovviamente, la derivata e se show è un metodo virtuale, in questo caso pur essendo oggetto un puntatore a Base, verrà richiamato l'override della funzine virtuale definita in Derived. L'argomento comunque merita un approfondimento quindi ti consiglio di leggerti della documentazione e/o un libro

microinfo
21-05-2012, 08:38
E quindo come dovrebbe esser modificato questo codice per far vedere luso del polimorfismo? facendo un chiamata con i puntatori nel main? Poi un altra cosa se ho la geranchia base-> figlio e mi chiede di creare un altra classe x che gestisca un vettore di elementi figlio, perche se scrivo nei membri privato di classe x: figlio v .m da errore? Dice che non e un tipo valido?

[Kendall]
21-05-2012, 09:49
E quindo come dovrebbe esser modificato questo codice per far vedere luso del polimorfismo? facendo un chiamata con i puntatori nel main? Poi un altra cosa se ho la geranchia base-> figlio e mi chiede di creare un altra classe x che gestisca un vettore di elementi figlio, perche se scrivo nei membri privato di classe x: figlio v .m da errore? Dice che non e un tipo valido?

Il codice delle due classi non va modificato (quello che ti ho consigliato di fare finora era proprio per simulare il polimorfismo nell'overload degli operatori >> e <<. Se vuoi vedere in opera il polimorfismo ti basta fare un semplice test dal tuo metodo main:

#include "padre.h"
#include "figlio.h"
#include <ostream>

int main() {
Padre * p[2];
p[0] = new Padre();
p[1] = new Figlio();

// Poliformismo della chiamata di print()
p[0]->print(cout); // (1)
p[1]->print(cout); // (2)
// Simulazione di polimorfismo dell'operatore <<
cout << *p[0]; // (3)
cout << *p[1]; // (4)
}

In questa maniera la chiamata 1 e 3, se hai fatto tutto giusto, dovrebbero stamparti il padre, mentre la 2 e la 4 il figlio.
La tua seconda domanda invece non l'ho ben capita, magari prova a postare il "codice incriminato".

microinfo
21-05-2012, 14:54
grazie per l'aiuto che mi stai dando ma continuo a non capire...
questo è come mi hai detto tu..

figurina *a= new figurina("calciatori",12.50,"cavani",1,false,false); //figlio1
figurina *b= new figurina("calciatori",12.50,"pato",3,false,false); //figlio2

inserisco i due figli
// cin>>*a;
//cin>>*b;
stampo i due figli
cout<<*a;
cout<<*b;
ma anche facendo cosi funziona tutto..

figurina a("calciatori",12.50,"cavani",1,false,false); //figlio1
figurina b("calciatori",12.50,"pato",3,false,false); //figlio2

inserisco i due figli
// cin>>a;
//cin>>b;
stampo i due figli
cout<<a;
cout<<b;

forse con il polimorfismo devo agire sempre sui puntatori?

[Kendall]
21-05-2012, 15:12
grazie per l'aiuto che mi stai dando ma continuo a non capire...
questo è come mi hai detto tu..

figurina *a= new figurina("calciatori",12.50,"cavani",1,false,false); //figlio1
figurina *b= new figurina("calciatori",12.50,"pato",3,false,false); //figlio2

inserisco i due figli
// cin>>*a;
//cin>>*b;
stampo i due figli
cout<<*a;
cout<<*b;
ma anche facendo cosi funziona tutto..

figurina a("calciatori",12.50,"cavani",1,false,false); //figlio1
figurina b("calciatori",12.50,"pato",3,false,false); //figlio2

inserisco i due figli
// cin>>a;
//cin>>b;
stampo i due figli
cout<<a;
cout<<b;

forse con il polimorfismo devo agire sempre sui puntatori?

Beh così ti credo che è uguale perchè usi comunque due puntatori a classe figlio (figurina). Piuttosto dichiara quei puntatori come puntatori alla classe padre. Se la classe padre è per esempio Item fai così:

Item * a = new figurina("calciatori",12.50,"cavani",1,false,false); //figlio1
Item * b = new Item( /* e qui inserisci i parametri per il suo costruttore */);

vedrai che chiamando il cout su a e b:

cout << *a;
cout << *b;

pur essendo a e b puntatori di tipo Item, nel primo caso stamperà la stringa corretta per l'istanza figurina, mentre nel secondo caso ti stamperà quella per l'istanza Item (questo è il polimorfismo! riassumento in maniera molto stringata).

Comunque ti consiglio di leggerti della documentazione (per esempio Thinking in C++ di Eckel che è gratuito) per avere una panoramica generale sul polimorfismo (e che ovviamente io faccio fatica a riassumerti in maniera precisa in poche righe di post).

microinfo
21-05-2012, 15:45
ok grazie, io l'ho studiato dal deitel&deitel e savy ma non ci ho capito molto, proverò su questo altro libro ;)
per quanto rigurarda il vettore?
praticamnte l'esercizio mi dice di creare la gerarchia

item->figurina

e poi definire una classe album che gestisce un vettore i figurine dinamico, ma quando vado a mettere nel privete di album: figurina *vet, mi dice che non è un tipo figurina , ho anche provato a fare figurina friend class album , ma niente coma mai? forse perchè è una classe figlio?

[Kendall]
21-05-2012, 15:54
ok grazie, io l'ho studiato dal deitel&deitel e savy ma non ci ho capito molto, proverò su questo altro libro ;)
per quanto rigurarda il vettore?
praticamnte l'esercizio mi dice di creare la gerarchia

item->figurina

e poi definire una classe album che gestisce un vettore i figurine dinamico, ma quando vado a mettere nel privete di album: figurina *vet, mi dice che non è un tipo figurina , ho anche provato a fare figurina friend class album , ma niente coma mai? forse perchè è una classe figlio?


Prova a postarmi l'header della classe album e vediamo, perchè così è un po' confuso.

microinfo
21-05-2012, 19:38
kendall questa è la traccia che sto cercando di svolgere..

Si realizzi in C++ una gerarchia Item-Carta-Figurina, la classe Item rappresenta un elemento da collezione, e può essere specializzato in una carta da playset o in una figurina adesiva. La classe Item contiene le seguenti variabili membro:
- Collezione, stringa di caratteri allocata dinamicamente, titolo della collezione
Prezzo, numero reale rappresentante il costo unitario (ad esempio di una bustina)
La classe Carta aggiunge le variabili membro:
- Personaggio, stringa di caratteri allocata dinamicamente (ad esempio: Sommo Luminescente)
Serie, stringa allocata dinamicamente (ad esempio: Oro)
La classe Figurina aggiunge le variabili membro:
- Descrizione, stringa allocata dinamicamente, soggetto della figurina (ad esempio Cavani)
- Numero, intero rappresentante il numero della figurina
bool Presente, indica se la figurina è presente o mancante nella specifica collezione
bool Doppione, indica se la figurina è un doppione per la specifica collezione

Tutte le classi devono prevedere gli opportuni costruttori, distruttori e devono gestire correttamente l’estensione dinamica attraverso le opportune funzionalità. Devono inoltre fornire l’overloading degli operatori di flusso << e >>. Si vuole che l’utente possa utilizzare << e >> apparentemente in maniera polimorfa.
La classe Figurina deve fornire una funzione membro Acquisisci_Fig che fornito in ingresso il numero della figurina modifica lo stato controllando se la figurina e doppione o meno nella collezione, se la figurina manca pone la variabile membro presente a true, se invece è doppione pone la variabile membro Doppione a true.
Si realizzi quindi la classe Album, contenente oggetti di tipo Figurina. La classe Album contiene le seguenti variabili membro:
- Editore, stringa di caratteri allocata dinamicamente, editore della collezione
Collezione, stringa di caratteri allocata dinamicamente, nome della collezione
Num, intero rappresentante il numero di figurine presenti nella collezione
A, vettore di elementi di tipo figurina allocato dinamicamente (conterrà tanti elementi quanti indicati da Num)
La classe Album deve prevedere gli opportuni costruttori, il distruttore e in generale le funzionalità necessarie ad una corretta gestione dell’estensione dinamica ed inoltre deve contenere le funzioni:
Devono inoltre essere forniti gli overloading delle funzioni [] e le funzioni membro:
- Visualizza_Mancanti che consente la stampa a video di tutte le figurine mancanti dell’album
Stampa_Mancanti che consente la stampa su file di tipo testo di tutte le figurine mancanti dell’album
Gli operatori [] lanciano una eccezione di tipo bad_access nel caso si tenti di accedere ad una posizione non valida. La classe bad_access è fornita dallo studente ed oltre al messaggio di errore fornisce anche l’informazione relativa al valore dell’indice che ha provocatol’errore.
Si scriva un opportuno programma per il test delle classi realizzate, il programma definisca un oggetto di tipo Album e lo inizializzi assegnando agli elementi del vettore un certo numero di figurine (si assegni all’indice i la figurina di numero i). Si noti che la sessione di scrittura su file viene gestita dalla funzione Stampa_Mancanti della classe Album che definisce la variabile di tipo stream. La funzione memorizza_Dati si limita a riceverla come parametro di ingresso.
Si strutturi il codice secondo le appropriate tecniche di programmazione modulare illustrate durante il corso e nei libri di testo adottati.

non capisco perchè non riesco a creare il vettore di figurine

microinfo
21-05-2012, 19:45
class album{
public:
album(char*,char*,int);
~album(){delete[] editore;delete[] collezione;}
void visua_mancanti();
void stampa_mancanti();
int getnum(){return num;}
int &operator[](int);
private:
char* editore;
char* collezione;
int num;
figurina *fig; //cerco di creare il vettore ma mi dice figurina non è un tipo
};

microinfo
22-05-2012, 15:57
secondo te da cosa dipende?

[Kendall]
22-05-2012, 16:30
secondo te da cosa dipende?

Hai aggiunto tramite include l'header della classe figurina?

microinfo
22-05-2012, 20:38
si
#include <iostream>
#include <string.h>
#include "figurina.h"
using namespace std;

class album{
friend class figurina;
public:
album(char*,char*,int);
~album(){delete[] editore;delete[] collezione;}
void visua_mancanti();
void stampa_mancanti();
int getnum(){return num;}
int &operator[](int);
private:
char* editore;
char* collezione;
int num;
figurina fig; //vettore allocato din
};
#########
#include <iostream>
#include <string.h>
#include "album.h"
#include "item.h"
using namespace std;

class figurina:public item{
friend ostream &operator<<(ostream& , figurina &);
friend istream &operator>>(istream& , figurina &);
friend class album;
public:
figurina(char*,float,char*,int,bool,bool);
~figurina(){delete[] descrizione;}

ostream& print(ostream&);
istream& set(istream&);
//void input_fig(album,int);
protected:
char* descrizione;
int numero;
bool presente;
bool doppione;
};

[Kendall]
23-05-2012, 01:49
Forse non ho letto bene la consegna dell'esercizio, ma perchè dichiari album e figurina a vicenda membri friend? Cioè, a che ti serve sta cosa?

microinfo
23-05-2012, 10:03
in realtà l'avevo dichiarato solo in figurina (friend class album) per far si che album potesse usare la classe figurina.. poi per provare l'ho messo avunque lol ma non va :(
se lo elimino ovunque mi da errore no matching function for call to 'figurina::figurina()

[Kendall]
23-05-2012, 11:12
in realtà l'avevo dichiarato solo in figurina (friend class album) per far si che album potesse usare la classe figurina.. poi per provare l'ho messo avunque lol ma non va :(
se lo elimino ovunque mi da errore no matching function for call to 'figurina::figurina()

No allora, dichiarare funzioni o classi friends serve per rendere visibili a queste funzioni e/o classi i membri privati. Questa cosa a te non serve, in quanto un album è una semplice raccolta di figurine. Quindi elimina le dichiarazioni friend, crea una classe album e al suo interno inserisci un container (un vector, una list, una map o quella che implementa le funzionalità più idonee al tuo utilizzo).

Esempio:

// album.h
#include "figurina.h"
#include "vector"

#ifndef ALBUM_H
#define ALBUM_H

class Album {
public:
Album();
Album& Add(const Figurina& figurina);
private:
vector<Figurina> _album;
}

#endif


//album.cpp
#include "album.h"

Album::Album()
{
}

Album& Album::Add(const Figurina& figurina)
{
_album.push_back(figurina);
return *this;
}



In questo esempio ho usato per semplicità un container vector, ma probabilmente map o multimap sarebbero anche più idonee permettendoti di associare ogni figurina ad una precisa key, magari per la ricerca o per altro.

microinfo
23-05-2012, 11:47
questo perà utilizzando l STL ma io non posso usarlo, devo allocarlo dinamicamente manualemnte..
ma in ogni caso c'è un errore perchè anche utilizzando vector mi dice:
figurina non dichiarata nello scope
template argument 1 non valido
template argument 2 non valido

[Kendall]
23-05-2012, 12:20
questo perà utilizzando l STL ma io non posso usarlo, devo allocarlo dinamicamente manualemnte..

Allora all'interno di Album devi utilizzare un array di figurine, o ancor meglio (secondo me) un array di puntatori a figurine.
Fermo restando che non è pensabile per un esercizio crearsi una propria classe che gestisca dinamicamente la crescita dell'album (come fa la STL) in quanto sarebbe assolutamente dispendioso a livello di tempo (visto che devi gestire la crescita dinamica di memoria e non è banale), l'unica altra possibilità è appunto andare sui "semplici" array. Questo comporta che devi preventivamente avere idea del numero massimo di figurine contenibili nell'album (e la cosa può anche starci, pensa per esempio agli album di figurine che acquisti, all'inizio è un insieme definito di spazi liberi nei quali poi andrai ad incollare le figurine acquistate).
Posto questo, gli approci sono 2 (che mi vengono in mente), e poniamo per esempio che il numero massimo di figurine sia 200 (per semplicità della spiegazione):

1) Ti crei staticamente ( Figurina _album[200]; ) o dinamicamente ( Figurina* _album = new Figurina[200]; <-- Questo presuppone che nella dichiarazione della classe dichiari un puntatore a figurine, e poi nel costruttore fai puntare quel puntatore ad un array di 200 figurine) l'album di figurine. Il vantaggio dell'usare il puntatore è che puoi decidere a runtime il numero di figurine che costituisce l'album, a differenza del dichiarare direttamente un array (che deve essere dichiarato con una costante).
L'aspetto negativo di questo approcio è invece che istanziare Album comporterà sempre l'occupazione di memoria pari a istanziare anche 200 variabili Figurina.

2) Ti crei un vettore di puntatori a Figurina. In questa maniera istanzi solo i 200 puntatori (che solitamente hanno dimensione di 4 byte ognuno) ed eviti di istanziare 200 istanze di Figurina, che sicuramente è ben più corposa a livello di spazio occupato. Li assegni tutti quant a null, inzialmente, e infine a runtime, quando serve, crei una nuova istanza di Figurina e l'assegni a uno dei puntatori. Cosa negativa di questo approcio? Che andrà ad occupare sempre minor memoria, rispetto al caso 1, tranne quando avrai un album completamente riempito, caso nel quale avrai forzatamente 200 istanze anche usando i puntatori, quindi alla fine la memoria occupata sarà la medesima (anzi leggermente superiore visto gli 800 byte utilizzati per i 200 puntatori) rispetto al caso 1.

microinfo
23-05-2012, 12:45
la traccia mi dice:
Si realizzi quindi la classe Album, contenente oggetti di tipo Figurina. La classe Album contiene le seguenti variabili membro:
....
Num, intero rappresentante il numero di figurine presenti nella collezione
A, vettore di elementi di tipo figurina allocato dinamicamente (conterrà tanti elementi quanti indicati da Num)

il problema però rimane qui : figurina* valbum; //errore:figurina non è nome del tipo

[Kendall]
23-05-2012, 13:20
la traccia mi dice:
Si realizzi quindi la classe Album, contenente oggetti di tipo Figurina. La classe Album contiene le seguenti variabili membro:
....
Num, intero rappresentante il numero di figurine presenti nella collezione
A, vettore di elementi di tipo figurina allocato dinamicamente (conterrà tanti elementi quanti indicati da Num)

il problema però rimane qui : figurina* valbum; //errore:figurina non è nome del tipo

Ok, quindi la consegna ti chiede di usare un puntatore al quale "aggancerai" a runtime un'array di dimensione specificata (vedi caso 1 di prima). Fissato questo, posta tutto il codice del programma (integralmente), o se preferisci inviameloin privato,poi vedrò di risponderti qui

microinfo
23-05-2012, 13:38
ti ho inviato un pm, cmq grazie per l'aiuto :)

[Kendall]
23-05-2012, 16:26
Allora microinfo, io ho trovato questi errori:

1) Nell'header di figurina dovresti eliminare l'include di album.h . Questo perchè facendo in tal modo lui va a leggersi la dichiarazione di album e si ritrova ad utilizzare figurina, una classe che ancora deve definire. Per questo ti dice che figurina non è un tipo (perchè lui in effetti ancora non sa che esiste e come è fatta!).

2) Aggiungi su figurina e sulla sua sottoclasse item dei costruttori di default con nessun parametro. Definendone uno tuo il compilatore non si prende la premura di definirlo più (il costruttore item() e figurina() per intenderci), e questi sono i costruttori utilizzati quando dichiari un array di un tipo definito da te.

Poi non vedo altro di rilevante, almeno apparentemente. Prova a fare quelle modifiche e poi dimmi se funziona.

microinfo
23-05-2012, 19:07
scusa non ho capito il punto 2, perchè non mi funziona se definisco il vettore qui?

album::album(char* edit="",char* coll="",int n=0){
editore=new char[strlen(edit)+1];
strcpy(editore,edit);
collezione=new char[strlen(coll)+1];
strcpy(collezione,coll);
num=n;
valbum=new figurina[num];
}

[Kendall]
23-05-2012, 21:00
scusa non ho capito il punto 2, perchè non mi funziona se definisco il vettore qui?

album::album(char* edit="",char* coll="",int n=0){
editore=new char[strlen(edit)+1];
strcpy(editore,edit);
collezione=new char[strlen(coll)+1];
strcpy(collezione,coll);
num=n;
valbum=new figurina[num];
}

Perchè non puoi inizializzare un'array di oggetti di un tipo definito dall'utente se esso non ha un costruttore di default. Per dire, nella forma che tu utilizzi:

valbum = new figurina[num]

con quale costruttore essi vengono inizializzati? (dato che non specifichi alcun parametro).
La risposta sta proprio sul costruttore di default. Non necessitando di alcun parametro è idoneo alla forma utilizzata sopra, e pertanto deve essere specificato.

microinfo
23-05-2012, 21:37
cioè intendi dire che visto che non posso non posso dargli un valore di default devo creare il costruttore figurina();
però questo album(char* edit="",char* coll="",int n=0)
rimane un altro costruttore di default?

e la creazione del vettore dove la faccio?

[Kendall]
24-05-2012, 08:47
Il costruttore di default serve solo (per quanto riguarda questo caso) per la classe della quale vuoi creare un array di oggetti, quindi figurina (e relativa classe madre).
Per Album puoi lasciare il costruttore che già avevi messo.

microinfo
24-05-2012, 14:43
ma mi conviene creare una funzione per inizializzare il vettore con new oppure posso farlo nel costruttore? perchè nel costruttore
album::album(char* edit="",char* coll="",int n=0){
editore=new char[strlen(edit)+1];
strcpy(editore,edit);
collezione=new char[strlen(coll)+1];
strcpy(collezione,coll);
num=n;
valbum=new figurina[num];
}
mi dice che non trova la referenze figurina::figurina(), ma io i costruttori di default li ho messi sia in padre che in figlio :s

[Kendall]
24-05-2012, 15:50
ma mi conviene creare una funzione per inizializzare il vettore con new oppure posso farlo nel costruttore? perchè nel costruttore
album::album(char* edit="",char* coll="",int n=0){
editore=new char[strlen(edit)+1];
strcpy(editore,edit);
collezione=new char[strlen(coll)+1];
strcpy(collezione,coll);
num=n;
valbum=new figurina[num];
}
mi dice che non trova la referenze figurina::figurina(), ma io i costruttori di default li ho messi sia in padre che in figlio :s

Un'alternativa è quella di eliminare i parametri di default dall'implementazione dei costruttori che avevi prima, ed inserire i valori di default solo nel prototipo dentro la dichiarazione della classe (che è comunque una pratica più pulita in generale, secondo me).

Es°

// Point.h
#ifndef POINT_H
#define POINT_H

class Point
{
public:
Point(double x = 0, double y = 0) // anzichè Point(double x, double y)
private:
double x;
double y;
}

#endif

// Point.cpp
#include "Point.h"

Point::Point(double x, double y) //anzichè Point(double x = 0, double y = 0)
{
this->x = x;
this->y = y;
}


Così te lo dovrebbe accettare come costruttore di default, e quindi permetterti di utilizzarlo per istanziare l'array di figurine.

microinfo
25-05-2012, 11:05
:( non ci riesco mado, ho fatto i costruttori di default come mi hai detto, ma sto vettore non riesco proprio a crearlo. Puoi farmi vedere come si fa?

call of overloaded 'figurina()' is ambiguous album.cpp

album::album(char* edit,char* coll,int n){
editore=new char[strlen(edit)+1];
strcpy(editore,edit);
collezione=new char[strlen(coll)+1];
strcpy(collezione,coll);
num=n;
valbum=new figurina[num];
}

[Kendall]
25-05-2012, 11:21
:( non ci riesco mado, ho fatto i costruttori di default come mi hai detto, ma sto vettore non riesco proprio a crearlo. Puoi farmi vedere come si fa?

call of overloaded 'figurina()' is ambiguous album.cpp

album::album(char* edit,char* coll,int n){
editore=new char[strlen(edit)+1];
strcpy(editore,edit);
collezione=new char[strlen(coll)+1];
strcpy(collezione,coll);
num=n;
valbum=new figurina[num];
}

La chiamata è ambigua perchè hai definito un costruttore di default (quindi senza parametri) e un altro costruttore con dove però ai vari parametri dai sempre un valore di default. Questo significa che il compilatore non sa se la chiamata a figurina() sia per il costruttore di default o per quell'altro con tutti i parametri di default.
Le possibilità sono 2:

1) mantieni entrambi i costruttori, ma in quello non di default lasci almeno un parametro non specificato (nel senso, almeno nel primo parametro non devi specificare un valore di default)

2) elimini il costruttore di default mantenendo solo quello che avevi prima con i vari parametri, e fai quello che ti ho scritto nel precedente post (cioè invece di specificare i parametri di default nel file di implementazione li specifichi nell'header della classe, cioè nel prototipo del costruttore).

microinfo
25-05-2012, 12:54
ah ecco ora funziona, avevi ragione ;)
per finire ho fatto le tre fuznioni richieste nella classe album
int &album::operator[](int ind){
if(ind<0 || ind>num)
throw bad_access();
return valbum[ind];
}
void album::visua_mancanti(){
cout<<"Le figurine mancanti alla collezione sono: "<<endl;;
int i;
for(i=0;i<num;i++){
if(valbum[i].getpre()==false){
cout<<valbum[i];
cout<<endl;}
}
}
void album::stampa_mancanti(){
int i;
fstream f;
f.open("dati.txt",ios::out);
f<<"Le figurine mancanti sono: "<<endl;
for(i=0;i<num;i++){
if(valbum[i].getpre()==false)
f<<"La figurina numero: "<<valbum[i]<<endl;
}
f.close();
}
mentre la funzione acquisisce nella classe figurina, non l'ho capita, cioè come faccio a dire se è presente o meno, se il vettore figurine è definitoin album?

[Kendall]
25-05-2012, 13:43
ah ecco ora funziona, avevi ragione ;)
per finire ho fatto le tre fuznioni richieste nella classe album
int &album::operator[](int ind){
if(ind<0 || ind>num)
throw bad_access();
return valbum[ind];
}
void album::visua_mancanti(){
cout<<"Le figurine mancanti alla collezione sono: "<<endl;;
int i;
for(i=0;i<num;i++){
if(valbum[i].getpre()==false){
cout<<valbum[i];
cout<<endl;}
}
}
void album::stampa_mancanti(){
int i;
fstream f;
f.open("dati.txt",ios::out);
f<<"Le figurine mancanti sono: "<<endl;
for(i=0;i<num;i++){
if(valbum[i].getpre()==false)
f<<"La figurina numero: "<<valbum[i]<<endl;
}
f.close();
}
mentre la funzione acquisisce nella classe figurina, non l'ho capita, cioè come faccio a dire se è presente o meno, se il vettore figurine è definitoin album?

Tutte le classi possono comunicare con altre classi. Nel caso specifico immagino che il metodo debba sapere se la specifica istanza della classe figurina è presente sull'album. Questo significa fare una comparazione di riferimenti (che per i puntatori equivale banalmente ad un puntatore1 == puntatore2). Non voglio risolvere la cosa per te (non per cattiveria, ma ti è più utile sbatterci la testa), ma ti do un suggerimento: la funzione della quale parli evidentemente ha dei parametri in ingresso. Di sicuro ci sarà pure un modo per dargli in pasto un qualche riferimento a ad un album di figurine... ;)

microinfo
25-05-2012, 17:02
io non riesco a capire proprio il testo...
cioè quello che ho capito:
//creo tre oggetti figurina
figurina f1("pato",3,false,false);
figurina f2("lavezzi",4,false,false);
figurina f3("totti",10,false,false);

//creo al'album che le conterrà (in valbum)
album al;
//inserisco le figurine nell'album in questo ordine
al.valbum[0]=f1;
al.valbum[1]=f2;
al.valbum[2]=f3;
//dato il numero della figurina in ingresso, mi dice se è presente nell'album, oppure se è un doppione
f.acquisisci(4);

però non capisco l'utilità della funzione acquisici...non dovrebbe prendere in ingresso l'oggetto figurina, e non il numero?
#########
void figurina::acquisisci(int x,album a){
int i;
for(i=0;i<a.num;i++){
if(a.valbum[i].numero==x)
a.valbum[i].doppione=true;
else if(a.valbum[i].numero!=x)
a.valbum[i].presente=true;
}
}
#########



f.acquisici(2);

microinfo
28-05-2012, 13:54
up

[Kendall]
28-05-2012, 20:00
Lì devi più che altro capire con il tuo professore qual'è la consegna precisa dell'esercitazione.
Perchè ha senso sia, dato il numero della figurina, verificare se essa è presente nell'album, sia data l'istanza di figurina verificare se essa è tra quelle inserite nell'album. Solo che, come detto, devi capire precisamente con il prof cosa vuole effettivamente che tu faccia.

microinfo
29-05-2012, 10:55
ma nel caso in ingresso alla funzione acquisici ho solo il numero della figurina, come faccio a scorrere il vettore di figurine senza un oggetto? cosi
void figurina::acquisisci(int x){
int i;
for(i=0;i<num;i++){
if(valbum[i].numero==x)
valbum[i].doppione=true;
else if(valbum[i].numero!=x)
valbum[i].presente=true;
}
}

[Kendall]
29-05-2012, 16:11
Allora, facciamo un passetto indietro micro, e spiegami precisamente cosa deve fare il metodo acquisisci(int)

microinfo
29-05-2012, 16:17
da quanto ho capito è una funzione della classe figurina, che dato in input il numero della figurina deve controllare che sia presente nella collezione, quindi suppongo che deve essere presente nel vettore figurine

[Kendall]
29-05-2012, 17:24
da quanto ho capito è una funzione della classe figurina, che dato in input il numero della figurina deve controllare che sia presente nella collezione, quindi suppongo che deve essere presente nel vettore figurine

Se è una funzione della classe figurina allora però avrà bisogno almeno di avere il riferimento alla collezione nella quale fare il check. A meno che tra i campi della figurina non inserisci un puntatore alla classe Album, che andrà, ogni qualvolta inserisci una figurina nell'album, a puntare all'album stesso (proprio come avviene nelle interfacce grafiche, dove ad ogni widget creato viene passato il riferimento al widget o form che lo contiene.

microinfo
29-05-2012, 20:08
cioè il riferimento ad album?
void figurina::acquisisci(int x,album a){
int i;
for(i=0;i<a.num;i++){
if(a.valbum[i].numero==x)
a.valbum[i].doppione=true;
else if(a.valbum[i].numero!=x)
a.valbum[i].presente=true;
}
}

microinfo
02-06-2012, 11:38
devo procedere cosi?

[Kendall]
02-06-2012, 17:40
devo procedere cosi?

L'album prima di tutto dovresti passarglielo per riferimento o tramite puntatore.
E' cattiva pratica passare istanze di classi per valore (oltre al fatto che metti in gioco il costruttore per copia che quindi dovrebbe essere definito per evitare pasticci), in primis perchè comporta il creare una copia interna di una istanza (e quindi utilizzo di risorse evitabile) e per secondo perchè ogni modifica su di essa andrebbe persa, essendo una copia.

A parte questo, io una cosa non ho capito. Ma il numero della figurina corrisponde alla posizione nell' array dell' album o le figurine vengono inserite sequenzialmente a prescindere dal loro numero?

microinfo
04-06-2012, 10:31
si assegni all’indice i la figurina di numero i
ah ti ho inviato un programma in pm puoi dirmi perchè non funziona la funzione inserisci ordinato? grazie

microinfo
05-06-2012, 10:09
up

[Kendall]
05-06-2012, 11:10
si assegni all’indice i la figurina di numero i
ah ti ho inviato un programma in pm puoi dirmi perchè non funziona la funzione inserisci ordinato? grazie

Allora in tal caso non ti serve scorrere nulla, ma semplicemente verificare che il puntatore a figurina nell'iesima posizione dell'album (iesima-1 per la precisione essendo in base 0) corrisponda al riferimento dell'istanza di figurina per il quale fai il check ( qualcosa tipo: if (this == album[i]) ) . Ricorda, si tratta di un confronto di riferimenti, quindi di indirizzi di memoria.

Rimango comunque dell'idea che tenere all'interno di figurina un puntatore al relativo album (che sarà NULL nel caso in cui la figurina non è inserita in alcun album) sia la via migliore

microinfo
06-06-2012, 14:56
per quanto rigurarda la lista che ti ho inviato per pm. ?

[Kendall]
06-06-2012, 16:31
per quanto rigurarda la lista che ti ho inviato per pm. ?

In questi giorni riesco a scrivere solo via cell... Riusciró a darci un'occhiata solo tra qualche giorno. Magari apri un nuovo thread a riguardo

microinfo
18-06-2012, 11:05
novità?