Newsgroup: it.comp.lang.c++
Titolo: Classi && eredità

Salve,
vi espongo il problema del giorno:
ho una classe base (pezzo), da cui ho derivato 6 classi
(re,regina,cavallo,alfiere,pedone,torre), ora come posso richiamare
genericamente le classi derivate?, indendo, si puo' agire in tal modo:
pezzo::muovi();
intendendo l'uso di "pezzo" come un nome generico, quindi applicabile
a qualunque classe derivata, quindi non ha tanta importanza che
effettivamente il pezzo sia un cavallo o un re, in quanto per ogni
classe derivata la funzione membro muovi() è specificata.
Questa mia teoria è valida, o è solo una marea di stupidaggini?
Grazie. 

 pezzo::muovi();
No, devi chiamare il metodo muovi attraverso un puntatore o reference
alla classe pezzo che punta, in realtà, ad un pezzo particolare. In
questo modo verrà chiamato il metodo del pezzo effettivo. Es.:
pezzo *ped = new pedone;
pezzo *alf = new alfiere;
ped -> muovi();
alf -> muovi();
...
EMG

 writes:

Si, e' valida; ovviamente muovi() sara' un metodo virtuale, ridefinito
per ogni classe derivata da pezzo.  Basta provare:
#include <iostream>
class pezzo {
public:
  virtual ~pezzo() {}
  virtual void chiSei() { std::cout << "Sono un pezzo\n"; }
};
class re : public pezzo {
public:
  ~re() {}
  void chiSei() { std::cout << "Sono un re\n"; }
};
int main() {
  pezzo *p = new re;
  p->chiSei();
  delete p;
}
-- 
Maurizio Loreti                         
http://www.pd.infn.it/~loreti/mlo.html
Univ. of Padova, Dept. of Physics - Padova, Italy            
lor...@pd.infn.it
The instructions said to use Windows 98 or better - so I installed FreeBSD.

alf -> muovi();
e naturalmente ricordati di dichiarare la funzione muovi come virtuale
pura nella classe pezzo, altrimenti non funziona niente!
class Pezzo {
/*...*/
virtual void muovi() =0;
};
Anto
--
Antonio Cuni, 18 anni, studente
Brainbench Certification: 
Master C++: 4.6, higher than 98% of all previous test takers.
C Language: 3.32, higher than 79% of all previous test takers.
http://www.brainbench.com/transcript.jsp?pid=1301688

 
http://www.brainbench.com/transcript.jsp?pid=1301688
Zio caro, che sfigato che sei...

}
Ok, ma in tal modo viene creato un'altro oggetto, non lavoro con
quello originale. Io vorrei lavorare con quello originale.

 writes:

Viene creato uno ed un solo oggetto.  Non capisco cosa tu voglia dire
con "originale".


con "originale".
Si, viene creato un'oggetto quando uso:
[...]
 pezzo *p = new re;
 p->chiSei();
 delete p;
[...]
ma che non è quello di partenza.
[...code...]
re prova; //creo l'oggetto di partenza
pezzo *p=new re; //crea un nouvo oggetto re
p->muovi(A,4); //muove il nuovo oggetto re
delete p; //distrugge il nuovo oggetto re
[... code...]
ma l'oggetto re originale, il prova, tanto per intenderci, non si
muove di un pixel, io voglio, chiamandolo in modo diciamo "generico"
(quindi con qualcosa di simile a pezzo::muovi(A,4);) far muovere
l'oggetto di partenza.

quello originale. Io vorrei lavorare con quello originale.
non riesco ad afferrare fino in fondo quello che dici: questo è solo
un esempio semplificato: tu dici una cosa del genere:
void InterrogaPezzo(pezzo& p) {
  p.chiSei();
}
int main() {
  Re pezzo1;
  Alfiere pezzo2;
  InterrogaPezzo(pezzo1);
  InterrogaPezzo(pezzo2);
}
la funzione InterrogaPezzo() opera sull'oggetto "originale", se è
questo quello che intendevi.
Anto
--
Antonio Cuni, 18 anni, studente
Brainbench Certification: 


 }
La funzione chiSei() che viene eseguita e' quella di class pezzo o di class
re ?
Per quale motivo si deve specificare virtual nella dichiarazione di
pezzo::chiSei ?


Ciro Caltana wrote:

