Stanovení volání konstruktorů a volání virtuálních metod



znění příkladu (vzorový příklad pro demonstraci probírané látky, možností kombinací takovýchto příkladů jsou prakticky nevyčerpatelné – variace na takovýto příklad se může vyskytnout u zkoušky):



#include <iostream>

using std::cout;


class A {

public:

A(void) {cout << 'a';}

A(int) {cout << 'n';}

virtual ~A(void) {cout << 'b';}

void f(void) {cout << 'c';}

virtual void fv(void) {cout << 'd';}

};


class B:public A {

A a;

public:

B(void) {cout << 'e';}

B(int) {cout<< 'm';}

virtual ~B(void) {cout << 'f';}

void f(void) {cout << 'g';fv();}

virtual void fv(void) {cout << 'h';}

};



class C:public A {

B a,c;

A b;

public:

C(void) :b(2),c(1),a(){cout << 'i';}

virtual ~C(void) {cout << 'j';}

void f(void) {cout << 'k';fv();}

};



int main ()

{

A *a;

B b;

A *c = (A*)new C;

a = &b;

a -> f(); // nevirtuální -> volání podle definice -> f z A

a -> fv(); // virtuální -> volání podle vzniku -> fv z B (a ukazuje na b, to vzniklo B)

c -> f(); // nevirtuální -> volání podle definice -> f z A

c -> fv(); // virtuální -> volání podle vzniku -> fv z C (c ukazuje na A, ale vzniklo jako C)

delete c;

b.f(); // nevirtuální -> volání podle definice -> f z B

b.fv(); // virtuální -> volání podle vzniku -> fv z B (b je typu B a vzniklo jako B)

}


Diagram závislostí tříd daného příkladu









Výsledný tisk: aae aaaeaamni c h c d jbfbbfbbb ghh fbb (konstruktory, volání metod, destruktor, volání metod, destruktor).







Zkuste vymazat virtual u destruktorů a všimněte si změny.

Pravidla pro „řešení“ jsou shrnuta na konci přednášek denního studia (asi tohle:
Pravidla pro volání konstruktorů a destruktorů (automatické (definice objektů) i dynamické proměnné (vytvoření pomocí new))
1) volání konstruktor
ů (v každém kroku se začíná od a), pokud byl bod na dané úrovni vyřešen, pokračuje se dalším)
a) konstruktor bázové t
řídy (existuje-li bázová třída, a zde opět od a))
b) konstruktory objekt
ů třídy (existují-li, v pořadí daném definicí objektů ve třídě. Pro každý objekt se provádí a) b) c) ). Předepsané konstruktory v hlavičce konstruktoru neurčují pořadí ale typ.
c) vlastní t
ělo konstruktoru
2) volání destruktor
ů je v opačném pořadí jako volání konstruktorů. Mohou být virtuální (potom se volají v opačném pořadí v jakém došlo ke konstrukci, nehledě na to, čemu je objekt v současnosti přiřazen). Pokud jsou nevirtuální, jsou destruktory volány v opačném pořadí ke konstruktorům, jaké by se volaly pro prvek třídy, které je objekt právě přiřazen. Destruktor je volán na konci definičního bloku pro proměnné v něm definované. Destruktor je volán při delete.

Pravidla pro volání (virtuálních) metod
1) zjistíme, zda-li je volaná metoda virtuální nebo nevirtuální
2) pokud je volaná metoda nevirtuální, rozhoduje “jak to vidí” překladač – neboli je volána taková metoda, která patří k typu (třídě) jak je současný objekt (ukazatel na objekt) definován.
3) pokud je volaná metoda virtuální, nerozhoduje, čemu je aktuálně prvek přiřazen, ale jak “se narodil”. Při vzniku (konstruktor) je mu totiž virtuální metoda přiřazena na základě vznikajícího typu (a zůstává “majetkem” objektu). U objektu se při běžné činnosti nejedná o problém, protože je známo jak objekt vznikl (podle typu v definici). Důležité je to však u ukazatelů, které mohou ukazovat na cokoli (i když z hlediska daného mechanizmu je nutné dodržet to, že přiřazovat by se měl ukazatel na potomka do ukazatele na předka). Potom musíme najít, jak opravdu vznikl objekt (definice, nebo new), na který se právě ukazuje – nezávisle na množství přiřazení, které se staly.
4) Pokud metoda neexistuje, použije se metoda nejbližší (například u předka).











Poslední změna 2009-12-29