Moștenire (programare)

Moștenire (ing. moștenire ) - conceptul de programare orientată pe obiecte , conform căruia un tip de date abstract poate moșteni datele și funcționalitatea unui tip existent, facilitând reutilizarea componentelor software .

Terminologie

În programarea orientată pe obiecte , începând cu Simula 67 , tipurile de date abstracte sunt numite clase .

Superclasă ( ing.  super clasă ), clasă părinte ( ing.  parent class ), strămoș, părinte sau superclasă - o clasă care produce moștenire în subclase, adică o clasă de la care moștenesc alte clase. O superclasă poate fi o subclasă, o clasă de bază, o clasă abstractă și o interfață.

Subclasa ( ing.  subclasa ), clasa derivata ( ing.  clasa derivata ), clasa copil ( ing.  clasa copil ), clasa descendenta, clasa succesoare sau clasa de implementare - o clasa mostenita de la o superclasa sau interfata, adica o clasa definita prin mostenire de la altă clasă sau mai multe astfel de clase. O subclasă poate fi o superclasă.

O  clasă de bază este o clasă care se află în vârful ierarhiei de moștenire a clasei și în partea de jos a arborelui subclaselor, adică nu este o subclasă și nu moștenește de la alte superclase sau interfețe. Clasa de bază poate fi o clasă abstractă și o interfață. Orice clasă non-bază este o subclasă.

O  interfață este o structură care definește o interfață de clasă pură constând din metode abstracte. Interfețele participă la ierarhia de moștenire a claselor și interfețelor.

O superinterfață ( ing.  super interfață ) sau o interfață strămoșă este un analog al unei superclase din ierarhia moștenirii, adică este o interfață care moștenește în subclase și subinterfețe.

O interfață descendentă, o interfață derivată sau o interfață derivată  este un analog al unei subclase din ierarhia de moștenire a interfețelor, adică este o interfață moștenită de la una sau mai multe superinterfețe.

O interfață de bază este echivalentul unei clase de bază în ierarhia de moștenire a interfețelor, adică este interfața din vârful ierarhiei de moștenire.

O ierarhie de moștenire sau ierarhie de clasă este un arbore ale cărui elemente sunt clase și interfețe.

Aplicație

Moștenirea este un mecanism de reutilizare a codului (reutilizarea codului englez ) și contribuie la extinderea independentă a software -ului prin clase deschise (clase publice engleze) și interfețe (interfețe engleze). Setarea unei relații de moștenire între clase generează o ierarhie de clasă.

Moștenirea și polimorfismul subtipului

Moștenirea este adesea identificată cu polimorfismul de subtipizare :

