Newsgroup: it.comp.lang.c++
Titolo: dynamic_cast per confrontare il contenuto di classi derivate...

ciao a tutti, sto imparando ad usare il dynamic_cast....
aiutatemi!
ho una classe base vistuale pura,
class Handle
e delle sotto classi,
class WndHandle : public Handle{
public:
    HWND hWnd;
    //...
};
class MenuHAndle : public Handle{
public:
    HMENU hMenu;
    //...
};
la mia idea era di implementare un metodo operator== per confontare due
generici Handle:
vorrei che
bool operator==(const Handle& A, const Handle& B)
prima confrontasse se i due handle sono dello stesso tipo, se non lo sono mi
ritorna un bel "false"...
se sono invece dello stesso tipo, vorrei che mi restituisse
return A.hWnd == B.hWnd;
se sono WndHandle, oppure se sono MenuHandle
return A.hMenu == B.hMenu;
come posso fare???

Ok... ho un idea... ma non ne sono sicuro.... mi dite la vostra???
Se faccio cosě come va????
Il problema, che mi scompiglia, č che ero abituato a chiamare operator==
come funzione friend, e non come metodo delle classi....
mi leggete un attimo puo' funzionare cosě????
Grazie mille!!!
// Dichiarazione classi ------------------------------
class Handle {
 public:
 virtual bool operator==(const Handle&) = 0;
};
class WndHandle : public Handle {
public:
 bool operator==(const Handle&);
 HWND hWnd;
};
class MenuHandle : public Handle {
public:
 bool operator==(const Handle&);
 HMENU hMenu;
};
// Metodi ---------
bool WndHandle::operator==(const Handle& Hand)
{
 const WndHandle* NewHand = dynamic_cast<const WndHandle*>(&Hand);
 if(NewHand) return hWnd == NewHand->hWnd;
 else return false;
};
bool MenuHandle::operator==(const Handle& Hand)
{
 const MenuHandle* NewHand = dynamic_cast<const MenuHandle*>(&Hand);
 if(NewHand) return hMenu == NewHand->hMenu;
 else return false;
};

 wrote in message
news:1lZW9.27249$ZE.7...@twister2.libero.it...

Penso che dovresti guardarti typeid e type_info.
Da MSDN:
******************************************
typeid( type-id )
typeid( expression )
The typeid operator allows the type of an object to be determined at
run-time.
The result of a typeid expression is a const type_info&. The value is a
reference to a type_info object that represents either the type-id or the
type of the expression, depending on which form of typeid is used. See
type_info Class for more information.
*******************************************
The type_info class describes type information generated within the program
by the compiler. Objects of this class effectively store a pointer to a name
for the type and an encoded value suitable for comparing two types for
equality or collating order. The encoding rules and collating sequence for
types are unspecified and may differ between programs.
class type_info {
public:
   virtual ~type_info();
   int operator==(const type_info& rhs) const;
   int operator!=(const type_info& rhs) const;
   int before(const type_info& rhs) const;
   const char* name() const;
   const char* raw_name() const;
private:
   ...
};
Note   You must include the typeinfo.h header file in order to use the
type_info class.
*********************************************************
Maurus


