Öröklődés (programozás)

Inheritance (eng. inheritance ) - az objektum-orientált programozás fogalma , amely szerint egy absztrakt adattípus örökölheti valamilyen létező típus adatait és funkcionalitását, megkönnyítve a szoftverkomponensek újrafelhasználását .

Terminológia

Az objektumorientált programozásban a Simula 67 óta az absztrakt adattípusokat osztályoknak nevezik .

Szuperosztály ( eng.  super class ), szülő osztály ( eng.  parent class ), ős, szülő vagy szuperosztály - olyan osztály, amely az alosztályokban öröklődik, vagyis olyan osztály, amelyből más osztályok örökölnek. A szuperosztály lehet egy alosztály, egy alaposztály, egy absztrakt osztály és egy interfész.

Alosztály ( eng.  subclass ), származtatott osztály ( eng.  derived class ), leszármazott osztály ( eng.  child class ), leszármazott osztály, utódosztály vagy megvalósító osztály - egy szuperosztálytól vagy interfésztől örökölt osztály, azaz egy olyan osztály, amelyet a következőtől öröklöttek meg. egy másik osztály vagy több ilyen osztály. Egy alosztály lehet szuperosztály.

Az  alaposztály olyan osztály , amely az osztályöröklési hierarchia tetején és az alosztályfa alján található, azaz nem alosztály, és nem örököl más szuperosztályoktól vagy interfészektől. Az alaposztály lehet egy absztrakt osztály és egy interfész. Minden nem alaposztály alosztály.

Az  interfész egy olyan struktúra, amely egy absztrakt metódusokból álló tiszta osztályinterfészt határoz meg. Az interfészek részt vesznek az osztályok és interfészek öröklési hierarchiájában.

A szuperinterfész ( eng.  super interface ) vagy egy ősinterfész egy szuperosztály analógja az öröklési hierarchiában, vagyis olyan interfész, amely alosztályokban és alinterfészekben öröklődik.

A leszármazott interfész, származtatott interfész vagy származtatott  interfész egy alosztály analógja az interfészek öröklődési hierarchiájában, azaz egy vagy több szuperinterfésztől örökölt interfész.

Az alap interfész az interfészek öröklődési hierarchiájában egy alaposztály megfelelője, azaz az öröklési hierarchia tetején található interfész.

Az öröklési hierarchia vagy osztályhierarchia egy fa, amelynek elemei osztályok és interfészek.

Alkalmazás

Az öröklődés a kód újrafelhasználásának mechanizmusa (angol code reuse ), és hozzájárul a szoftverek független kiterjesztéséhez nyílt osztályokon (angol nyilvános osztályok) és interfészeken (angol interfészek) keresztül. Az osztályok közötti öröklődési kapcsolat beállítása osztályhierarchiát generál .

Öröklődés és altípus polimorfizmus

Az öröklődést gyakran az altípus-polimorfizmussal azonosítják :

