Virtuális függvények és absztrakt osztályok

Előadás 18. Többszörös öröklés

Egy osztály lehet létrehozni bármely számú bázis osztályok. Miután több mint egy közvetlen szülő osztály úgynevezett többszörös öröklés.
osztály;
B osztály;
C osztály;
osztályú D. nyilvánosságra, nyilvános B, magán C;

Egy mutatót az származtatott osztály átadhatók egy függvény, amely elvárja egy mutatót az egyik a bázis osztályok. E mechanizmus magában foglalja az egyszerű összeállítása technikák, hogy egy függvény, amely elvárja a mutató egy alap osztály, lásd a részét a származtatott osztály, amely eltér attól, amelyik megjelenik a funkció, amely elvárja a mutatót egy másik alap osztály. Virtuális függvények a szokásos módon működnek.
osztály ; B osztály ; C osztály: nyilvános A, nyilvános B ; void f1 (A * p) f1 ();> void f2 (B * p) f2 ();> void main () g (); // helyes p-> H (); // Hiba: h funkció nem tagja a osztályú dynamic_cast (P) -> H (); // Helyes>

Az osztály nem lehet meghatározni, mint egy azonnali alap osztály többször, de lehet, hogy többször közvetett alap osztály.

osztály <.>; B osztály: nyilvános A, nyilvánosságra;

osztály <.>; B osztály: nyilvános A; C osztály: nyilvános A; D osztályú: nyilvános B, nyilvános C;

Itt egy D osztályú létesítmény lesz két al-objektum osztály A.

A származtatott osztály és annak alap osztályok leírható mint egy irányított aciklikus gráf.

Mivel objektum D két működtetés objektum A. (explicit vagy implicit) között az A és egy mutató a mutató egy D egyértelmű, és ezért tilos.

D * PD = új D; A * pa = pd; PA = (A *) PD; pa = (B *) pd; pa = (C *) pd;

// Ambiguity! // Minden ugyanaz a kétértelműség! // csökkentését egy mutató a B tárgy // csökkentését egy mutatót az objektum C.

Azonban az osztály lehet közvetlen és közvetett alap osztály.

osztály <.>; B osztály: nyilvános A <.>; C osztály: nyilvános A <.>; D osztályú: nyilvános A, nyilvános B, nyilvános C <.>; pa = pd; pa = (B *) pd; pa = (C *) pd;

// Can! // Hoz egy mutatót az objektum el azonnal D // csökkentését egy mutató a B tárgy // csökkentését egy mutatót az objektum C.

// A :: f (int) megnyíltak

// A funkciót A :: f (int) // Hívás funkció B1 :: f (dupla) // hívás funkciót B2 :: f (char) // hívás funkciót C :: f (char *)

Az alap osztály leíró, felveheti a kulcsszó virtuális.
osztály <.>; B osztály: a virtuális nyilvánosság <.>; C osztály: a virtuális nyilvánosság <.>; D osztályú: nyilvános B, nyilvános C <.>;

Ebben az esetben a D osztályú csak egy példánya a A. Grafikailag ez így néz ki:

Egy osztály egyaránt tartalmazhat virtuális és nem virtuális alap osztály az ilyen típusú.
osztály <.>; B osztály: a virtuális nyilvánosság <.>; C osztály: a virtuális nyilvánosság <.>; D osztály: nyilvános A <.>; E osztályú: nyilvános B, nyilvános C, nyilvános D <.>;

Itt E osztály magában foglalja a két osztály egyedeire A. D. egyik osztály és egy másik csoportját a virtuális megosztott osztályok A. B. és C.

osztály <.>; B osztály: a virtuális nyilvánosság <.>; C osztály: a virtuális nyilvánosság <.>; D osztályú: nyilvános A, nyilvános B, nyilvános C <.>;

// Nem lehet! Hozza az osztály nem egyértelmű.

Annak megállapítására funkciók osztály egy virtuális alap osztály programozó, általában nem lehet tudni, hogy az alap osztály együtt használják más osztályokba. Lehet valami probléma van a végrehajtását az algoritmusok, amelyek előírják, hogy az alap osztály funkciót nevezik pontosan egyszer. Nyelv biztosítja, hogy a virtuális alap osztály konstruktora nevezzük csak egyszer. Constructor úgynevezett virtuális alap osztály (közvetlenül vagy közvetve) az objektum kivitelező (a kivitelező a „rövid szénláncú” származtatott osztály).
osztály >; B1: virtuális nyilvánosság >; osztály B2: virtuális nyilvánosság >; C osztály: nyilvános B1, nyilvános B2 >; osztály >; B1: nyilvános A >; osztály B2: nyilvános A >; C osztály: nyilvános B1, nyilvános B2 >;

