Newsgroup: it.comp.lang.c++
Titolo: togliere dynamic_cast

Salve a tutti,
ho il seguente programmillo:
#### INIZIO #######
#include <iostream>
class IFace
{
	public:
	virtual ~IFace(){};
	virtual int get_int() = 0;
};
class Face : public IFace
{
	public:
		virtual ~Face(){};
		virtual int get_int(){return m_i;};
		void set_int(int i){ m_i = i;};
	private:
		int m_i;
};
IFace*  f()
{
	Face* f = new Face();
	f->set_int(5);
	return(f);
};
IFace* redo(IFace* i)
{
	Face* f = dynamic_cast<Face*>(i);
	f->set_int(7);
	return(f);
};
void print()
{
	IFace* i = f();
	std::cout << i->get_int() << "\n" ;
	i = redo(i);
	std::cout << i->get_int() << "\n" ;
};
int main()
{
	print();
};
#### FINE ############
è possibile fare una gerarchia di classi che mi permetta di togliere il
dynamic_cast!? io penso di no. Voi cosa mi dite ?
Grazie 
Ciao

 dynamic_cast!? io penso di no. Voi cosa mi dite ?
La risposta ovvia e' definire set_int() virtuale puro in IFace. Se non
lo fai redo() e' concettualmente sbagliata: non ha senso prendere per
argomento una classe che non ha la funzione membro che si deve
chiamare.
Ciao,
Nicola

 
non voglio però definire quella funzione nella classe base; vorrei che
la funzione print potesse accedere solo minino indispensabile di membri
che le servono, non posso neanche chiedere a print di fare lei il cast
xke non è tenuta a sapere con che classe è stata implementata IFace.
altre soluzioni? pattern? o non so :)
Grazie ciao

 xke non è tenuta a sapere con che classe è stata implementata IFace.
Se pero' tra i compiti di print c'e' anche l'effetto di redo() allora
set_int() fa parte dell'interfaccia che print() deve conoscere.
Probabilmente devi rivedere il tuo disegno piu' drasticamente, perche'
la sensazione e' che tu non abbia colto correttamente gli opportuni
livelli di astrazione.
Ciao,
Nicola

 livelli di astrazione.
probabilmente sbaglio nel voler usare le interfacce per restringere
l'accesso a certi membri. Nel senso è logico che un IFace abbia una
funzione per settare dei valori, però alla funzione print non servono e
non voglia che ci possa accedere.
Mi sa che mi rassegnerò a mettere set_init in IFace se non ci sono
altre soluzioni.
Ciao

 };
infine
int main() {
  redo();
}
A questo punto i nomi probabilmente non tornano, la logica si.
Ciao,
Nicola

 A questo punto i nomi probabilmente non tornano, la logica si.
per me invece non torna la logia :) questo ovviamnete xke ho dato un
esempio striminzito del problema reale. Posto del codice un po piu
verosimigliante con il caso reale.
#include <iostream>
class IFace
{
	public:
	virtual ~IFace(){};
	virtual int get_int() = 0;
};
class Face : public IFace
{
	public:
		virtual ~Face(){};
		virtual int get_int(){return m_i;};
		virtual void set_int(int i){ m_i = i;};
		virtual bool get_bool(){return(m_b);};
		virtual void set_bool(bool b){ m_b=b};
	private:
		int m_i;
		bool m_b;
};
class Engine
{
	public:
		Engine(){};
		~Engine(){};
		IFace* get(){
			Face* f = new Face();
			f->set_int(5);
			return(f);
		};
 