Ti ho preso il tuo codice e ho messo un po' di scritte per vedere se andava
tutto bene, modificando HWND e HMENU in tipi piu' standard, tanto il
risultato non cambia.
Eccoti il risultato:
#include <iostream>
typedef int* HWND;
typedef char* HMENU;
class Handle
{
 public:
 virtual bool operator==(const Handle&) = 0;
};
class WndHandle : public Handle
{
public:
 bool operator==(const Handle&);
 HWND hWnd;
};
class MenuHandle : public Handle
{
public:
 bool operator==(const Handle&);
 HMENU hMenu;
};
// Metodi ---------
bool WndHandle::operator==(const Handle& Hand)
{
   std::cout << "WndHandle::operator==" << std::endl;
   const WndHandle* NewHand = dynamic_cast<const WndHandle*>(&Hand);
 if(NewHand) return hWnd == NewHand->hWnd;
 else
 {
   std::cout << "WndHandle::No Dynamic Cast!" << std::endl;
   return false;
 }
};
bool MenuHandle::operator==(const Handle& Hand)
{
 std::cout << "MenuHandle::operator==" << std::endl;
 const MenuHandle* NewHand = dynamic_cast<const MenuHandle*>(&Hand);
 if(NewHand) return hMenu == NewHand->hMenu;
 {
   std::cout << "MenuHandle::No Dynamic Cast!" << std::endl;
   return false;
 }
};
int main()
{
   int itest = 10;
   char ctest = 0;
   WndHandle wh1, wh2;
   MenuHandle mh1, mh2;
   wh1.hWnd = wh2.hWnd = &itest;
   mh1.hMenu = mh2.hMenu = &ctest;
   if (wh1 == wh2)
      std::cout << "wh1 == wh2" << std::endl;
   else
      std::cout << "wh1 != wh2" << std::endl;
   if (mh1 == mh2)
      std::cout << "mh1 == mh2" << std::endl;
   else
      std::cout << "mh1 != mh2" << std::endl;
   if (wh1 == mh2)
      std::cout << "wh1 == mh2" << std::endl;
   else
      std::cout << "wh1 != mh2" << std::endl;
   system("PAUSE");
   return 0;
}
Scritte sull'output:
WndHandle::operator==
wh1 == wh2
MenuHandle::operator==
mh1 == mh2
WndHandle::operator==
WndHandle::No Dynamic Cast!
wh1 != mh2
Per cui il test e' pienamente riuscito.
Maurus

Oltre ad essere un angelo del C++ sei anche un lampo Maurus!
Grazie 1000...
adesso spero che l'implementazione vada bene!
Ciao!

Nota che anche con l'implementazione di Maurus se qualcuno fa una cosa
tipo:
class MyMenuHandle : public MenuHandle
{
// qualunque cosa
};
il discorso crolla. A quel punto il seguente esempio dara' sempre
risultato errato:
int itest = 10;
MenuHandle m;
m.hMenu = &itest;
MyMenuHandle mm;
mm.hMenu = &itest;
std::cout << ( m == mm ) << '\n';
Nota che se poi in MyMenuHandle definisci l'operatore di uguaglianza
potrei arrivare ad avere che ( m == mm ) != ( mm == m ) .
In generale quando si tratta con classi polimorfiche, definire
l'operatore di uguaglianza in termini di equivalenza e' fonte di guai.
Al tuo posto definirei l'operatore come funzione friend in ciascuna
classe esplicitamente e lascerei che chi confronta mele con pere se la
smazzi da solo.
Ciao,
Nicola


cut.
Hai ragione.
A questo punto non si dovrebbe permettere di derivare ulteriormente dalle
classi MenuHandle e WndHandle allora.
Oppure ri-ragionarci su con i typeid ed i type_info.
Altrimenti come dici tu, sta a chi fa i confronti smazzarsi il problema.
Ma non e' un problema di tipo generale questo qua?
Dovrei vedere se esiste un design patterns o almeno un modo diverso di
strutturare il concetto per evitare il problema.
Stavo immaginando il solito discorso della lista o del vettore che accetta
puntatori di classe Handle. Poi una volta inseriti puntatori vari alle 2
sottoclassi, li si prende per fare i confronti. Per cui li' mele e pere
saranno mischiate ancora una volta.
Maurus

Non lo devo riderivare, quindi non mi interessa!
grazie

 saranno mischiate ancora una volta.
Il problema e' che l'operatore==() prende i parametri per reference
per efficenza, e quindi ne subisce il comportamento polimorfico. In
realta' dal punto di vista concettuale andrebbe considerato
strettamente legato al tipo statico degli argomenti.
In effetti la definizione dell'operatore di uguaglianza in termini di
equivalenza, cioe' attraverso il confronto di una determinata porzione
dello stato degli oggetti, ha senso solo per classi che presentano la
semantica dei valori; guarda caso queste non vengono usate in modo
polimorfico e vengono generalmente passate per valore, salvo problemi
di prestazioni.
Quando si tratta con classi con la semantica degli oggetti l'operatore
di uguaglianza andrebbe definito in termini di identita': ciascun
oggetto e' uguale solo a se stesso.
In fondo se tu ed io abbiamo lo stesso gruppo sanguigno e lo stesso
colore degli occhi non siamo "uguali". D'altra parte se a San
Francisco ci sono 6 gradi come a Milano le due temperature sono
uguali, anche se una e' di Milano e l'altra di S.Francisco.
Ciao,
Nicola