Newsgroup: it.comp.lang.c++
Titolo: consiglio su modellazione e dynamic_cast

Ciao a tutti.
Volendo fare una funzione che agisce su un array di puntatore a
oggetto e che
per ogni tipo di oggetto fa della azioni diverse, secondo voi e'
necessario un dynamic_cast
per forza o esistono altre soluzioni migliori?
Mettiamo che io abbia la classe base Object e che da questa derivi
Luci,Camera,....,etc etc
Pensavo di fare una funzione che avessa la capacita' prendere un array
in ingresso di puntatori a Object e che permetta di processare ogni
singolo oggetto della scena in base al suo tipo.
void ProcessScene(vector<Object*> & listObj)
{
     for (int i=0;i<listObj.size;i++)
     {
          Light* l=NULL;
          l=dynamic_cast<Light*>(listObj[i]);
          if (l!=NULL)
          {
              // fai qualcosa per gestire le luci
          }
          Camera* c=NULL;
          c=dynamic_cast<Camera*>(listObj[i]);
         if (c!=NULL)
          {
              // fai qualcosa per gestire la camera
          }
      }
}
Qualche idea su come modellare le classi magari in modo da non usare
il dynamic_cast?
Soprattuto mi preoccupa quel dynamic_cast dato che l'applicazione deve
essere
molto efficente e safe nello stesso tempo.

esistono altre soluzioni migliori?
Sicuramente sì. Usando bene il polimorfismo (che sostanzialmente non
fa altro che delegare al sistema i controlli "dinamici") si può
scrivere codice migliore e più sicuro.
Però bisogna capire che intendi con quel "fai qualcosa per gestire".
Il problema che intravedo nel tuo design è che hai modellato le tue
entità con delle classi, ma stai implementando i comportamenti in
maniera procedurale. Descrivi meglio cosa vorresti fare...

 maniera procedurale. Descrivi meglio cosa vorresti fare...
una sorta di motore 3d. Per cui una scena è composta da tante entità
che di fatto hanno delle caratteristiche molto diverse.
Di uguale vedo la posizione e orientazione nello spazio di questa
entità.
Sarà per quello che ho un design confuso.

 le ho mai approfondite e non le domino bene.
Non so perché tu ti ci trovi male, ma le funzioni virtuali pure non
hanno poi molto di diverso dalle funzioni virtuali ordinarie. E' solo
che rappresentano comportamenti astratti (e quindi, in C++,
conferiscono astrazione alla classe cui appartengono). Concepire un
comportamento astratto non è un'attività legata necessariamente a
grosse costruzioni di classi, in grandi sistemi, anche se un buon uso
dell'astrazione richiede che tu abbia ben chiaro cosa vuoi fare.

 per forza o esistono altre soluzioni migliori?
Suggerirei:
 
http://en.wikipedia.org/wiki/Visitor_pattern
Max

 le ho mai approfondite e non le domino bene.
Se ti fai di questi problemi forse dovresti smettere di programmare.
Scusa la franchezza, ma la tua affermazione e' l'equivalente
informatico di "Ho paura del Babau".
Pensare di fare programmazione object oriented in C++ senza usare le
funzioni virtuali pure non ha senso. Ti pare davvero meglio scrivere:
class Base {
  public:
    void f() { std::cout << "Messaggio inutile tanto per
mettercelo"; }
};
che non
class Base1 {
  public:
    void f() = 0;
}
Cosa ci sia poi da "non trovarsi bene", non lo capisco.
Ciao,
Nicola

 }
Max suggerisce il pattern Visitor, che e' certamente un'opzione
valida. Io pero' mi domando se in realta' non faccia piu' al caso tuo
il pattern Composite: 
http://en.wikipedia.org/wiki/Composite_pattern
Nel tuo caso potresti considerare le classi Light, Camera, etc. come
derivate da una classe base SceneElement:
class SceneElement {
  public:
    virtual void process() = 0;
    virtual ~SceneElement() {}
};
class Light : public SceneElement {
  public:
    virtual void process() {
      // Fai qualcosa per gestire la luce
    }
};
class Camera  : public SceneElement {
  public:
    virtual void process() {
      // Fai qualcosa per gestire la camera
    }
};
A questo punto puoi considerare anche Scene come un SceneElement di
tipo composito, che gestisce un insieme di SceneElement:
class Scene : public SceneElement {
  public:
    virtual void process() {
      for ( int i = 0; i != elems.size(); ++i )
        elems[i]->process();
    }
  private:
    std::vector<SceneElement *> elems;
};
Ed la funzione Scene::process() prende il posto della tua
ProcessScene.
Ciao,
Nicola