		IFace* value(IFace* i){
			Face* f = dynamic_cast<Face*>(i);
			if(f->get_bool())
				f->set_int(7);
			return(f);
		};		
};
void print()
{
	Engine* e = Engine();
	IFace* i = e.get();
	std::cout << i->get_int() << "\n" ;
	i->set_bool(true);
	i = e.value(i);
	std::cout << i->get_int() << "\n" ;
};
int main()
{
	print();
};
print prende la struttura da Engine che la crea e la riempie come
dovuto, print la stampa e prende un input dall'utente poi ripassa il
tutto ad Engine che valuta l'input dell'utente. Ora visto che print
print non deve riempire quella strurra ne deve farlo in IFace non ho
messo nessuna funzione che serva a quello ma solo quelle indispensabili
per il suo funzionamento. Non posso chiamre print da dentro engine ma
devo fare il contrario. Ora ho anche un altro problema; in Face
dovrebbe esserci un id che la identifica univocamente, questo serve
alla classe Engine; qui sorge nuovamente il problema del dowcast, print
non deve essere a conoscenza di quell'id in quanto è solo un dettaglio
implementativo. 
C'è qualche sistema che posso usare ? ho la sensazione di essermi perso
qualcosa del c++.
Ciao e grazie

 ha scritto:

Il tuo problema non e' di C++ ma di disegno. Hai due alternative: o
decidi che print() controlla tutto e Engine fa solo da factory, oppure
fai mediare da Engine l'interazione tra (I)Face e print().
Nel primo caso e' inevitabile che print abbia accesso ai metodi
mutatori di Face ed Engine non ha molto senso di esistere: grosso modo
stai implementando uno schema Document - View, tipico ad esempio di
MFC. Il secondo caso e' quello comunemente noto come Model - View -
Controller e mi sembra preferibile, perche' separa meglio le
responsabilita'. In questo caso quello che era la funzione print()
diventa una classe e l'interazione in pseudo codice diventa qualcosa
come (cerca di visualizzare il diagramma con un font non
proporzionale!):
utente           View         Engine   Face / IFace
  +-Apri Finestra->+            |
  |                +-getFace()->+
  |                |            +-create()->+
  |                |            +<---this---+
  |                +<--return---+           |
  +<----print()----+            |           |
  +---Modifica---->+            |           |
  |                +-modify()-->+           |
  |                |            +-set_int()>+
  |                +-getFace()->+           |
  |                +<--return---+           |
  +<----print()----+            |           |
In questo caso View non ha bisogno di conoscere i mutatori di Face,
perche' non e' compito suo modificarne lo stato. Idealmente View
chiama metodi di Engine che sono ad un livello di astrazione piu' alto
ed e' Engine a decidere che la corrispondente operazione di basso
livello e' effettivamente modificare Face. Questo approccio e'
certamente piu' complesso, ma i compiti risultano decisamente meglio
distribuiti: View si occupa esclusivamente di presentare le
informazioni e di ricevere i comandi dell'utente, (I)Face costituisce
la rappresentazione esplicita del dominio applicativo e Engine media
tra i due, presentando a View una rappresentazione piu' astratta del
dominio e isolando (I)Face dai dettagli della presentazione.
Spero sia ragionevolmente chiaro.
Ciao,
Nicola

 presentazione. 
Engine per fornire un livello di astrazione piu alto, ma lavorare anche
ad uno piu basso, non deve necessariamente effettuare un downcast? nel
tuo schema la funzione modify(); deve passere il puntatore ad un Iface
perchè è il livello di astrazione a cui lavora View però poi Engine
deve lavorare ad uno piu basso ovvero Face.
Scusami prorpio non capisco
Grazie ancora
CIao

 Scusami prorpio non capisco
L'idea e' che al suo interno Engine manipola Face, ma all'esterno
presenta solo IFace.
Questo in effetti dal diagramma non traspare.
Ciao,
Nicola

 presenta solo IFace.
quello che non capisco è se Engine per manipolare Face e presentare
IFace deve necessariamente efettuare un dowcast o se ci sono altre
tecniche?? pensavo a un map<Iface*, Face*> ma non mi sembra una gran
cosa.
Ciao

 cosa.
No, Engine manipola sempre e solo Face, sia che ne gestisca la
costruzione e quindi il possesso, sia che le riceva da qualche entita'
esterna.
Ciao,
Nicola

 esterna.
non puo riceverli però da qualche entita esterna perche l'entita
esterna (in questo caso View) conosce solo IFace.
Ciao

 esterna.
riusciresti a farmi due righe di codice come esempio? Perchè cosi
proprio non riesco a capire come Engne possa fare a manipolare FAce se
riceve IFace senza un cast.
Ciao
Grazie