/ 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
Polymorfi - v-tabel - v-ptr ?
Fra : Torben W. Hansen


Dato : 10-12-02 12:52

Glædelig jul allesammen,

Ved læsning i "C++ Grundbog" af Jesse Liberty i kapitel 17, "Polymorfi og
afledte klasser" beskrives, hvorledes et afledt objekt kan kaldes gennem en
pointer til basisklassen.

Jeg ved ikke om jeg har forstået det rigtigt, men der står noget i retning
af:

1.
Når man så erklærer en pointer til en basis-klasse og initialiserer denne
til et oprettet objekt af den afledte klasse, kan man via pointeren kalde en
metode i det afledte objekt såfremt metoden har en tilsvarende virtuel
metode med samme signatur i basis-klassen.

2.
For hver basisklasse indeholdende virtuelle metoder, genererer compileren en
v-tabel af pointere til hver af de virtuelle metoder i basisobjektet. Når
der oprettes et afledt objekt, indeholder dette objekt en v-ptr, der i
første omgang peger på en af de virtuelle metoder i basisklassen, men hvis
der i det afledte objekt findes en alternativ metode med samme signatur som
en af de virtuelle metoder i basisklassen, bliver v-ptr modificeret til at
pege på denne alternative metode.

3.
Af ovenstående fremgår også at en pointer til et basisobjekt kan
initialiseres til at pege på et afledt objekt, dvs. et objekt af en anden
type. Hvordan kan man det? Et afledt objekt er vel af en anden størrelse end
dets basisobjekt ?
Som jeg har forstået består et afledt objekt af både basis del+afledt del,
hvor et basis-objekt udelukkende består af basis-delen.

Jeg føler mig noget usikker på ovenstående, så alle korrektioner/tilføjelser
eller kommentarer til ovenstående er særdeles velkomne...

Med venlig hilsen
Torben W. Hansen



 
 
Mogens Hansen (10-12-2002)
Kommentar
Fra : Mogens Hansen


Dato : 10-12-02 20:47


"Torben W. Hansen" <mail@ins-intersoft.com> wrote in message
news:at4ke7$16j6$1@news.cybercity.dk...

Nedenstående kommentarer afspejler ikke _krav_ til hvordan virtuelle metoder
er implementeret.
Det er udelukkende et udtryk for hvordan det ofte bliver implementeret.

Nedenstående vil blive brugt som eksempel:

class a
{
public:
virtual ~a();
void foo_a();
virtual void v_foo_a1();
virtual void v_foo_a2

private:
int a_i;
};

class b : public a
{
public:
void foo_b();
virtual void v_foo_a1();
virtual void v_foo_b1();

private:
int b_i;
};

> Ved læsning i "C++ Grundbog" af Jesse Liberty i kapitel 17, "Polymorfi og
> afledte klasser" beskrives, hvorledes et afledt objekt kan kaldes gennem
en
> pointer til basisklassen.
>
> Jeg ved ikke om jeg har forstået det rigtigt, men der står noget i retning
> af:
>
> 1.
> Når man så erklærer en pointer til en basis-klasse og initialiserer denne
> til et oprettet objekt af den afledte klasse, kan man via pointeren kalde
en
> metode i det afledte objekt såfremt metoden har en tilsvarende virtuel
> metode med samme signatur i basis-klassen.

Når man har en pointer til basis-klasse har man adgang til det interface som
basis-klassen stiller til rådighed.
Man kan således kalde metoderne uanset om de er virtuelle eller ej.

Det vil sige:
b b_obj;
a* a_ptr = &b_obj;

a_ptr->foo_a(); // OK a::foo_a called
a_ptr->v_foo_a1(); // OK b::v_foo_a1 called
a_ptr->v_foo_a2(); // OK a::v_foo_a2 called
a_ptr->foo_b(); // Error !
a_ptr->v_foo_b(); // Error !

Hvis metoden er virtuel bliver det (almindeligvis) bestemt på run-time
hvilken funktion, der faktisk bliver kaldt.
Hvis metoden ikke er virtuel bliver det bestemt på compile-time hvilken
funktion, der faktisk bliver kaldt.

Det spiller en rolle når man skriver en afledt klasse om metoderne er
virtuelle eller ej.
Man bør ikke overskrive ikke virtuelle metoder.

>
> 2.
> For hver basisklasse indeholdende virtuelle metoder, genererer compileren
en
> v-tabel af pointere til hver af de virtuelle metoder i basisobjektet.

Det er for så vidt ligegyldigt om det er en basis-klasse - altså om der er
nogen der _faktisk_ arver fra den.
Men ja.


> Når
> der oprettes et afledt objekt, indeholder dette objekt en v-ptr, der i
> første omgang peger på en af de virtuelle metoder i basisklassen, men hvis
> der i det afledte objekt findes en alternativ metode med samme signatur
som
> en af de virtuelle metoder i basisklassen, bliver v-ptr modificeret til at
> pege på denne alternative metode.

Næsten.
vptr arver den afledte klasse fra basis-klassen.
For hver klasse med virtuelle funktioner, findes der en virtuel tabel -
vtbl.
Tabellen indeholder pointere til samtlige virtuelle metoder som klassen
har - både dem den arver og dem den overskrive.
vptr sættes til at pege på den vtbl for den klasse som objektet faktisk er.

De virtuelle tabeller (vtbl) for ovenstående klasser vil f.eks. kunne være:

Index a b
-------------- --------------
0 | dtor a:a | | dtor b:b |
-------------- --------------
1 | a::v_foo_a1 | | b::v_foo_a1 |
-------------- --------------
2 | a::v_foo_a2 | | a::v_foo_a2 |
-------------- --------------
3 | b::v_foo_b1 |
--------------

Og udlægget af objekterne vil kunne være:
a b
-------------- --------------
| vptr | | vptr |
-------------- --------------
| a_i | | a_i |
-------------- --------------
| b_i |
--------------

Det vil sige at

b b_obj;
a* a_ptr = &b_obj;

a_ptr->foo_a(); // OK a::foo_a called
a_ptr->v_foo_a1(); // OK b::v_foo_a1 called
a_ptr->v_foo_a2(); // OK a::v_foo_a2 called

vil blive "oversat" til følgende "C"

b b_obj;
b_ctor(&b_obj); // constructor

a* a_ptr = &b_obj;

a__foo_a(a_ptr);
(*a_ptr->vptr[1])(a_ptr);
(*a_ptr->vptr[2])(a_ptr);

hvor

void a_ctor(a* a_obj)
{
a_obj->vptr = class_a_vtbl;
}

void b_ctor(b* b_obj)
{
a_ctor(b_obj);
b_obj->vptr = class_b_vtbl;
}

void a__foo_a(a* this);


> 3.
> Af ovenstående fremgår også at en pointer til et basisobjekt kan
> initialiseres til at pege på et afledt objekt, dvs. et objekt af en anden
> type. Hvordan kan man det? Et afledt objekt er vel af en anden størrelse
end
> dets basisobjekt ?

Ja, muligvis - men en pointer til basisklassen har samme størrelse som en
pointer til den afledte.
Den del af den afledte klasse som er arvet, har samme udlæg som basis
klassen. Det samme gælder for vtbl.

> Som jeg har forstået består et afledt objekt af både basis del+afledt del,
> hvor et basis-objekt udelukkende består af basis-delen.

Ja.

> Jeg føler mig noget usikker på ovenstående, så alle
korrektioner/tilføjelser
> eller kommentarer til ovenstående er særdeles velkomne...

En god kilde til hvad der foregår inde bag C++ er
Inside the C++ Object Model
Stanley B. Lippman
ISBN 0-201-83454-5
Bemærk at den er skrevet i 1996 - altså før C++ Standarden blev vedtaget.
Det ændrer dog ikke på min anbefaling.

Venlig hilsen

Mogens Hansen



Torben W. Hansen (10-12-2002)
Kommentar
Fra : Torben W. Hansen


Dato : 10-12-02 22:57

Tak for hjælpen Mogens,

"Mogens Hansen" <mogens_h@dk-online.dk> skrev i en meddelelse
news:at5g2o$2dfv$1@news.cybercity.dk...

> Man kan således kalde metoderne uanset om de er virtuelle eller ej.
Ja den er jeg med på - men det jeg mente var bare, for at få adgang til
metoderne i den _afledte_ klasse (b) skal der være en tilsvarende virtuel
metode med samme signatur i basisklassen (b) ...eller hvad ?


> Det vil sige:
> b b_obj;
> a* a_ptr = &b_obj;
>
> a_ptr->foo_a(); // OK a::foo_a called
> a_ptr->v_foo_a1(); // OK b::v_foo_a1 called
> a_ptr->v_foo_a2(); // OK a::v_foo_a2 called
> a_ptr->foo_b(); // Error !
> a_ptr->v_foo_b(); // Error !
>
> Hvis metoden er virtuel bliver det (almindeligvis) bestemt på run-time
> hvilken funktion, der faktisk bliver kaldt.
> Hvis metoden ikke er virtuel bliver det bestemt på compile-time hvilken
> funktion, der faktisk bliver kaldt.
Den er jeg også med på...


> Man bør ikke overskrive ikke virtuelle metoder.
Her kommer jeg lidt til kort fordi bogen fordansker udtrykkene. Der bruges
"tilsidesætte" og "overstyre", hvor sidstnævnte er "overload". Der bruges
"tilsidesætte" for metoder med identisk signatur.
Mener du med "overskrive" så "tilsidesætte" (og hvad hedder det på engelsk)
?


> Det er for så vidt ligegyldigt om det er en basis-klasse - altså om der er
> nogen der _faktisk_ arver fra den.
> Men ja.
OK - bare nogle af metoderne i en klasse er virtuelle så oprettes der en
vtbl for klassen

> Næsten.
> vptr arver den afledte klasse fra basis-klassen.
Dit svar her er et af de længere, så det har jeg ikke fået tygget igennem
endnu - men jeg vender måske frygteligt tilbage...


> Ja, muligvis - men en pointer til basisklassen har samme størrelse som en
> pointer til den afledte.
Det forstår jeg ikke helt, da eksempelvis pointere til char og til float vel
også er af samme størrelse, men det medfører vel ikke at man umiddelbart kan
tildele den ene til den anden (uden type cast af den ene pointer) ?
Eksempel:
float tal;
char *ptr = &tal; // ulovligt

> En god kilde til hvad der foregår inde bag C++ er
> Inside the C++ Object Model
> Stanley B. Lippman
> ISBN 0-201-83454-5
> Bemærk at den er skrevet i 1996 - altså før C++ Standarden blev vedtaget.
> Det ændrer dog ikke på min anbefaling.
Tak for anbefalingen.

Med venlig hilsen
Torben W. Hansen





Torben W. Hansen (10-12-2002)
Kommentar
Fra : Torben W. Hansen


Dato : 10-12-02 22:57

Tak for hjælpen Mogens,

"Mogens Hansen" <mogens_h@dk-online.dk> skrev i en meddelelse
news:at5g2o$2dfv$1@news.cybercity.dk...

> Man kan således kalde metoderne uanset om de er virtuelle eller ej.
Ja den er jeg med på - men det jeg mente var bare, for at få adgang til
metoderne i den _afledte_ klasse (b) skal der være en tilsvarende virtuel
metode med samme signatur i basisklassen (b) ...eller hvad ?


> Det vil sige:
> b b_obj;
> a* a_ptr = &b_obj;
>
> a_ptr->foo_a(); // OK a::foo_a called
> a_ptr->v_foo_a1(); // OK b::v_foo_a1 called
> a_ptr->v_foo_a2(); // OK a::v_foo_a2 called
> a_ptr->foo_b(); // Error !
> a_ptr->v_foo_b(); // Error !
>
> Hvis metoden er virtuel bliver det (almindeligvis) bestemt på run-time
> hvilken funktion, der faktisk bliver kaldt.
> Hvis metoden ikke er virtuel bliver det bestemt på compile-time hvilken
> funktion, der faktisk bliver kaldt.
Den er jeg også med på...


> Man bør ikke overskrive ikke virtuelle metoder.
Her kommer jeg lidt til kort fordi bogen fordansker udtrykkene. Der bruges
"tilsidesætte" og "overstyre", hvor sidstnævnte er "overload". Der bruges
"tilsidesætte" for metoder med identisk signatur.
Mener du med "overskrive" så "tilsidesætte" (og hvad hedder det på engelsk)
?


> Det er for så vidt ligegyldigt om det er en basis-klasse - altså om der er
> nogen der _faktisk_ arver fra den.
> Men ja.
OK - bare nogle af metoderne i en klasse er virtuelle så oprettes der en
vtbl for klassen

> Næsten.
> vptr arver den afledte klasse fra basis-klassen.
Dit svar her er et af de længere, så det har jeg ikke fået tygget igennem
endnu - men jeg vender måske frygteligt tilbage...


> Ja, muligvis - men en pointer til basisklassen har samme størrelse som en
> pointer til den afledte.
Det forstår jeg ikke helt, da eksempelvis pointere til char og til float vel
også er af samme størrelse, men det medfører vel ikke at man umiddelbart kan
tildele den ene til den anden (uden type cast af den ene pointer) ?
Eksempel:
float tal;
char *ptr = &tal; // ulovligt

> En god kilde til hvad der foregår inde bag C++ er
> Inside the C++ Object Model
> Stanley B. Lippman
> ISBN 0-201-83454-5
> Bemærk at den er skrevet i 1996 - altså før C++ Standarden blev vedtaget.
> Det ændrer dog ikke på min anbefaling.
Tak for anbefalingen.

Med venlig hilsen
Torben W. Hansen





Torben W. Hansen (11-12-2002)
Kommentar
Fra : Torben W. Hansen


Dato : 11-12-02 13:21


"Mogens Hansen" <mogens_h@dk-online.dk> skrev i en meddelelse
news:at5g2o$2dfv$1@news.cybercity.dk...


Lige en rettelse til mit tidligere fremsendte...
> Man kan således kalde metoderne uanset om de er virtuelle eller ej.
Ja den er jeg med på - men det jeg mente var bare, for at få adgang til
metoderne i den _afledte_ klasse (b) skal der være en tilsvarende virtuel
metode med samme signatur i basisklassen (a) ...eller hvad ?



Jeg kan ikke lige gennemskue hvad du mener nedenfor ?
> vptr arver den afledte klasse fra basis-klassen. (specielt denne sætning)
> For hver klasse med virtuelle funktioner, findes der en virtuel tabel -
> vtbl. (OK)
> Tabellen indeholder pointere til samtlige virtuelle metoder som klassen
> har (OK) - både dem den arver og dem den overskrive. (og denne sætning)
> vptr sættes til at pege på den vtbl for den klasse som objektet faktisk
er. (OK)



> De virtuelle tabeller (vtbl) for ovenstående klasser vil f.eks. kunne
være:
>
> Index a b
> -------------- --------------
> 0 | dtor a:a | | dtor b:b |
> -------------- --------------
> 1 | a::v_foo_a1 | | b::v_foo_a1 |
> -------------- --------------
> 2 | a::v_foo_a2 | | a::v_foo_a2 |
> -------------- --------------
> 3 | b::v_foo_b1 |
> --------------
Oversat til "C" måske noget i retning af :
void (*class_a_vtbl[3])();
void (*class_b_vtbl[4])();
???
Men hvorfor er "dtor b:b" med i b's vtbl - der er vel ingen virtuel
destructor i "class b" ?


> Og udlægget af objekterne vil kunne være:
> a b
> -------------- --------------
> | vptr | | vptr |
> -------------- --------------
> | a_i | | a_i |
> -------------- --------------
> | b_i |
> --------------
Oversat til "C" f.eks. som :
typedef struct
{
void *vptr;
int a_i;
} a;

typedef struct
{
a a_obj;
int b_i;
} b;
???

> Det vil sige at
>
> b b_obj;
> a* a_ptr = &b_obj;
>
> a_ptr->foo_a(); // OK a::foo_a called
> a_ptr->v_foo_a1(); // OK b::v_foo_a1 called
> a_ptr->v_foo_a2(); // OK a::v_foo_a2 called
>
> vil blive "oversat" til følgende "C"
>
> b b_obj;
> b_ctor(&b_obj); // constructor
"b_obj.vptr" peger nu på "class_b_vtbl".

> a* a_ptr = &b_obj;
"a_ptr->.vptr" peger nu også på "class_b_vtbl".

> a__foo_a(a_ptr);
Ovenstående er et almindeligt "ikke virtuelt" funktionskald.

> (*a_ptr->vptr[1])(a_ptr);
> (*a_ptr->vptr[2])(a_ptr);
Dvs. at de to ovenstående virtuelle funktionskald benytter
funktionspointerne fra "class_b_vtbl[1] og "class_b_vtbl[2] "
hvor "class_b_vtbl[1]" peger på "b::v_foo_a1" og "class_b_vtbl[2]" peger på
"a::v_foo_a2".

> hvor
>
> void a_ctor(a* a_obj)
> {
> a_obj->vptr = class_a_vtbl;
> }
>
> void b_ctor(b* b_obj)
> {
> a_ctor(b_obj);
Her initialiseres b_obj->vptr til class_a_vtbl;
> b_obj->vptr = class_b_vtbl;
og dernæst til class_b_vtbl;

> }
>
> void a__foo_a(a* this);

Kan man drage følgende konklusion:
Hvis en klasse_a, indeholdende virtuelle metoder, har en afledt klasse_b, så
genereres der en "vtbl" for begge klasser - samt en "vptr" for hvert objekt
af begge klasser - også selvom den afledte klasse_b i sig selv ikke
indeholder virtuelle erklæringer ?

Med venlig hilsen
Torben W. Hansen




Henning Larsen (11-12-2002)
Kommentar
Fra : Henning Larsen


Dato : 11-12-02 17:23

On Tue, 10 Dec 2002 12:52:01 +0100, "Torben W. Hansen"
<mail@ins-intersoft.com> wrote:

>Glædelig jul allesammen,
>
>Ved læsning i "C++ Grundbog" af Jesse Liberty i kapitel 17, "Polymorfi og
>afledte klasser" beskrives, hvorledes et afledt objekt kan kaldes gennem en
>pointer til basisklassen.
[cut]

Hej

se evt. denne side:
http://www.codesourcery.com/cxx-abi/cxx-vtable-ex.html

Hening

Henning Larsen (11-12-2002)
Kommentar
Fra : Henning Larsen


Dato : 11-12-02 17:23

On Tue, 10 Dec 2002 12:52:01 +0100, "Torben W. Hansen"
<mail@ins-intersoft.com> wrote:

>Glædelig jul allesammen,
>
>Ved læsning i "C++ Grundbog" af Jesse Liberty i kapitel 17, "Polymorfi og
>afledte klasser" beskrives, hvorledes et afledt objekt kan kaldes gennem en
>pointer til basisklassen.
[cut]

Hej

se evt. denne side:
http://www.codesourcery.com/cxx-abi/cxx-vtable-ex.html

Hening

Torben W. Hansen (11-12-2002)
Kommentar
Fra : Torben W. Hansen


Dato : 11-12-02 20:01

"Henning Larsen" <post.reply@to.group> skrev i en meddelelse
news:h6tt1v4n8i32vggpm06coteem7ejd4ssc6@4ax.com...

se evt. denne side:
http://www.codesourcery.com/cxx-abi/cxx-vtable-ex.html

Det ser interessant ud...

Tusind tak!

med venlig hilsen
Torben W. Hansen



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

Månedens bedste
Årets bedste
Sidste års bedste