Incluziune și moștenire

Includerea obiectelor.

Există două opțiuni pentru includerea unui obiect de tip X din clasa A:

  1. Declarați un membru de tip X din clasa A;
  2. Declarați într-o clasă A un membru de tip X * sau X.

Este de preferat să includeți obiectul real ca și în primul caz. Aceasta este mai eficientă și mai puțin predispusă la erori, deoarece relația dintre obiectele conținute și cele conținute este descrisă prin reguli de construcție și distrugere.







Cea de-a doua variantă cu pointerul poate fi utilizată atunci când pentru durata de viață a obiectului "care conține" este necesar să se schimbe pointerul la obiectul "conținut".

A doua opțiune poate fi utilizată atunci când doriți să specificați obiectul "conținut" ca argument.

Având obiecte care includ alte obiecte, creăm o ierarhie de obiecte. Este o alternativă și o adăugare la ierarhia de clasă. Și când numărul de obiecte incluse este necunoscut în prealabil și (sau) se poate schimba pe durata de viață a obiectului "care conține". De exemplu, dacă obiectul Scoala conține studenți, atunci numărul acestora poate varia.

Există două modalități de a rezolva această problemă. Primul este că o listă legată de obiecte incluse este organizată, iar obiectul "containing" are un pointer membru la începutul acestei liste.

În acest caz, atunci când creați obiectul Scoala, este creată o listă goală a obiectelor incluse. Pentru a activa obiectul, se apelează metoda add (). care ca parametru transmite un pointer obiectului inclus. Distructorul șterge secvențial toate obiectele incluse. Obiectul Obiect conține următorul câmp. care vă permite să conectați obiecte la listă.

A doua modalitate este de a folosi un obiect container special.

Clasa de containere este concepută pentru a stoca obiecte și pentru a le oferi acces facil la metode simple și convenabile.

Împreună cu containerele există grupuri, adică Obiecte în care sunt incluse și alte obiecte. Obiectele care fac parte dintr-un grup sunt numite membri ai grupului. Elementele grupului, la rândul său, pot fi, de asemenea, un grup.

  1. O fereastră într-un program interactiv care deține elemente precum câmpurile de introducere și editare de date, butoane, liste de selecție, casete de dialog etc.
  2. Un ansamblu format din noduri mai mici.
  3. O grădină de legume constând din plante, sisteme de irigare și un plan de creștere.
  4. Unele structuri organizaționale (de exemplu, FACULTY, CHAIR, GROUP STUDENT).

Conceptele "grup" și "container" sunt diferite. Containerul este utilizat pentru a stoca alte date. Exemplu de container: obiecte din clasele de containere ale bibliotecii STL din C ++ (matrice, liste, cozi).

Spre deosebire de un container, un grup este o clasă care nu numai stochează obiecte din alte clase, ci și proprietăți proprii care nu rezultă din proprietățile elementelor sale.

Grupul oferă o a doua vedere al ierarhiei (primul tip - ierarhie de clasă construit pe baza de moștenire) - ierarhia obiect (număr întreg de ierarhie de tip / parte), construită pe baza de agregare.

Puteți implementa un grup în mai multe moduri:

  1. Grupul de clase conține câmpuri de date cu tipul de obiect. Astfel, obiectul "grup" conține fie elemente proprii, fie indicatori ai acestora ca date. Acest mod de implementare a grupului este folosit în C ++ Builder.
  2. Grupul conține un membru al ultimului tip TObject *. care indică începutul listei legate de obiecte incluse în grup. În acest caz, obiectele trebuie să aibă un câmp următor de tip TObject *. indicând următorul element din listă.
  3. Se creează o listă legată de structuri de tipul TItem. Câmpul elementului indică obiectul inclus în grup. Grupul conține un ultim câmp de tipul TItem *. care indică începutul unei liste legate de structuri de tip TItem. Dacă aveți nevoie de a avea acces la elemente de câmpuri și metodele sale, un obiect de tip TObject ar trebui să aibă tipul de câmp proprietar TGroup *. care indică proprietarul acestui element.

Există două metode care sunt necesare pentru funcționarea grupului:

Include un element într-un grup.

În plus, grupul poate conține următoarele metode:

Indică dacă există cel puțin un element în grup.

Elimină un element din grup, dar îl salvează în memorie.

Elimină un element din grup și din memorie.

Iteratoarele vă permit să efectuați anumite acțiuni pentru fiecare element dintr-un anumit set de date.

Un astfel de ciclu ar putea fi făcută pentru întregul set, de exemplu, este de a imprima toate elementele unui set, sau s-ar putea să caute un element care îndeplinește o anumită condiție, caz în care acest ciclu se poate termina imediat ce elementul solicitat va fi găsit.

Vom lua în considerare iteratorii ca o clasă specială de metode de grup pentru a efectua o acțiune pentru toate obiectele incluse în grup. Un exemplu de iterator este metoda Show.