ClassID()==Class_ID(FSPOT_LIGHT_CLASS_ID,0)) {
                           sprintf(buf, GetString(IDS_FSPOT_LIGHT),
node->GetName());
		           AddToMsgList(msgList, buf);
			   //Append(node, obj, OBTYPE_SPOTLIGHT);
            }
            break;
        }
		case CAMERA_CLASS_ID:
			if (obj->ClassID()==Class_ID(LOOKAT_CAM_CLASS_ID,0))
				Append(node, obj, OBTYPE_CAMERA);
			break;
		}
che tipo di pattern corrisponde questo modo di utilizzare class_id a
qualcuno o no?
Mi consigliate un semplice libro di design pattern per principianti.

 di SceneElement?
Nel mio esempio lo e', come puoi notare dal pezzetto di codice che ho
lasciato qui sopra.

Questo e' un *anti-pattern*, cioe' qualcosa che in C++ non si dovrebbe
proprio fare. Non solo esegue una condizione sul tipo di un oggetto,
ma si inventa un modo suo per classificare i tipi invece di usare
quello proprio del linguaggio, ovvero il dynamic_cast. Un esempio
classico di dove applicare le funzioni membro virtuali.
Puo' avere un senso in C, ma e' un forte sintomo di aver sbagliato a
scegliere il C invece del C++.
Ciao,
Nicola

 Mi consigliate un semplice libro di design pattern per principianti.
So che c'e' chi consiglia altri libri, ma secondo me non si puo' non
passare da "Design Patterns", di Gamma, Helm, Johnson, Vlissides.
Bisogna pero' tener presente che in genere i testi di design pattern
tendono a concentrarsi su cio' che si puo' fare con ereditarieta' e
funzioni virtuali e non considerano i template.
Questo puo' essere ragionevole per linguaggi con meccanismi per la
programmazione generica limitati o proprio assenti, ma non di rado in C
++ esistono soluzioni piu' naturali di quelle descritte nei pattern.
Ciao,
Nicola

 riesco a riconoscere al volo cosa ho fatto?
Di nuovo: affari tuoi, ma se dai cattivi consigli o scrivi
"porcherie", ci sara' sempre qualcuno che te lo fara' notare, magari
non per convincere te, ma per farlo notare a tutti gli altri che
leggono.
Ciao,
Nicola

funzioni virtuali e non considerano i template.
Magari la mancanza in questo senso si colma con Alexandrescu. O no?

riesco a riconoscere al volo cosa ho fatto?
Al questa domanda si risponde facilmente con un test veloce:
- Se lavori da solo e per hobby, non smettere di programmare;
- Se c'è il minimo rischio che altre persone debbano lavorare in un
team in cui ci sia anche tu; se c'è il minimo rischio che questa gente
debba entrare in contatto col tuo codice, allora, fidati, smetti di
programmare.

non è quello di programmatore.
Bene, ma guarda che stiamo dicendo la stessa cosa.

 troppa.
Si capisco. In questo senso la cosa può avere senso. Ma un 
conto è dirsi : spero che non lavorerai mai nel mio team. 
L'altro è dire : spero che non programmerai più (circa eh). 
  O no ?
ciao
Soviet


 tipo composito,
Anche io originariamente avevo pensato al composite. Tuttavia poi 
-- 
-riko

 problema c'è?
Finche non scrivi software di controllo per centrali nucleari,
nessuno ;-)
Ciao,
Nicola

 materialmente)
Queste sono pure e semplici sciocchezze e avviliscono il ruolo dei
programmatori. Allora chi programma per mestiere è uno che non ha
capacità di ragionamento sul dominio che affronta? i software per la
medicina vengono scritti dai medici? i software per gestire le capsule
lunari vengono scritti dagli astronauti? I software per la fisica
devono essere scritti da fisici e per la chimica da chimici? senza
offesa, ma a me sembrano stupidaggini. Vienimi a dire, più che altro,
che un fisico o un chimico che conosce il proprio dominio
infinitamente meglio di un programmatore collaborerà con un
quest'ultimo, che conosce il proprio di dominio infinitamente meglio
del fisico o del chimico. Che un fisico o un chimico possano poi
essere bravi programmatori perché apprendo certe noziosi per osmosi, è
un conto, ma partire dal presupposto che se un fisico o un chimico non
programmano, il loro software non può scriverlo nessun altro è una
banalissima sciocchezza. Tu confondi pericolosamente chi conosce
dominio e requisiti del problema e chi quel dominio e quei requisiti
deve "svilupparli".

 deve "svilupparli".