În ciuda observației de mai sus, moștenirea este un mecanism utilizat pe scară largă pentru stabilirea unei relații is -a . Unele limbaje de programare sunt de acord cu moștenirea și polimorfismul subtipului (mai ales limbaje tipizate static , cum ar fi C++C#Java și Scala ), în timp ce altele împărtășesc conceptele de mai sus.

Moștenirea - chiar și în limbaje de programare care acceptă utilizarea moștenirii ca mecanism pentru polimorfismul subtipului - nu garantează polimorfismul comportamental subtipului; vezi: „Principiul substituției” de Barbara Liskov .

Tipuri de moștenire

Moștenire „simple”

Moștenirea „simple”, numită uneori moștenire unică, descrie relația dintre două clase, dintre care una o moștenește pe cealaltă. Multe clase pot deriva dintr-o singură clasă, dar chiar și așa, acest tip de relație rămâne moștenire „simple”.

Clase abstracte și crearea de obiecte

Pentru unele limbaje de programare, următorul concept este valabil.

Există clase „abstracte” (declarate ca atare în mod arbitrar sau din cauza metodelor abstracte care le sunt atribuite ); ele pot fi descrise ca având câmpuri și metode . Crearea de obiecte (instanțe) înseamnă concretizare , aplicabilă numai claselor non-abstracte (inclusiv descendenților neabstracti ai celor abstracte), ai căror reprezentanți, ca urmare, vor fi obiectele create.

Exemplu: Să fie abstractă clasa de bază „Angajat al Universității ”, din care sunt moștenite clasele „ Student postuniversitar ” și „ Profesor ”. Câmpurile și funcțiile comune ale claselor (de exemplu, câmpul „Anul nașterii”) pot fi descrise în clasa de bază. Și programul va crea obiecte numai din clasele derivate: „Student postuniversitar” și „Profesor”; de obicei nu are sens să se creeze obiecte ale claselor de bază.

Moștenire multiplă

Cu moștenire multiplă, o clasă poate avea mai mult de un părinte. În acest caz, clasa moștenește metodele tuturor strămoșilor. Avantajul acestei abordări este o mai mare flexibilitate.

Moștenirea multiplă este implementată în C++ . Alte limbi care oferă această caracteristică includ Python și Eiffel . Moștenirea multiplă este acceptată în UML .

Moștenirea multiplă este o sursă potențială de erori care pot apărea din a avea aceleași nume de metode în strămoși. În limbile care sunt poziționate ca succesori ai C++ ( Java , C# și altele), s-a decis abandonarea moștenirii multiple în favoarea interfețelor . Aproape întotdeauna puteți face fără a utiliza acest mecanism. Cu toate acestea, dacă totuși a apărut o astfel de nevoie, atunci pentru a rezolva conflictele în utilizarea metodelor moștenite cu aceleași nume, este posibil, de exemplu, să aplicați operația de extensie a vizibilității - "::" - pentru a apela o anumită metodă a unui anumit părinte.

O încercare de a rezolva problema de a avea aceleași nume de metodă în strămoși a fost făcută în limba Eiffel , în care, atunci când descrieți o nouă clasă, este necesar să se indice în mod explicit membrii importați ai fiecărei clase moștenite și denumirea lor în clasa de copii.

Majoritatea limbajelor de programare orientate pe obiecte moderne ( C# , Java , Delphi și altele) acceptă capacitatea de a moșteni simultan de la o clasă strămoșească și de a implementa metode ale mai multor interfețe de către aceeași clasă. Acest mecanism vă permite să înlocuiți în mare măsură moștenirea multiplă - metodele de interfață trebuie redefinite în mod explicit, ceea ce elimină erorile atunci când moșteniți funcționalitatea acelorași metode ale diferitelor clase de strămoși.

Clasă de bază unică

Într-un număr de limbaje de programare, toate clasele, fie explicit, fie implicit, moștenesc de la o clasă de bază. Smalltalk a fost una dintre primele limbi care a folosit acest concept. Aceste limbaje includ și: Objective-C (clasă NSObject), Perl ( UNIVERSAL), Eiffel ( ANY), Java ( java.lang.Object), C# ( System.Object), Delphi ( TObject), Scala ( Any).

Moștenirea în limbaje de programare

C++

Moștenirea în C++ :

clasaA { }; // Clasa de bază clasa B : public A {}; // Clasa de moștenire publică C : protejată A {}; // Clasa de moștenire protejată Z : privat A {}; // Moștenire privată

Există trei tipuri de moștenire în C++ : publică , protejată , privată . Specificatorii de acces ai membrilor clasei de bază se modifică în descendenți după cum urmează:

  • Dacă o clasă este declarată ca clasa de bază a unei alte clase cu un specificator de acces...
    • ... public :
      • membri publici ai clasei de bază - disponibili ca membri publici ai clasei derivate;
      • protected-membri ai clasei de bază - disponibili ca membri protejați ai clasei derivate;
    • … protejat :
      • membrii publici și protejați ai clasei de bază sunt disponibili ca membri protejați ai clasei derivate;
    • ... privat :
      • membrii publici și protejați ai clasei de bază sunt disponibili ca membri privați ai clasei derivate.

Unul dintre principalele avantaje ale moștenirii publice este că un pointer către clase derivate poate fi implicit convertit într-un pointer către clasa de bază, așa că pentru exemplul de mai sus, puteți scrie:

A * a = nouB ( );

Această caracteristică interesantă deschide posibilitatea identificării dinamice a tipului (RTTI).

Delphi (Obiect Pascal)

Pentru a utiliza mecanismul de moștenire în Delphiclass , trebuie să specificați clasa strămoșului în declarația de clasă între paranteze :

Strămoş:

TAncestor = clasa privat protejat public // procedura procedura virtuala VirtualProcedure ; virtual ; abstract ; procedura StaticProcedure ; sfârşitul ;

Moştenitor:

TDescendant = clasă ( TAncestor ) privat protejat public // Procedura virtuală de înlocuire a procedurii VirtualProcedure ; suprascrie ; procedura StaticProcedure ; sfârşitul ;

Absolut toate clasele din Delphi sunt descendenți ai TObject. Dacă nu este specificată o clasă de strămoș, atunci se presupune că noua clasă este un descendent direct al TObject.

Moștenirea multiplă în Delphi nu este acceptată inițial în principiu, cu toate acestea, pentru cei care nu se pot descurca fără ea, există încă astfel de oportunități, de exemplu, prin utilizarea claselor de ajutor (Сlass Helpers).

Python

Python acceptă atât moștenirea unică, cât și moștenirea multiplă. La accesarea unui atribut, vizualizarea claselor derivate are loc în ordinea ordinii de rezoluție a metodei  ( MRO ) [1] .

clasa Ancestor1 ( obiect ): # Ancestor-1 def m1 ( self ): trece clasa Ancestor2 ( obiect ): # Ancestor-2 def m1 ( self ): trece class Descendent ( Ancestor1 , Ancestor2 ): # Descendent def m2 ( self ): trece d = Descendent () # Instanță tipărită d . __clasa__ . __mro__ # Ordinea rezoluției metodei: ( < clasa ' __main__ . Descendent '>, <clasa ' __principal__ . Strămoș1 '>, <clasa ' __principal__ . Strămoș2 '>, <tip ' obiect '>)

Începând cu Python 2.2, clasele „clasice” și clasele „noile” coexistă în limbaj. Aceștia din urmă sunt moștenitori object. Clasele „clasice” vor fi acceptate până la versiunea 2.6, dar eliminate din limbaj în Python 3.0.

Moștenirea multiplă este utilizată în Python, în special, pentru a introduce clase mix -in în clasa principală . 

PHP

Pentru a utiliza mecanismul de moștenire în PHPextends , este necesar să specificați cuvântul și numele clasei strămoși după numele clasei succesoare declarate în declarația clasei :

clasa Descendent extinde Strămoș { }

Dacă clasa derivată se suprapune cu metodele strămoșilor, metodele strămoșilor pot fi accesate folosind parent:

class A { function example () { echo "Metoda A::example() numit.<br /> \n " ; } } clasa B extinde A { function example () { echo "Metoda B::example() numit.<br /> \n " ; parinte :: exemplu (); } }

Este posibil să împiedicați o clasă derivată să depășească metodele unui strămoș; pentru a face acest lucru, trebuie să specificați cuvântul cheie final:

class A { final function example () { echo "Metoda A::example() numit.<br /> \n " ; } } clasa B extinde A { function example () { //va arunca o eroare parent :: example (); //și nu se va executa niciodată } }

Pentru a face referire la constructorul clasei părinte în timpul moștenirii, este necesar ca clasa copil să specifice în constructor parent::__construct();[2]

Obiectiv-C

@interfața A  : NSObject - ( vod ) exemplu ; @Sfârşit @implementation - ( vod ) exemplu { NSLog ( @"ClassA" ); } @Sfârşit @interfața B  : A - ( nul ) exemplu ; @Sfârşit @implementation - ( vod ) exemplu { NSLog ( @"ClassB" ); } @Sfârşit

Interfața declară metode care vor fi vizibile în afara clasei (publice).

Metodele interne pot fi implementate fără interfață. Pentru a declara proprietăți suplimentare, utilizați extensia-interfață în fișierul de implementare.

Toate metodele din Objective-C sunt virtuale.

Java

Un exemplu de moștenire de la o clasă și două interfețe :

public class A { } public interface I1 { } public interface I2 { } public class B extinde A implementează I1 , I2 { }

O directivă finaldintr-o declarație de clasă face imposibilă moștenirea din ea.

C#

Un exemplu de moștenire de la o clasă și două interfețe :

public class A { } public interface I1 { } public interface I2 { } public class B : A , I1 , I2 { }

Moștenirea din clasele tipizate se poate face prin specificarea unui tip fix sau prin transferul unei variabile de tip într-o clasă moștenită:

clasă publică A < T > { } clasă publică B : A < int > { } clasă publică B2 < T > : A < T > { }

De asemenea, este posibil să moșteniți clase imbricate din clasele care le conțin:

clasa A // clasa implicită A este internă, nu publică clasa B nu poate fi publică { clasa B : A { } }

O directivă sealeddintr-o declarație de clasă face imposibilă moștenirea din ea. [3]

Ruby

părinte de clasă def public_method „Metoda publică” final privat def private_method „Metoda privată” final Sfârşit classChild < Părinte _ def public_method „Metoda publică redefinită” final def call_private_method "Metoda privată a strămoșilor: " + private_method end Sfârşit

Clasa Parenteste strămoșul clasei a Childcărei metodă este suprascrisă public_method.

copil = Copil . copil nou._ _ public_method # => „Metodă publică redefinită” copil . call_private_method # => „Metoda privată a strămoșilor: metoda privată”

Metodele private ale unui strămoș pot fi apelate de la descendenți.

JavaScript

class Parent { constructor ( date ) { this . data = data ; } publicMethod () { return 'Metodă publică' ; } } class Child extinde Parent { getData () { return `Data: ${ this . date } ` ; } publicMethod () { return 'Metoda publică redefinită' ; } } const test = newChild ( ' test' ); test . getdata (); // => „Date: test” test . publicMethod (); // => Testul „Metodă publică redefinită” . date ; // => 'test'

Clasa Parenteste strămoșul clasei a Childcărei metodă este suprascrisă publicMethod.

JavaScript folosește moștenirea prototipală.

Constructori și destructori

În C++ , constructorii sunt chemați secvențial în timpul moștenirii de la cel mai vechi strămoș la cel mai recent copil și invers, destructorii sunt chemați de la cel mai recent copil la cel mai vechi strămoș.

classFirst _ { public : First () { cout << ">>Primul constructor" << endl ; } ~ First () { cout << ">>First destructor" << endl ; } }; clasa a doua : public Prima { public : Second () { cout << ">Al doilea constructor" << endl ; } ~ Second () { cout << ">Secund destructor" << endl ; } }; clasa a treia : public a doua { public : Third () { cout << "Al treilea constructor" << endl ; } ~ Third () { cout << "Third destructor" << endl ; } }; // executarea codului Third * th = new Third (); șterge th ; // rezultat rezultat /* >>Primul constructor >Al doilea constructor Al treilea constructor Al treilea distrugător >Al doilea distrugător >>Primul distrugător */

Link -uri

Note

  1. pe ordinea rezoluției metodei în Python
  2. Ce este programarea orientată pe obiecte . wh-db.com (30 iunie 2015).
  3. C# Language Specification Versiunea 4.0, Copyright © Microsoft Corporation 1999-2010