Ha szükséges, a programozó képes szimulálni ez az áramkör, ami az alap osztály virtuális függvény csak a „rövid szénláncú” származtatott osztály.

A származtatott osztály felülírhatja a virtuális függvény a közvetlen vagy közvetett virtuális alap osztály. Két különböző osztályok felülírhatja virtuális függvények különböző virtuális alap osztály. Ily módon több származtatott osztályokban is hozzájárulhat, hogy a végrehajtás a bemutatott felület egy virtuális alap osztály.
osztály

A () <> virtuális void g (); virtuális void h ();>; B1: virtuális nyilvánosság ; osztály B2: virtuális nyilvánosság ; C osztály: nyilvános B1, nyilvános B2 <>; void main ()

// Hívás funkció B1 :: g // hívás funkciót B2 :: h

Ha két osztály helyére az azonos alap osztály funkciót, így azok származtatott osztály, nem helyettesíti ez a funkció érvénytelen. Ebben az esetben nem lehet létrehozni asztal virtuális függvények, mert ez a függvény nem egyértelmű.
osztály

// függvény C :: g felülbírálja funkció B1 :: g, és B2 :: g // Rendben - A funkciót C :: g // kétértelműséget - B1 :: H vagy B2 :: h.

Sok osztályok egyszerű és közös kapcsolódási pontok által használt számos különböző módon. A pontos érték minden interfész célfüggvény kerül meghatározásra, amelyre ez az úgynevezett. Gyakran a program egy kérelmet és a téma őket befogadó egy szoftver réteg. Ideális esetben a köztes kódot nem kell tudni semmit az egyes tranzakciók, különben el kellett volna módosítani kell minden egyes alkalommal, amikor változik olyan műveletek. Következésképpen egy ilyen köztes kódot kell egyszerűen továbbítja a kérelmet a kedvezményezett az adatok egy részét képviselő művelet lehet hivatkozni.

Egy egyszerű módja annak, hogy végre ez a megközelítés, hogy küldje el a húr képviselete a művelet, amelynek meg kell nevezni. Azonban ez a vonal valakinek, hogy hozzon létre, és valaki - dekódolni, hogy meghatározza, hogy milyen műveleteket megfelelnek. Ez elég nehéz és kényelmetlen. Lehetséges lenne, hogy küldjön egészek megfelelő műveleteket. Ugyanakkor, bár a szám és kényelmes számítógép, az emberek értékük nem egyértelmű. És még mindig szükség van egy kód, hogy meghatározzák, hogy mit kíván hívni.

C ++ eszközt biztosít közvetett hivatkozások a tanulót. A mutató egy osztály tagja egy olyan érték, amely azonosítja egy osztály tagja. Akkor kezelni, mint egy osztály tagja helyzetben az osztály az objektum, de természetesen a fordító figyelembe veszi a különbségek az adatokat virtuális függvények nonvirtual funkciók stb

Egy mutatót az M osztályú tagot alkalmazunk kombinációban a tárgy. Az üzemeltetők -> * és. * Hagyjuk a programozó, hogy kifejezze a következő sorrendben. p-> * m m csatlakozik az objektum által mutatott p. és obj. M * m kötődik az objektum obj. Az eredmény összhangban használják típusú m. Nem lehet menteni az ilyen műveletek eredményeként annak későbbi használatra.

Természetesen, ha tudtuk, hogy mi az a tagja, az osztály a használni kívánt tudtuk ezt nélkül közvetlenül mutatók. Valamint rámutatnak a szokásos funkciók, mutatókat az osztály tagjai használják, amikor szükség van, hogy olvassa el egy tárgy, amelynek neve ismeretlen. Azonban, ellentétben a mutató egy változó vagy egy szabályos működését a tanulót mutató csak egy mutatót a memória területet. Ez megfelel több, eltolódás a szerkezet egy index a tömbben. A kombináció a mutató egy tagja, az osztály egy tárgy vagy egy mutatót egy objektum ad neki, amely azonosítja egy adott tagja egy adott objektumot.
osztály Base tényleges

Base () <>>; osztály D1: nyilvános adatbázisa void close () void print () >; osztály D2: nyilvános adatbázisa void close () void print () >;