A fenti megjegyzés ellenére az öröklődés egy széles körben használt mechanizmus az is -a kapcsolat létrehozására. Egyes programozási nyelvek egyetértenek az öröklődési és altípus-polimorfizmusban (többnyire statikusan tipizált nyelvek , mint a C++C#Java és Scala ), míg mások a fenti fogalmakat osztják.

Az öröklődés – még azokban a programozási nyelvekben sem, amelyek támogatják az öröklődésnek az altípus-polimorfizmus mechanizmusaként való használatát – nem garantálja az altípus viselkedési polimorfizmusát; lásd: "A helyettesítési elv" Barbara Liskovtól .

Öröklődés típusai

"Egyszerű" öröklődés

Az „egyszerű” öröklődés, amelyet néha egyszeri öröklődésnek is neveznek, két osztály közötti kapcsolatot írja le, amelyek közül az egyik örökli a másikat. Sok osztály származhat egyetlen osztályból, de még így is ez a fajta kapcsolat "egyszerű" öröklődés marad.

Absztrakt osztályok és objektumok létrehozása

Egyes programozási nyelvekre a következő fogalom érvényes.

Vannak "absztrakt" osztályok (tetszőlegesen vagy a hozzájuk rendelt absztrakt metódusok miatt ilyennek nyilvánítva ); úgy írhatók le, hogy mezőkkel és módszerekkel rendelkeznek . Az objektumok (példányok) létrehozása konkretizálást jelent , amely csak a nem absztrakt osztályokra vonatkozik (beleértve az absztraktok nem absztrakt leszármazottait is), amelyek képviselői ennek eredményeként a létrehozott objektumok lesznek.

Példa: Legyen absztrakt az „ Egyetem alkalmazottja” alaposztály , amelyből a „ Posztgraduális hallgató ” és „ Professzor ” osztályok öröklődnek. Az osztályok közös mezői és funkciói (például a "Születési év" mező) az alaposztályban írhatók le. És a program csak származtatott osztályokból hoz létre objektumokat: "Posztgraduális hallgató" és "Professzor"; általában nincs értelme alaposztályokból álló objektumokat létrehozni.

Többszörös öröklődés

Többszörös öröklődés esetén egy osztálynak több szülője is lehet. Ebben az esetben az osztály örökli az összes ős metódusait . Ennek a megközelítésnek az előnye a nagyobb rugalmasság.

A többszörös öröklődés a C++ nyelven valósul meg . A funkciót biztosító egyéb nyelvek közé tartozik a Python és az Eiffel . Az UML támogatja a többszörös öröklődést .

A többszörös öröklődés potenciális hibaforrás, amely abból eredhet, hogy az ősökben ugyanazok a metódusnevek vannak. Azokon a nyelveken, amelyeket a C++ utódjaként helyeztek el ( Java , C# és mások), úgy döntöttek, hogy elhagyják a többszörös öröklődést az interfészek javára . Szinte mindig nélkülözheti ezt a mechanizmust. Ha azonban mégis felmerült egy ilyen igény, akkor az azonos nevű öröklött metódusok használatában felmerülő konfliktusok feloldására lehetőség van például a láthatósági kiterjesztési művelet - "::" - alkalmazására egy adott metódus meghívására. konkrét szülő.

Kísérlet történt az ősökben azonos metódusnevek problémájának megoldására az Eiffel -nyelvben , amelyben egy új osztály leírásánál egyértelműen meg kell jelölni az egyes öröklött osztályok importált tagjait és elnevezésüket a gyerek osztály.

A legtöbb modern objektum-orientált programozási nyelv ( C# , Java , Delphi és mások) támogatja azt a képességet, hogy egyidejűleg örököljenek egy ősosztályból és implementálják több interfész metódusait ugyanazon osztály által. Ez a mechanizmus lehetővé teszi több öröklődés nagymértékben helyettesítését - az interfész metódusait kifejezetten újra kell definiálni, ami kiküszöböli a hibákat a különböző ősosztályok azonos metódusainak funkcionalitásának öröklése során.

Egyetlen alaposztály

Számos programozási nyelvben minden osztály, akár explicit, akár implicit módon, valamilyen alaposztályból örököl. A Smalltalk volt az egyik első nyelv, amely ezt a fogalmat használta. Ezek a nyelvek még: Objective-C (class NSObject), Perl ( UNIVERSAL), Eiffel ( ANY), Java ( java.lang.Object), C# ( System.Object), Delphi ( TObject), Scala ( Any).

Öröklődés programozási nyelvekben

C++

Öröklődés C++ nyelven :

classA { }; // Alaposztály B osztály : nyilvános A {}; // Nyilvános öröklési osztály C : védett A {}; // Védett öröklési osztály Z : privát A {}; // Magánöröklés

A C++- ban háromféle öröklődés létezik : nyilvános , védett , privát . Az alaposztály tagjainak hozzáférési specifikációi a leszármazottakban az alábbiak szerint változnak:

  • Ha egy osztály egy másik osztály alaposztályaként van deklarálva egy hozzáférési specifikációval...
    • ... nyilvános :
      • az alaposztály nyilvános tagjai - elérhető a származtatott osztály nyilvános tagjaiként;
      • az alaposztály védett-tagjai - elérhető a származtatott osztály védett-tagjaiként;
    • … védett :
      • az alaposztály nyilvános és védett tagjai elérhetők a származtatott osztály védett tagjaiként;
    • ... privát :
      • Az alaposztály nyilvános és védett tagjai elérhetők a származtatott osztály privát tagjaiként.

A nyilvános öröklődés egyik fő előnye, hogy a származtatott osztályokra mutató mutató implicit módon átalakítható az alaposztályra mutató mutatóvá, így a fenti példában ezt írhatja:

A * a = újB ( );

Ez az érdekes funkció megnyitja a dinamikus típusazonosítás (RTTI) lehetőségét.

Delphi (Object Pascal)

A Delphiclass öröklési mechanizmusának használatához meg kell adnia az ősosztályt az osztálydeklarációban zárójelben :

Ős:

TAncestor = class private protected public // Virtuális eljárási eljárás VirtualProcedure ; virtuális ; absztrakt ; eljárás StatikusEljárás ; vége ;

Örökös:

TDescendant = osztály ( TAncestor ) private protected public // Virtuális eljárás felülbírálási eljárás VirtualProcedure ; felülbírálni ; eljárás StatikusEljárás ; vége ;

A Delphi összes osztálya a leszármazottja . Ha nincs megadva egy ősosztály, akkor az új osztályt a . TObjectTObject

A Delphiben a többszörös öröklést kezdetben elvileg nem támogatják, de aki nem tudja nélkülözni, annak még mindig van ilyen lehetőség, például segítő osztályok (Class Helpers) használatával.

Python

A Python támogatja az egyszeres és többszörös öröklődést is. Egy attribútum elérésekor a származtatott osztályok megtekintése a metódusfeloldási  sorrend (MRO ) sorrendjében történik [1] .

osztály Ancestor1 ( objektum ): # Ancestor-1 def m1 ( self ): pass Class Ancestor2 ( object ): # Ancestor-2 def m1 ( self ): pass Class Descendant ( Ancestor1 , Ancestor2 ): # Descendant def m2 ( self ): pass d = leszármazott () # Példánynyomtatás d . __osztály__ . __mro__ # Metódusfeloldási sorrend: ( < class ' __main__ . Descendant '>, <class ' __main__ . Ancestor1 '>, <class ' __main__ . Ancestor2 '>, <type ' object '>)

A Python 2.2-től kezdve a "klasszikus" osztályok és az "új" osztályok együtt léteznek a nyelvben. Utóbbiak az örökösök object. A "klasszikus" osztályok a 2.6-os verzióig támogatottak, de a Python 3.0-ban eltávolítják a nyelvből.

A Pythonban a többszörös öröklődést használják, különösen a keverési osztályok fő osztályba történő bevezetésére . 

PHP

Az öröklődési mechanizmus PHPextends -ben való használatához meg kell adni a szót és az ősosztály nevét a deklarált utódosztály neve után az osztálydeklarációban :

osztály leszármazottja kiterjeszti az ős { }

Ha a származtatott osztály átfedésben van az ősmetódusokkal, az ősmetódusok a következővel érhetők el parent:

class A { function example () { echo "Az A::example() metódus meghívva.<br /> \n " ; } } class B expands A { function example () { echo "A B::example() metódus meghívva.<br /> \n " ; szülő :: példa (); } }

Meg lehet akadályozni, hogy egy származtatott osztály felülírja egy ős metódusait; ehhez meg kell adnia a kulcsszót final:

class A { final function example () { echo "Az A::example() metódus meghívva.<br /> \n " ; } } class B kiterjeszti A { function example () { //hiba szülőt fog dobni :: példa (); //és soha nem fog végrehajtani } }

Ahhoz, hogy az öröklődés során a szülő osztály konstruktorára hivatkozhassunk, szükséges, hogy a gyerekosztályt a konstruktorban megadjuk parent::__construct();[2]

Objective-C

@interfész A  : NSObject - ( érvénytelen ) példa ; @vége @implementáció - ( érvénytelen ) példa { NSLog ( @"ClassA" ); } @vége @B interfész  : A - ( érvénytelen ) példa ; @vége @implementáció - ( érvénytelen ) példa { NSLog ( @"ClassB" ); } @vége

Az interfész deklarál metódusokat, amelyek az osztályon kívül is láthatóak lesznek (nyilvános).

A belső módszerek interfész nélkül is megvalósíthatók. További tulajdonságok deklarálásához használja az interfész-kiterjesztést a megvalósítási fájlban.

Az Objective-C összes metódusa virtuális.

Java

Példa az öröklődésre egy osztályból és két interfészből :

public class A { } public interface I1 { } public interface I2 { } public class B extenss A implements I1 , I2 { }

Az osztálydeklarációban lévő direktíva finallehetetlenné teszi az öröklést.

C#

Példa az öröklődésre egy osztályból és két interfészből :

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

A tipizált osztályokból való öröklés történhet egy rögzített típus megadásával, vagy egy típusváltozó átvitelével egy örökölt osztályba:

nyilvános osztály A < T > { } nyilvános osztály B : A < int > { } nyilvános osztály B2 < T > : A < T > { }

Lehetőség van beágyazott osztályok örökölésére is az azokat tartalmazó osztályokból:

A osztály // alapértelmezett A osztály belső, nem nyilvános, B osztály nem lehet nyilvános { B osztály : A { } }

Az osztálydeklarációban lévő direktíva sealedlehetetlenné teszi az öröklést. [3]

Ruby

osztályos szülő def public_method "Nyilvános metódus" end magán def private_method "Privát metódus" end vége osztálygyermek < szülő _ def public_method "Újradefiniált nyilvános metódus" end def call_private_method "Az ősök privát metódusa: " + private_method end vége

Az osztály Parentannak az osztálynak az őse, Childamelynek metódusa felül van írva public_method.

gyermek = Gyermek . új gyerek . _ public_method #=> "Újradefiniált nyilvános metódus" gyermek . call_private_method #=> "Az ősök privát metódusa: Privát metódus"

Az ősök privát módszerei a leszármazottakból hívhatók.

JavaScript

class Szülő { konstruktor ( adat ) { this . adat = adat ; } publicMethod () { return 'Public Method' ; } } class Gyermek kiterjeszti Szülő { getData () { return `Adatok: ${ this . adatok } ` ; } publicMethod () { return 'Újradefiniált nyilvános metódus' ; } } const teszt = newChild ( ' teszt' ); teszt . getdata (); // => 'Adatok: teszt' teszt . publicMethod (); // => 'Újradefiniált nyilvános metódus' teszt . adatok ; // => 'teszt'

Az osztály Parentannak az osztálynak az őse, Childamelynek metódusa felül van írva publicMethod.

A JavaScript prototípus öröklődést használ .

Konstruktorok és destruktorok

A C++ nyelvben a konstruktorokat szekvenciálisan hívják az öröklődés során a legkorábbi őstől a legkésőbbi gyermekig, és fordítva, a destruktorokat a legújabb gyermektől a legkorábbi ősig.

osztályelső _ { nyilvános : Első () { cout << ">>Első konstruktor" << endl ; } ~ Első () { cout << ">>Első destruktor" << endl ; } }; osztály Második : nyilvános Első { nyilvános : Második () { cout << ">Második konstruktor" << endl ; } ~ Második () { cout << ">Második destruktor" << endl ; } }; osztály Harmadik : nyilvános Második { nyilvános : Harmadik () { cout << "Harmadik konstruktor" << endl ; } ~ Harmadik () { cout << "Harmadik romboló" << endl ; } }; // kód végrehajtása Third * th = new Third (); törölje th ; // kimeneti eredmény /* >>Első konstruktor >Második konstruktor Harmadik konstruktor Harmadik romboló > Második romboló >> Első romboló */

Linkek

Jegyzetek

  1. a metódusfeloldási sorrendről a Pythonban
  2. Mi az objektum-orientált programozás ? wh-db.com (2015. június 30.).
  3. C# nyelvi specifikáció 4.0-s verzió, Copyright © Microsoft Corporation 1999-2010