Non credo che inserire muovi nella classe pezzo sia l'approccio giusto.
Infatti se il come muoversi è specifico per ogni pezzo (sappiamo che
ogni pezzo ha tipi di mosse differenti), è altrettanto vero che
l'effettiva
capacità di compiere una mossa è legata alla posizione degli altri
pezzi sulla scacchiera.
Ammetto di non averci riflettuto molto, ma così, di primo acchito,
io tenterei la strada di una soluzione del genere:
class Scacchiera {
public:
    // Questa funzione chiama pezzo->IsValidMove(...)
    // per conrollare che il pezzo possa eseguire una tale
    // mossa, e poi controlla che sia possibile fare la mossa
    // in base ai pezzi sulla scacchiera
    bool muovi(Pezzo* pezzo, Posizione pos);
};
class Pezzo {
public:
    // Questa funzione si occupa di controllare che il
    // tipo di mossa sia nelle possibilità del pezzo
    virtual bool IsValidMove(Posizione pos_start, Posizione pos_end) const
= 0;
    // Chiedo al pezzo se per eseguire la mossa necessita di
    // "avere la strada libera"
    virtual bool NeedFreeWay() const = 0;
};
class Re : public Pezzo {
    bool IsValidMove(Posizione pos_start, Posizione pos_end) const { ... }
    bool NeedFreeWay() const { ... }
};
Ciao Fulvio.

};
io personalmente farei un misto tra i due: ovvero l'utente chiama
Scacchiera::muovi(), che a sua volta chiama Pezzo::muovi() (infatti la
scacchiera non dovrebbe sapere nulla sui suoi pezzi). Se il pezzo non
si puň muovere, solleva una eccezione.


 si può muovere, solleva una eccezione.
Antonio, in realtà (anche se forse ti sei espresso male dicendo che la
scacchiera non sa nulla dei suoi pezzi) tu parti da un presupposto che non e'
stato espresso.
Non possiamo parlare di design in questo caso dato che non sappiamo se la mossa
da eseguirsi viene dall'esterno (scacchiera digitale) o se stiamo scrivendo una
engine di gioco (gioco degli scacchi con il computer).
Ovviamente la tua soluzione e' valida solo nel caso della scacchiera digitale.
Pero' se provi a pensarci BENE. L'implementazione piu' logica ed efficiente per
una scacchiera digitale (anche se poi fa parte di un gioco degli scacchi al
computer con tanto di engine di gioco) non prevede la creazione di una istanza
della classe pezzo per ogni pezzo.
Flyweight pattern docet.
Andrea Ferro
---------
Brainbench C++ Master. Scored higher than 97% of previous takers
Scores: Overall 4.46, Conceptual 5.0, Problem-Solving 5.0
More info 
http://www.brainbench.com/transcript.jsp?pid=2522556

Flyweight pattern docet.
???


 ???
 
http://csgwww.uwaterloo.ca/dptool/patterns/structur/flyweigh.htm

 pezzo::chiSei ?
E' proprio dichiarando la funzione "virtual" che si ottiene il
meccanismo descritto qui sopra. Il meccanismo di chiamata virtuale fa
si' che la funzione da chiamare venga scelta a runtime in base al tipo
effettivo di un oggetto riferito da un puntatore o da un reference,
invece che stabilita durante la compilazione come avviene per le
funzioni normali.
Ciao,
Nicola

 ???
Ti ha risposto Max.
Vedila cosi:
Se crei una istanza per ogni pezzo, il pezzo deve avere fra i suoi dati la
posizione attuale e il colore. Ma molti degli algoritmi relativi al pezzo
(movimenti etc) hanno bisogno di avere accesso agli altri pezzi. Quindi ti serve
un puntatore ad un container dei pezzi (ovvero la scacchiera). Questo container
contiene un puntatore per ogni pezzo (o direttamente i pezzi).
Con una sola scacchiera il guadagno del Flyweight non e' grandissimo. Ma
immagina un sistema di scacchiera elettornica multipla. Ovvero non c'e' la
engine di calcolo della mossa (o meglio puo' esserci, ma e' un altra parte del
progetto) ma solo una scacchiera elettronica su cui due giocatori umani giocano.
Immagina di estenderlo: lo stesso sistema gestisce decine di scacchiere (e
quindi di partite). Magari via internet o in un torneo.
A questo punto ha ancora senso una classe per ogni pezzo dato che il test del
movimento del pezzo lo devi ancora fare (e anche l'esecuzione del movimento,
magari animata etc. etc.).
Flyweight: ciascuna scacchiera e' rappresentata da un container di quaterne.
Ciascuna quaterna contiene le due coordinate, il colore e il tipo di pezzo.
Ciascun TIPO di pezzo (6 in tutto) e' rappresentato da una sola istanza e i suoi
metodi ricevono come parametri i valori della quaterna.
Le variazioni sono a fantasia. Pezzi come singleton (nella quaterna metti il
puntatore). Nome del pezzo come enum o come stringa invece che come puntatore e
poi map fra nomi dei pezzi e loro istanza. Etc.
--