typedef void (Base :: * PF) (); void main () * PF1) (); (Pb -> * PF2) (); (Pb -> * PF3) ();>

// Határozza meg a mutató, amely egy tag függvény osztály Base // tárolja egy mutató a tanulót // Base (nyit és zár funkció virtuális, // és a nyomtatási funkció - nem virtuális). // d - D1 osztály objektum // hívás D1 funkció :: open () // A funkciót D1 :: close () // függvény hívás Base :: print () // pb - mutató egy objektum osztály Base (tárgy valójában tartozik osztály D2) // a funkciót D2 :: open () // a funkciót D2 :: close () // függvényhívás Base :: print ()

Shapes.h fájl

Alakzatok () static int GetCount () int Bal () const int Top () const int jobbra () const int Bottom () const virtuális void Draw () = 0; virtuális void Mozgatás (int, ahol, const alakzatok * alakú) = 0; virtuális alakzatok * NewShape () = 0; virtuális alakzatok * Clone () = 0;>;

Shapes.cpp fájl

#include "Shapes.h" int alakzatok :: count = 0;

Storable.h fájl

#define tárolható #include using namespace std; osztály tárolható

Tárolható (); virtuális int Read () = 0; virtuális int Write () = 0;>;

Storable.cpp fájl

#include "Storable.h" Tárolható :: tárolható (const char * f1, const char * f2) Tárolható :: tárolható (const char * f, int mode) else if (mód == WRITE) > Tárolható ::

Circle.h fájl *

#if. meghatározott (alakzatok) #include "Shapes.h" #endif class Circle: nyilvános alakzatok

Kör () <> void Draw (); void Mozgatás (int, ahol, const alakzatok * alakja);>;

Triangle.h fájl *

#if. meghatározott (alakzatok) #include "Shapes.h" #endif osztály Triangle: nyilvános alakzatok

Triangle () <> void Draw (); void Mozgatás (int, ahol, const alakzatok * alakja);>;

Circle_Storable.h fájl

#include "Circle.h" #ha. meghatározott (tárolható) #include "Storable.h" #endif osztály Circle_Storable: nyilvános Circle, virtuális nyilvános tárolható Circle_Storable (const char * f, int mód, int x = 0, int y = 0, int r = 0, int c = 0): Tárolható (F, mód), kör (x, y, R, c) <>

Circle_Storable () <> int read (); int Write ();>;

Circle_Storable.cpp fájl

Triangle_Storable.h fájl

#include "Triangle.h" #ha. meghatározott (tárolható) #include "Storable.h" #endif osztály Triangle_Storable: nyilvános Triangle, virtuális nyilvános tárolható Triangle_Storable (const char * f, int mód, int x1 = 0, int y1 = 0, int x2 = 0, int y2 = 0, int x3 = 0, int y3 = 0, int c = 0): Tárolható (F, mód), Triangle (x1, y1, x2, y2, x3, y3, c) <>

Triangle_Storable () <> int read (); int Write ();>;

Triangle_Storable.cpp fájl

main.cpp fájl

#include "Circle_Storable.h" #include "Triangle_Storable.h" void main () catch (const char * s) A (int i = 0; i Draw (); A (int i = 1; i Mozgatás (alakzatok :: BAL, alakzatok [i - 1]); A (int i = 0; i Draw (); // A tömb tárolt mutatókat alakzatok osztályban. Valós objektumok csoportjába tartoznak, vagy Circle_Storable Triangle_Storable. // amely egy osztály származó mind az alakzatok osztályban. és az osztály tárolható. Nem tudjuk, hogy pontosan milyen osztály // (Circle_Storable vagy Triangle_Storable) tartozik a tárgyhoz, de lehet konvertálni a mutatót egy mutatót osztály tárolható. // amely, valamint az alakzatok osztályban. Ez az alapja a mindkét osztályban. Ez azonban lehet tenni csak a // programot, így használja dynamic_cast típuskonverzió üzemben. amely ellenőrzi a tárgy osztályába tartozik származékos // alakzatok és tárolható osztályok. és végrehajtja a konverziót. Ha az objektum valójában nem tartozik az osztály // ezekből osztályokat, az index konverziós on alakzatok osztály egy mutatót egy osztály Tárolható lehetetlen lenne, // és dynamic_cast operátor visszatérhet az érték 0. (int i = 0; i (Alakzatok [i]) -> write (); A (int i = 0, n = alakzatok :: GetCount (); i