Am dori să avem un iterator care să permită efectuarea pe toate elementele grupului a acțiunilor specificate nu de una dintre metodele obiect, ci de o funcție arbitrară a utilizatorului. Un astfel de iterator poate fi implementat dacă această funcție este trecută printr-un pointer la o funcție.

Definiți tipul indicatorului la funcție după cum urmează:

Funcția are un parametru obligatoriu de tip TObject sau TObject *. prin care se transmite un obiect, pentru care este necesară efectuarea anumitor acțiuni.

Metoda iterator este declarată după cum urmează:

unde acțiunea este singurul parametru dorit-pointer la o funcție care este apelată pentru fiecare element al grupului; parametrii suplimentari - parametrii care trebuie transferați la funcția apelată.

Apoi, un pointer de funcții este definit și inițializat la funcția trecută la iterator.

Apoi, iteratorul va fi apelat, de exemplu, pentru un parametru suplimentar de tip int. după cum urmează:

Aici gr este un grup de obiecte.

Luați în considerare relația dintre moștenire și incluziune.







Incluziune și moștenire.

Fie clasa D o clasă derivată din clasa B.

Cuvântul public din antetul clasei D se referă la o moștenire deschisă. Moștenirea deschisă înseamnă că clasa D derivată este un subtip de clasa B. D obiect este obiectul B. Aceasta este relația moștenire este-a sau D spune că este o formă de D. este, uneori, de asemenea, menționată ca moștenire de interfață. Când moștenirea este deschisă, variabila clasei derivate poate fi tratată ca o variabilă a tipului de clasă de bază. Pointer, tipul care - „un pointer la o clasă de bază“ poate indica obiecte care au tipul clasei derivate. Folosind moștenirea, construim o ierarhie de clasă.

Luați în considerare următoarea ierarhie a clasei.

Definim indicatorii pentru obiectele din aceste clase.

Creați obiecte din aceste clase.

Acum, să presupunem că clasa D are un membru din clasa B.

La rândul său, clasa B are un membru din clasa C.

O astfel de incluziune se numește a avea o relație. Folosind incluziunea, construim o ierarhie de obiecte.

În practică, există o problemă de alegere între moștenire și incluziune. Luați în considerare clasele "Avion" și "Motor". Începătorii vin adesea în minte pentru a face derivatul "Avion" al "motorului". Acest lucru nu este adevărat, deoarece aeronava nu este un motor, are un motor. O modalitate de a vedea acest lucru este să ne întrebăm dacă un avion poate avea mai multe motoare. Pentru că acest lucru este posibil, ar trebui să utilizăm includerea, nu moștenirea.

Luați în considerare următorul exemplu:

De ce sunt erori de linii # 1 și # 3?

În linia # 1 nu există o conversie a lui D * în B *.

În linia # 3, D nu are g ().

Spre deosebire de moștenire publică, nu există nici o conversie implicită de la o clasă la unul dintre membrii săi, precum și o clasă care conține un membru al altei clase, nu înlocuiește funcțiile virtuale ale clasei.

Dacă folosiți moștenirea deschisă pentru clasa D

nu conține erori.

Deoarece D este o clasă derivată din B. atunci se efectuează o conversie implicită de la D la B. O consecință este dependența crescută între B și D.

Există cazuri în care vă place moștenirea, dar nu puteți permite astfel de transformări.

De exemplu, vrem să reutilizeze codul clasei de baza, dar nu se așteaptă să ia în considerare un obiect de clasă derivată ca o instanță a bazei. Tot ce vrem din moștenire este reutilizarea codului. Soluția aici este moștenirea privată. Moștenirea închisă nu este o relație subtip sau este o relație. Noi o numim atitudine ca-a (similar) sau moștenire de punere în aplicare, spre deosebire de interfață moștenire. Moștenirea închisă (dar și sigură) nu creează o ierarhie de tip.

Din punct de vedere al designului, moștenirea privată este echivalentă cu includerea, cu excepția problemei cu înlocuirea funcțiilor. O aplicație importantă a acestei abordări este moștenirea deschisă din clasa abstractă și, în același timp, moștenirea închisă (sau protejată) de la o anumită clasă pentru a reprezenta implementarea.

Un exemplu. Arbore de căutare binar

Nodurile copacului binar conțin un pointer generalizat la datele de date. Acesta va corespunde tipului de pointer din clasa derivată. Câmpul de numărare conține numărul de apariții repetate ale datelor. Pentru o clasă derivată specială, trebuie să scriem funcția comp pentru a compara valorile unui anumit tip derivat. Funcția insert () pune nodurile în arbore.

Funcția TP find (Node * r, TP d) caută subarborele cu rădăcina r pentru informația reprezentată de d.

Funcția print () este recursiunea standard pentru traversarea unui copac binar

Fiecare nod utilizează o funcție externă. print ().

Acum, vom crea o clasă derivată care stochează indicatorii la caracterul ca membri de date.

În clasa StringTree, funcția insert utilizează conversia implicită a char * pentru void *.

Funcția de comparație comp arată astfel

