"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