/ Forside / Teknologi / Udvikling / C/C++ / Nyhedsindlæg
Login
Glemt dit kodeord?
Brugernavn

Kodeord


Reklame
Top 10 brugere
C/C++
#NavnPoint
BertelBra.. 2425
pmbruun 695
Master_of.. 501
jdjespers.. 500
kyllekylle 500
Bech_bb 500
scootergr.. 300
gibson 300
molokyle 287
10  strarup 270
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



Søg
Reklame
Statistik
Spørgsmål : 177558
Tips : 31968
Nyheder : 719565
Indlæg : 6408925
Brugere : 218888

Månedens bedste
Årets bedste
Sidste års bedste