|
| Virtual functions Fra : Jacob Jensen |
Dato : 21-08-04 10:11 |
|
Jeg sidder lige og læser lidt om virtual functions.
Så vidt jeg kan se (jeg har også testet lidt) overrider en arvende klasse
altid overklassens funktion. Men hvis man erklærer en peger til en klasse
vil det være overklassens funktion der bliver brugt med mindre den er
virtual. Er det korrekt?
En anden ting er at hvis man definerer funktioner A og B i en overklasse og
lader A foretage et kald til B, hvorefter man forsøger at override
funktionen B i en arvende klasse, vil det stadig være overklassens
B-funktion der bliver kaldt af A (selv af den arvede version af A i den
arvende klasse). Er det korrekt? Med mindre man altså erklærer B som
virtual, korrekt?
Pure virtual functions forvirrer mig en del mere. Hvorfor overhovedet
erklære en funktion i baseklassen hvis man alligevel skal override den i
alle arvende klasser?
Jacob
| |
Bertel Brander (21-08-2004)
| Kommentar Fra : Bertel Brander |
Dato : 21-08-04 19:38 |
|
Jacob Jensen wrote:
>
> Pure virtual functions forvirrer mig en del mere. Hvorfor overhovedet
> erklære en funktion i baseklassen hvis man alligevel skal override den i
> alle arvende klasser?
Der kan være mange tilfælde hvor det kan være en fordel, f.ex:
1: Man har to klasser der er stort set ens, eneste forskel er
nogle få funktioner, prototypen for de to funktioner er
dog den samme for begge class'er. Så laver man en base class
hvor disse funktioner er virtual, og laver to class'er
der arver fra denne class, og som implementerer disse funktioner.
Da base class'en i sig selv ikke er brugbar laver man funktionerne
pure virtual, da man derved ikke kan lave et object af denne class.
Ved at bruge denne model kan base class'en tilgå disse ikke eksisterende
funktioner.
2: Lave et pænt interface. En class definition indeholder typisk to
ting:
A: Et interface dvs nogle public funktioner og variable
B: Nogle implementations detaljer, dvs de private og protected members.
Ved at lave en base class der kun indeholder public virtuelle funktioner
har man adskilt de to dele. Brugerene af class'en kender kun det public
interface, og et andet sted defineres en class der arver fra denne base
class og som implementerer resten. Denne model kan kombineres med
"factories" også kaldet virtuelle constructorer.
/b
| |
Mogens Hansen (22-08-2004)
| Kommentar Fra : Mogens Hansen |
Dato : 22-08-04 06:31 |
|
"Jacob Jensen" <omo@adslhome.dk> wrote:
> Jeg sidder lige og læser lidt om virtual functions.
>
> Så vidt jeg kan se (jeg har også testet lidt) overrider en arvende klasse
> altid overklassens funktion. Men hvis man erklærer en peger til en klasse
> vil det være overklassens funktion der bliver brugt med mindre den er
> virtual. Er det korrekt?
Det kommer an på hvilken type pegeren har.
Givet 2 klasser:
class base
{...};
class derived : public base
{...};
med 2 tilhørende instanser
base b;
derived d;
så er der ingen tvivl om at "b" er af typen "base" og "d" er af typen
"derived".
Hvis vi så laver en peger
base* pb;
så har den typen "peger til base".
Hvis vi sætter den til at pege på "d"
pb = &d;
så har vi 2 typer pegere i spil, nemlig:
* pb som stadig er af typen "peger til base".
Man kalder det den statiske type, fordi den er kendt på
oversættelsestidspunktet
* &d som er af typen "peger til derived"
Man kaldet det den dynamiske type, for den kun er kendt på
kørselstidspunktet
Bemærk at den statiske type og den dynamiske type kan være den samme,
hvilket vil være tilfældet hvis vi skriver
pb = &b;
Hvis man bruger en peger til at kalde en funktion med, vil den kaldte
funktion være bestemt af:
* den statiske type, hvis funktionen er _ikke_ virtuel
* den dynamiske type, hvis funktionen er virtuel
>
> En anden ting er at hvis man definerer funktioner A og B i en overklasse
og
> lader A foretage et kald til B, hvorefter man forsøger at override
> funktionen B i en arvende klasse, vil det stadig være overklassens
> B-funktion der bliver kaldt af A (selv af den arvede version af A i den
> arvende klasse). Er det korrekt?
Dit spørgsmål efterlader et par åbne punkter:
* Er A overskrevet i den afledte klasse ?
* Er A virtuel ?
* Er A kald via en pointer og hvad der i givet fald pointerens statiske
type ?
Men jeg tror ikke at det spiller ikke den store rolle for at svare på dit
spørgsmål, så bare lad være med at blande de ting med ind.
Hvis en member-funktion A kalder en anden member-funktion B vil der blive
samme funktion som hvis man kaldte B via en peger med samme statiske type
som det niveau i arvehierakiet som A tilhører.
Altså hvis B er virtuel vil det være funktionen fra pegerens (og dermed
objektets) dynamiske type.
Hvis B ikke er virtuel vil det være funktionen fra pegerens statiske type.
> Med mindre man altså erklærer B som
> virtual, korrekt?
Almideligvis giver det ikke mening at overskrive ikke virtuelle metoder.
>
> Pure virtual functions forvirrer mig en del mere. Hvorfor overhovedet
> erklære en funktion i baseklassen hvis man alligevel skal override den i
> alle arvende klasser?
Den typiske brug er til at definere et interface.
Forestil dig et tegneprogram.
Her kunne en tegning være en samling af figurer (firkanter, linier,
trekanter og cirkler).
Det kan man udtrykke i et arvehieraky
class figure {...};
class rectangle : public figure {...};
Fælles for dem er at en figur kan tegne sig selv, men alle figurers måde at
tegne sig på er forskellig. Det giver derfor ikke mening af have en
tegnerutine i basisklassen. Det kan man udtrykke ved pure virtual funktioner
class figure
{
public:
virtual ~figure(); // virtual destructor
virtual void draw() = 0; // pure virtual
...
};
class rectangle : public figure
{
public:
virtual void draw(); // implemented
};
Husk at hvis en klasse har een virtuel metode, bør man almideligvis erklære
destructoren virtuel.
Bemærk også at hvis en basisklasse har erklæret en funktion virtuel, vil den
være virtuel i alle afledte klasser, uanset om man skriver virtuel eller ej.
Venlig hilsen
Mogens Hansen
| |
|
|