Pentru a afișa valorile stocate în nod, utilizați funcția externă

Aici, pentru o distribuție explicită de tip void * to char *, folosim expresia tip operație exprimată (type_name). Mai fiabilă este utilizarea operatorului static_cast (TP).

Moștenire multiplă

O clasă poate avea mai multe clase de bază imediate

Această moștenire este numită plural. Cu moștenire multiplă, nici o clasă nu poate fi utilizată de mai multe ori ca bază directă. Cu toate acestea, clasa poate fi o clasă de bază indirectă mai mult decât o dată.

Avem următoarea ierarhie a clasei (și obiectelor):

Această duplicare a clasei corespunde includerii mai multor obiecte din clasa de bază în obiectul derivat. În acest exemplu, există două obiecte din clasa X. Pentru a elimina posibilele ambiguități, trebuie să vă referiți la o componentă specifică din clasa X, utilizând calificarea completă

Pentru a elimina duplicarea obiectelor din clasa de bază indirectă cu moștenire multiplă, această clasă de bază este declarată virtuală.

Acum, clasa A va include doar o instanță a lui X, acces la care clasele Y și Z au drepturi egale.

aici
  • obiect de clasă Baza ocupă în memorie 15 octeți:
    • 4 octeți - câmpul int;
    • 2 octeți - câmp de caractere;
    • 10 octeți - câmpul de caractere [10];
  • obiectul clasei ABase ocupă 79 de octeți în memorie:
    • 8 octeți - câmpul dublu;
    • 15 octeți - baza de bază;
    • 2 octeți - pentru comunicare în ierarhia claselor virtuale;
  • obiectul clasei BBase ocupă în memorie 21 de octeți:
    • 4 octeți - câmpul plutitor;
    • 15 octeți - baza de bază; 2 octeți - pentru comunicare în ierarhia claselor virtuale;
  • obiect de clasă Top primește memorie de 35 de octeți:
    • 4 octeți - câmp lung;
    • 10 octeți - date și comunicații ABase;
    • 6 octeți - valid și BBase;
    • 15 octeți - baza de bază;

Dacă, atunci când moștenim Baza în clasele ABase și BBase, clasa de bază nu este făcută virtuală, rezultatulb va fi:

  • obiect de clasă Baza ocupă în memorie 15 octeți
  • obiectul clasa ABase ocupă 26 de octeți în memorie (nu există 2 octeți pentru comunicație);
  • obiectul clasei BBase ocupă 59 de octeți în memorie (nu există 2 octeți pentru comunicare);
  • Clasa Objectv Top ocupă în memorie 46 de octeți (obiectul Base intră de două ori).

Clasele locale și imbricate

O clasă poate fi declarată în interiorul unui bloc, de exemplu, în cadrul unei definiții a funcției. Această clasă se numește locală. Localizarea unei clase implică inaccesibilitatea componentelor sale în afara zonei de definire a clasei (în afara blocului).

O clasă locală nu poate avea date statice, deoarece componentele clasei locale nu pot fi definite în afara textului clasei.

În cadrul unei clase locale, numai clasele de tip, variabilele statice, variabilele externe, funcțiile externe și elementele enumerare pot fi utilizate din clasa din jur. Din ceea ce este interzis, este important să notați variabilele memoriei automate. Există încă o limitare importantă pentru clasele locale: funcțiile lor componente pot fi doar în linie.

Într-o clasă, este permisă definirea tipurilor, de aceea o clasă poate fi descrisă în alta. Această clasă se numește imbricată. O clasă imbricată este locală pentru clasa în care este descrisă și regulile pentru utilizarea clasei locale discutate mai sus sunt propagate în ea. Ar trebui să se spună în mod special că o clasă imbricată nu are drepturi speciale de acces pentru membrii clasei care le închide, adică le poate accesa numai printr-un obiect de tipul acestei clase (precum și clasa anexată nu are drepturi speciale de acces la clasa imbricată ).

Un exemplu. Clasa "RECTANGLE".

Definiți clasa "dreptunghi". În interiorul acestei clase, definiți clasa ca o clasă "tăiată" imbricată. Dreptunghiul va fi construit din segmente.

Folosind această tehnică, puteți defini orice formă geometrică formată din segmente drepte.

Clasa String stochează un șir ca o matrice de caractere cu un null terminat C și folosește un mecanism de numărare a referințelor pentru a minimiza operațiile de copiere.

Clasa String utilizează trei clase de ajutor:
  • StringRepeater. care vă permite să separați reprezentarea reală între mai multe obiecte de tip String cu aceleași valori;
  • Interval - pentru a genera o excepție în cazul depășirii intervalului;
  • Referință - pentru a implementa o operație de indexare care face distincția între operațiile de citire și scriere.

Ca și ceilalți membri, o clasă imbricată poate fi declarată în clasă însă, dar definită mai târziu.

Clasa String oferă un set comun de constructori, destructori și operatori de atribuire.







Articole similare

Trimiteți-le prietenilor: