|
| Casting Fra : Peer Jensen |
Dato : 15-07-02 19:57 |
|
Forstil jer følgende C++-ting:
CClassA { ... };
class CClassB : public CClassA { ... };
Ved instans af klasse B kan jeg finde generaliseringen A ved gængs upcast,
fx
- CClassA * m_ptrA = dynamic_cast <CClassA*>(m_ptrB);
- CClassA * m_ptrA = (CClassA*)m_ptrB;
- CClassA * m_ptrA = m_ptrB;
Mit problem er den anden vej (downcast) og eksemplet fra MSDN:
CClassB * m_ptrB = new CClassB();
CClassA * m_ptrA = m_ptrB;
const type_info& t = typeid(m_ptrA ); // t holds pointer type_info
const type_info& t1 = typeid(*m_ptrA ); // t1 holds Derived info
Resultat: CClassA* og CClassA* * - jeg havde forventet CClassA* og CClassB*
....?
Jeg oprindelige problem var/er: at på run-time at kunne finde mulige
specialiseringer fra min superklasse, og ønsker ikke at anvende følgende
makroer fra Microsoft: STATIC_DOWNCAST & DYNAMIC_DOWNCAST. Jf. ovenstående
skulle jeg havde fået resultatet: CClassB
Udbygget med: class CClassC : public CClassA { ... };
Resultat: CClassB & CClassC
Yderligere med: class CClassD : public CClassB, CClassC { ... };
Resultat: CClassD (evt. CClassB & CClassC)
Er der noget hjælp med identifikation af specialiseringer...? Drop
flertydighed i første omgang.
--
/Peer
It's not a bug... - it's a feature!
| |
Mogens Hansen (16-07-2002)
| Kommentar Fra : Mogens Hansen |
Dato : 16-07-02 05:52 |
|
"Peer Jensen" <maxfart@hotmail.com> wrote
[snip]
> - CClassA * m_ptrA = dynamic_cast <CClassA*>(m_ptrB);
Overflødig - påtrykker et run-time overhead.
> - CClassA * m_ptrA = (CClassA*)m_ptrB;
Uhensigsigtsmæssigt:
* Foretræk altid C++ cast formerne frem for C cast (i dette tilfælde
static_cast)
* Fratager compileren muligheden for at brokke sig, hvis B rent faktisk
ikke arver public fra A
> - CClassA * m_ptrA = m_ptrB;
Nemlig
>
> Mit problem er den anden vej (downcast) og eksemplet fra MSDN:
MSDN er en glimrende kilde til information om MS-Windows programmering, men
det er ikke en god kilde til C++ programmering.
> CClassB * m_ptrB = new CClassB();
> CClassA * m_ptrA = m_ptrB;
> const type_info& t = typeid(m_ptrA ); // t holds pointer type_info
> const type_info& t1 = typeid(*m_ptrA ); // t1 holds Derived info
> Resultat: CClassA* og CClassA* * - jeg havde forventet CClassA* og
CClassB*
> ...?
Hvorfor havde du ikke forventet CClassA* og CClassB ?
>
Hvis du bruger Microsoft compileren, så husk at RTTI (Run Time Type
Information) ikke er enabled som default!
> Jeg oprindelige problem var/er: at på run-time at kunne finde mulige
> specialiseringer fra min superklasse
Du kan ikke direkte statisk finde mulige specialiseringer af en given klasse
i C++.
Du kan dynamisk (på run-time) undersøge om en klasse arver (public) fra en
anden.
>, og ønsker ikke at anvende følgende
> makroer fra Microsoft: STATIC_DOWNCAST & DYNAMIC_DOWNCAST.
Nemlig.
Hold dig langt væk fra de makroer - så vidt jeg husker blev de lavet fordi
Microsoft compileren (før V5.0) ikke understøttede de "nye" C++ cast former.
[snip]
> Er der noget hjælp med identifikation af specialiseringer...? Drop
> flertydighed i første omgang.
dynamic_cast kan bruges på polymorphy typer.
<code>
#include <typeinfo>
#include <iostream>
using namespace std;
class A
{
public:
virtual ~A() {}
};
class B : public A
{
};
class C : public A
{
};
int main()
{
B b;
C c;
cout << typeid(b).name() << endl;
cout << typeid(c).name() << endl;
A* pa = &b;
cout << typeid(pa).name() << endl;
cout << typeid(*pa).name() << endl;
pa = &c;
cout << typeid(*pa).name() << endl;
}
</code>
<output>
B
C
A *
B
C
</output>
Bemærk dog at der er ikke nogen garanti for at "typeid(...).name" for
forskellige typer giver forskellige resultater - endsige meningsfulde
resultater. Jeg har dog aldrig oplevet at de ikke giver meningsfulde
resultater.
Der er garanti for at typeid(T1) != typeid(T2), hvis T1 og T2 er forskellige
typer.
Venlig hilsen
Mogens Hansen
| |
Peer Jensen (17-07-2002)
| Kommentar Fra : Peer Jensen |
Dato : 17-07-02 19:28 |
|
"Mogens Hansen" <mogens_h@dk-online.dk> skrev i en meddelelse
news:ah08he$1o06$1@news.cybercity.dk...
> > - CClassA * m_ptrA = dynamic_cast <CClassA*>(m_ptrB);
> Overflødig - påtrykker et run-time overhead.
Den kaster en bad_cast exception, men håndteringen af fejlen er vanskelig.
Det forudsætter kendskab til arvehierarkiet, hvilket gør koden mindre
fleksibel.
> > - CClassA * m_ptrA = (CClassA*)m_ptrB;
> Uhensigsigtsmæssigt:
> * Foretræk altid C++ cast formerne frem for C cast (i dette tilfælde
> static_cast)
> * Fratager compileren muligheden for at brokke sig, hvis B rent faktisk
> ikke arver public fra A
Jeg mindes den ofte fra lærebøgerne!
[cut]
> > Resultat: CClassA* og CClassA* * - jeg havde forventet CClassA* og
> CClassB*
> > ...?
>
> Hvorfor havde du ikke forventet CClassA* og CClassB ?
Joe :)
> Hvis du bruger Microsoft compileren, så husk at RTTI (Run Time Type
> Information) ikke er enabled som default!
Done!
> > Jeg oprindelige problem var/er: at på run-time at kunne finde mulige
> > specialiseringer fra min superklasse
>
> Du kan ikke direkte statisk finde mulige specialiseringer af en given
klasse
> i C++.
> Du kan dynamisk (på run-time) undersøge om en klasse arver (public) fra en
> anden.
Nogen ideer til at iterere en generaliseringsstruktur på run-time
tidspunktet? Jeg har en del persistente objekter som jeg gerne vil have
mappet (indirect mapping) til brug for en brooker. Jeg kunne få de nedarvede
objekter til at melde sig ind i mappingsstrukturen i konstruktøren, men det
er meget lidt kønt og giver nogle frygtelige bindinger.
[cut]
--
/Peer
It's not a bug... - it's a feature!
| |
Mogens Hansen (17-07-2002)
| Kommentar Fra : Mogens Hansen |
Dato : 17-07-02 21:24 |
|
"Peer Jensen" <maxfart@hotmail.com> wrote
> "Mogens Hansen" <mogens_h@dk-online.dk> skrev
>
> > > - CClassA * m_ptrA = dynamic_cast <CClassA*>(m_ptrB);
> > Overflødig - påtrykker et run-time overhead.
> Den kaster en bad_cast exception, men håndteringen af fejlen er vanskelig.
Formodentlig ikke.
Når man bruger "dynamic_cast" for at få en pointer ("dynamic_cast<T*>(t)"),
returneres 0, hvis objektet ikke har den forventede type.
Når man bruger "dynamic_cast" for at få en reference ("dynamic_cast<T&>(t)")
smides der en bad_cast exception, hvis objektet ikke har den forventede
type.
> Det forudsætter kendskab til arvehierarkiet, hvilket gør koden mindre
> fleksibel.
Jeg forstår ikke præcist hvad du mener - kan du give et eksempel ?
[snip]
> Nogen ideer til at iterere en generaliseringsstruktur på run-time
> tidspunktet?
Sikkert ...
> Jeg har en del persistente objekter som jeg gerne vil have
> mappet (indirect mapping) til brug for en brooker. Jeg kunne få de
nedarvede
> objekter til at melde sig ind i mappingsstrukturen i konstruktøren, men
det
> er meget lidt kønt og giver nogle frygtelige bindinger.
Der skal nok lidt flere detaljer på, for at forstå hvad dit præcise problem
er.
Venlig hilsen
Mogens Hansen
| |
|
|