spero di avere chiarito meglio cosa volevo dire
ciao
Soviet

 prerogativa esclusiva del programmatore.
Probabilmente non hai letto e/o capito sufficientemente bene quello
che ho scritto nel mio precedente messaggio riguardo le collaborazioni
tra le parti. Io non sono un talebano della programmazione e ciò che
mi farebbe veramente piacere è che ognuno facesse bene ciò che sa fare
e non si avventurasse in campi che non conosce. Ti assicuro che anche
nel tuo campo, il lavoro di un programmatore professionista non
sarebbe da meno del tuo.

 usarlo,
Ma che cavolo c'entra questo discorso? Io non parlo affatto di USARE
un software. E' chiaro che un software orientato ai chimici debba
essere usato dai chimici. Io parlo di COSTRUIRE un software e sono
aspetti di gran lunga diversi.

 aspetti di gran lunga diversi.
ok sono diversi. Ma costruire implica saper usare (o meglio 
conoscere la natura del problema che ti metti a risolvere).
Cioè io penso che tu (magari sbaglio, ma questo ho capito) 
sia in fondo convinto che sia SEMPRE possibile
la soluzione del tipo : l'esperto della branca va 
dall'esperto in programmazione, gli spiega il problema e 
quello gli produce il miglior codice possibile.
Io dico che questo può essere vero, magari in molti casi, ma 
ti garantisco sulla parola che ci sono problemi, che se 
l'esperto ti spiega il suo modello, non è manco detto che 
capisci le parole che usa. Se non ha già fatto lui una parte 
del lavoro di modellizzare in maniera trasferibile a un 
linguaggio (diciamo almeno una metaprogrammazione, che so, 
in diagrammi a blocchi), parlarsi diventa difficilissimo.
E non è né una pecca del tale scienziato che non sa 
spiegarsi bene né del programmatore che non capisce su due 
piedi. E' solo tutto troppo incasinato. In quella zona di 
confine continuano a vivere vari programmatori, che tu 
probabilmente non definisci tali, che si fanno le cose da sé 
e solo se poi si crea un mercato, si investe nel fare il 
grande passo, e allora si, si creano gruppi di lavoro, si 
fatica assai, e si lima il tutto. CambridgeSoft è un esempio 
ammirevole in questo senso, ha superato la massa critica e 
può permettersi di formare figure ibride di raccordo, che 
magari sono scienziati che si affacciano a programmare e 
programmatori che si affacciano alle discipline in esame sin 
quando le distanze reciproche diventano abbastanza sfumate 
da parlare la stessa lingua.
Ma purtroppo non illuderti che anche il miglior 
programmatore general purpose possa mettercisi, farsi dire 
per sommi capi il problema e mettere a frutto la sua arte.
ciao
Soviet

 Apx.
-- 
-riko

 di un cane bassotto?
Questa è da signature. 
-- 
-riko

Archeopteryx <cor.bonukFANCULOSPAM@libero_NOMAIL_.it> wrote:







-- 
-riko

 in altri campi. 
Non credo che il calcolo numerico sia un "altro campo professionale". È
uno dei tanti campi dell'informatica (o della matematica applicata, a
scelta).
-- 
-riko

 bianche.
bianche no, specialmente se ancora lavori a contatto con 
l'UNI ... ma grigio chiaro, nella media, imho si.
Ciao
Soviet
P.S.
Ah, per info, esprimo spesso dei pareri pur essendo solo un 
hobbista, ma non è che sia all'oscuro completamente del 
resto del mondo, per questioni di amicizie. Metà dei miei ex 
compagni di liceo sono diventati ing. (elettrnici, 
informatici) e spesso sono "finiti" (senza valenze negative, 
eh eh he) a fare i programmatori per aziende grandi 
(italianamente parlando), uno informatico è andato in 
alcatel in francia, e anche tra i colleghi insegnanti (siamo 
un perito elettronico a indirizzo informatico) c'è chi 
collabora anche con studi professionali etc. Cioè, non avrò 
il massimo delle fonti, ma mi capita di parlare di questi 
argomenti, seppure da esterno la percezione non possa essere 
la medesima di chi è addentro per lavoro principale.

 raramente si può fare materialmente). 
