Funcții virtuale și clase abstracte
Curs 18. moștenire multiplă
O clasă poate fi generată de orice număr de clase de bază. Având mai mult de o clasă de bază imediată se numește moștenire multiplă.
clasa A;
din clasa B;
clasa C;
clasa D. publice A, B public, privat C;
Un pointer la clasa derivată poate fi trecut la o funcție care se așteaptă ca un pointer la una dintre clasele de bază. Punerea în aplicare a acestui mecanism presupune simpla compilare de tehnici pentru a se asigura că o funcție care se așteaptă un pointer la o clasă de bază, a se vedea partea clasei derivate, diferită de cea care se va vedea funcția pe care se așteaptă ca un pointer la o altă clasă de bază. Funcții virtuale funcționează ca de obicei.
clasa A
Clasa nu poate fi specificată ca o clasă de bază imediată mai mult de o dată, dar poate fi mai mult decât o dată clasa de baza indirectă.
clasa A <.>; clasa B: A publică, A publică;
clasa A <.>; clasa B: A publică; clasa C: A publică; clasa D: B publice, C public;
Aici, o facilitate de clasa D va avea două sub-obiect de clasa A.
Clasa derivată și clasele sale de bază pot fi reprezentate ca un grafic aciclic direcționat.
Deoarece obiectul D are două obiect de acționare A. (explicit sau implicit) între A și un pointer la un pointer la un D ambiguu și, prin urmare, interzise.
D * pd = new D; A * pa = pd; pa = (A *) pd; pa = (B *) pd; pa = (C *) pd;
// Ambiguitatea! // Toate aceeași ambiguitate! // Reducerea la un pointer la B Reducerea obiectului // la un pointer la obiectul C.
Cu toate acestea, clasa poate fi atât de clasă directă și indirectă de bază.
clasa A <.>; clasa B: A publică <.>; clasa C: A publică <.>; clasa D: A publică, B publică, C <.>; pa = pd; pa = (B *) pd; pa = (C *) pd;
// Can! // Introducerea unui pointer la obiectul A imediat Reduction D // la un pointer la reducerea obiectului B // la un pointer la obiectul C.
// Funcția A :: f (int) a devenit deschis
// apeleaza functia A :: f (int) // apel Funcția B1 :: f (double) // Apelul funcției B2 :: f (char) // Apelul funcției C :: f (char *)
Prin descriptorul clasă de bază, puteți adăuga cuvântul cheie virtual.
clasa A <.>; clasa B: virtual public A <.>; clasa C: virtual public A <.>; clasa D: B publică, C <.>;
În acest caz, clasa D are doar o singură instanță a clasei A. Grafic, se pare ca acest lucru:
O clasă poate conține clase de baza atât virtuale și non-virtuale de acest tip.
clasa A <.>; clasa B: virtual public A <.>; clasa C: virtual public A <.>; clasa D: A publică <.>; clasa E: B publice, C publică, D publică <.>;
Aici clasa E include două instanțe de clasă A. D. o clasă și o altă clasă de clase virtuale partajate A. B și C.
clasa A <.>; clasa B: virtual public A <.>; clasa C: virtual public A <.>; clasa D: A publică, B publică, C <.>;
// Nu se poate! Aducerea la clasa A este ambiguă.
La determinarea caracteristicilor de clasă cu un programator clasă de bază virtuală, în general, nu se poate ști dacă clasa de bază utilizată în combinație cu alte clase. Aceasta poate fi o problemă cu punerea în aplicare a algoritmilor, care necesită ca funcția de clasă de bază se numește exact o dată. Limba asigură că un constructor de clasă de bază virtuală este numit doar o singură dată. Numita clasă de bază constructor virtuală (direct sau indirect) de constructorul obiectului (constructorul clasei „inferior“ derivate).
clasa A
Dacă este necesar, programator poate simula acest circuit, cauzând funcția clasă de bază virtuală a clasei „inferior“ derivate.
O clasă derivată poate suprascrie funcția virtuală a clasei sale directe sau indirecte de bază virtuală. Două clase diferite pot trece peste funcții virtuale de clasă diferită de bază virtuală. În acest fel, mai multe clase derivate poate contribui la punerea în aplicare a interfeței prezentate într-o clasă de bază virtuală. A () <> void g virtual (); void virtuale h ();>; clasa B1: virtual public A // Funcția de apel B1 :: g // Apelul funcției B2 :: h Dacă două clase înlocuiți aceeași funcție de clasa de bază, care le determină clasă derivată, nu substituie această funcție nu este validă. În acest caz, nu poate fi creat tabelul de funcții virtuale, deoarece acest apel funcție este ambiguă. // Funcție C :: g înlocuirile B1 :: g și B2 :: g // Bine - apelați funcția C :: g // Ambiguitate - B1 :: h sau B2 :: h. Multe clase oferă o simplă și interfețe comune care urmează să fie utilizate în mai multe moduri diferite. Valoarea exactă a fiecărei funcții de interfață obiect este determinată pentru care este numit. De multe ori între program, emite o cerere și subiectul care le primesc, este un strat de software. În mod ideal, codul intermediar nu trebuie să știe nimic despre tranzacțiile individuale, altfel ar fi trebuit să fie modificat de fiecare dată când modificați un set de operații. În consecință, un astfel de cod intermediar trebuie să treacă pur și simplu cererea destinatarului o parte din datele care reprezintă operațiunea care urmează să fie invocate. Un mod simplu de a pune în aplicare această abordare este de a trimite reprezentarea șir a operațiunii, care trebuie să fie numit. Cu toate acestea, această linie cineva trebuie să creeze și cineva - decoda pentru a determina ce corespunde operațiunilor. Este destul de dificil și incomod. Ar fi posibil să se trimită numere întregi operații corespunzătoare. Cu toate acestea, deși numărul și convenabil pentru calculator, pentru oamenii din valoarea lor nu este evidentă. Și totuși nevoie de un cod pentru a determina ce doriți să îl apelați. C ++ oferă un mijloc de referințe indirecte la un membru al clasei. Un pointer la un membru al clasei este o valoare care identifică un membru al clasei. Puteți să-l trateze ca pe un membru al poziției de clasă în clasa obiectului, dar, desigur, compilatorul ia în considerare diferențele dintre funcțiile de date virtuale funcții nonvirtual, etc. Un pointer la elementul de clasă m este utilizat în combinație cu obiectul. Operatori -> * și. * Se lasă programator să-și exprime secvența următoare. P-> * m m se conectează la obiectul indicat de p. și obj. M * m se leagă la obj obiect. Rezultatul poate fi utilizat în conformitate cu tipul de m. Nu se poate salva prin aceste operațiuni pentru utilizarea sa în viitor. Desigur, dacă am ști ce un membru al clasei pe care doriți să o utilizați, am putea face acest lucru în mod direct, fără a utiliza indicii. Precum și indicii pentru funcțiile obișnuite, indicatoare către membrii clasei sunt utilizate atunci când este necesar să se facă referire la un obiect al cărui nume nu este cunoscut. Cu toate acestea, spre deosebire de un pointer la o variabilă sau o funcție în mod regulat pointerul membru al clasei este doar un pointer la zona de memorie. Ea corespunde mai mult sau schimbare în structura unui indice în matrice. Combinația dintre un pointer la un membru al clasei cu un obiect sau un pointer la un obiect dă care identifică un anumit membru al unui anumit obiect. Baza () <>>; clasa D1: Baza publică typedef void (Base :: * PF) (); void main () // Determina tipul de un pointer la o funcție membru al clasei de baza // stochează un pointer la un membru al clasei // Base (funcții de deschidere și de închidere sunt virtuale, // și funcția de imprimare - non-virtuală). // d - D1 obiect din clasa // functia de apel D1 :: open () // Apelați funcția D1 :: închidere () // Base :: Print (functie de apel) // Pb - un pointer la un obiect de bază de clasă (obiect aparține de fapt clasa D2) // apel D2 funcție :: open () // Apelați funcția D2 :: închidere () // funcția de bază :: Print apel () Forme () #include "Shapes.h" int forme :: count = 0; #define #include stocabil Storable (); virtuale int Read () = 0; int virtuale Scriere () = 0;>; #include "Storable.h" stocabil :: stocabil (const char * f1, const char * F2) #if. definit (FORME) #include „Shapes.h“ Cercul de clasă # endif: Forme publice Circle () <> void Draw (); void Move (int unde, Forme const * forma);>; #if. definit (FORME) #include „Shapes.h“ Triangle clasa # endif: Forme publice Triangle () <> void Draw (); void Move (int unde, Forme const * forma);>; #include "Circle.h" #if. definit (Storable) #include "Storable.h" # endif clasa Circle_Storable: cerc public, virtuale stocabil publice Circle_Storable () <> int Read (); int Write ();>; #include "Triangle.h" #if. definit (Storable) #include "Storable.h" # endif clasa Triangle_Storable: Triangle publice, virtuale stocabil publice Triangle_Storable () <> int Read (); int Write ();>; #include "Circle_Storable.h" #include "Triangle_Storable.h" void main ()
clasa A
clasa A
clasa de baza fișier Shapes.h
fișier Shapes.cpp
fișier Storable.h
fișier Storable.cpp
Circle.h fișier *
Fișier Triangle.h *
fișier Circle_Storable.h
fișier Circle_Storable.cpp
fișier Triangle_Storable.h
fișier Triangle_Storable.cpp
fișier main.cpp