Magari un buon approccio di progettazione OO, con un domain expert 
(fisico) e un implementatore potrebbe dare risultati migliori.
Non sempre però son disponibili risorse e fondi.

 e si lima il tutto.
E' proprio il fatto che non vi è opportuno  cambiamento nel salto 
dall'ambito hobbistico a quello professionale. E' il male dell'industria 
del software.

 prblemi, e tutta la casistica intermedia.
Ma assolutamente. Il punto è che ci sono dei "livelli" sotto i quali non
si "dovrebbe scegliere". Senza quei "minimi" si finisce per continuare a
re-inventare ruote quadrate. E mi sembra lecito farlo notare, no?
Nota che per inciso ci si sta attrezzando da tempo per formare tutta una
serie di cross-professionisti informatici che sacrificano generalità per
conoscenze "generiche" in un campo extra che hanno il sostanziale
compito di metterli in grado di dialogare con gli specialisti del
settore.
Mi vengono in mente i cosidetti "bio-informatici" (che manco a dirlo
danno in media risultati migliori innestando chimica e biologia
sull'informatica, visto che il loro tipico ruolo è ancillare rispetto al
ricercatore biologo). 
-- 
-riko

 Sarà per quello che ho un design confuso.
Oltre a quello che ti è stato detto, ti posso dare un'altro suggerimento 
più pragmatico. Nonostante possa sembrare meno elegante potrebbe essere 
utile, e più performante, non collezionare tutti gli oggetti polimorfi 
in una unica lista, ma creare differenti liste per i differenti tipi. 
Questo permette al compilatore di ottimizzare molto meglio il codice. 
Inoltre in casi come il tuo (motori 3D) risulta spesso comodo poter 
trattare tutti gli oggetti dello stesso tipo uno di seguito all'altro, 
perché alcuni settaggi globali dell'acceleratore 3D possono essere fatti 
una sola volta invece che per ogni oggetto.
E.

 generale.
Il tuo mi sembra un giudizio molto affrettato e mi sento in dovere di 
difendere questo anonimo programmatore. Dunque per fare l'avvocato del 
diavolo potrei dire che quel "lungo ciclo for" mi pare la cosa giusta da 
fare in una funzione generica per calcolare gli zeri di una funzione. 
Una volta trovato il cambio di segno ci sarŕ un algoritmo di bisezione.
E.

 fare in una funzione generica per calcolare gli zeri di una funzione.
Chi portava l'esempio fece questo esempio "in negativo", dal che deduco
che l'anonimo programmatore faceva questa cosa quando avrebbe potuto
applicare qualche strategia più astuta e che il poster semplicemente non
ha chiarificato il contesto per economia di discorso.
Oltretutto non si è parlato di 'ciclo for' per innescare un algoritmo.
Si è parlato di ciclo for e basta. 
-- 
-riko

 il dynamic_cast?
Direi di fare così:
void ProcessScene(vector<Object*> & listObj)
{
	for ( int i=0; i < listObj.size(); ++i )
		listObj[i]->gestisci();
}
E nelle classi Camera e Light definisci «void gestisci()», avendo
dichiarato un «virtual void gestisci() = 0» in Object; aggiungi
argomenti se necessario.
In questo modo, il giorno che hai un terzo tipo di Object non devi
andare a caccia di funzioni come ProcessScene in cui devi aggiungere
nuovi pezzi.
Nota che se listObj è molto grande e le operazioni di gestisci non sono
relativamente pesanti, potrebbe essere una buona idea scrivere:
	const int numberOfObjects = listObj.size();
	for ( int i=0; i < numberOfObjects; ++i )
		...
Ciao,
- -Federico
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.5 (GNU/Linux)
Comment: Using GnuPG with SUSE - 
http://enigmail.mozdev.org
iD8DBQFIwT5qBIpu+y7DlLcRAiNmAKCTzErijMA9smJc+r6NdsGBTcZIZgCeNkYZ
9ulNxhysgy8hL6go79HkcCs=
=ZPBC
-----END PGP SIGNATURE-----