Periytys (ohjelmointi)

Periytys (eng. inheritance ) - olio-ohjelmoinnin käsite , jonka mukaan abstrakti tietotyyppi voi periä jonkin olemassa olevan tyypin tiedot ja toiminnallisuuden, mikä helpottaa ohjelmistokomponenttien uudelleenkäyttöä .

Terminologia

Olio -ohjelmoinnissa Simula 67 :stä lähtien abstrakteja tietotyyppejä kutsutaan luokiksi .

Superclass ( eng.  super class ), yläluokka ( eng.  parent class ), esi-, yläluokka tai superluokka - luokka, joka tuottaa perinnön alaluokissa, eli luokka, josta muut luokat perivät. Superluokka voi olla alaluokka, perusluokka, abstrakti luokka ja rajapinta.

Alaluokka ( eng.  subclass ), johdettu luokka ( eng.  derived class ), alaluokka ( eng.  child class ), jälkeläinen luokka, seuraajaluokka tai toteutusluokka - luokka, joka on peritty superluokasta tai rajapinnasta, eli luokka, joka on määritetty periytymällä toinen luokka tai useita tällaisia ​​luokkia. Alaluokka voi olla superluokka.

Perusluokka on luokka , joka on luokan  periytymishierarkian huipulla ja alaluokkapuun alaosassa, eli se ei ole alaluokka eikä peri muilta superluokilta tai rajapinnoilta. Perusluokka voi olla abstrakti luokka ja käyttöliittymä. Mikä tahansa ei-perusluokka on alaluokka.

Rajapinta on rakenne , joka määrittelee puhtaan luokkarajapinnan  , joka koostuu abstrakteista menetelmistä. Liitännät osallistuvat luokkien ja rajapintojen periytymishierarkiaan.

Superrajapinta ( eng.  super interface ) tai esi-isärajapinta on superluokan analogi periytymishierarkiassa, eli se on rajapinta, joka perii alaluokissa ja alirajapinnoissa.

Jälkirajapinta, johdettu rajapinta tai johdettu  rajapinta on rajapintojen periytymishierarkiassa olevan alaluokan analogi, eli se on yhdestä tai useammasta superrajapinnasta peritty rajapinta.

Perusrajapinta vastaa perusluokkaa rajapintojen periytymishierarkiassa, eli se on periytymishierarkian huipulla oleva rajapinta.

Periytyshierarkia tai luokkahierarkia on puu, jonka elementit ovat luokkia ja rajapintoja.

Sovellus

Periytys on mekanismi koodin uudelleenkäyttöön (englanninkielinen koodin uudelleenkäyttö ) ja edistää ohjelmiston itsenäistä laajentamista avoimien luokkien (englanninkieliset julkiset luokat) ja rajapintojen (englanninkieliset rajapinnat) kautta. Luokkien välisen periytymissuhteen asettaminen luo luokkahierarkian .

Periytys ja alatyyppipolymorfismi

Periytys tunnistetaan usein alatyyppipolymorfismiin :

Yllä olevasta huomautuksesta huolimatta perinnöllisyys on laajalti käytetty mekanismi is -suhteen luomiseksi. Jotkut ohjelmointikielet ovat yhtä mieltä periytyvyydestä ja alatyyppipolymorfismista (useimmiten staattisesti kirjoitetut kielet, kuten C++C#Java ja Scala ), kun taas toiset jakavat yllä olevat käsitteet.

Periytys – edes ohjelmointikielissä, jotka tukevat perinnön käyttöä alatyypin polymorfismin mekanismina – ei takaa alatyypin käyttäytymispolymorfismia; katso: "Korvaava periaate", kirjoittanut Barbara Liskov .

Periytystyypit

"Yksinkertainen" perintö

"Yksinkertainen" perintö, jota joskus kutsutaan kertaperinnöksi, kuvaa kahden luokan välistä suhdetta, joista toinen perii toisen. Monet luokat voivat johtaa yhdestä luokasta, mutta silti tällainen suhde pysyy "yksinkertaisena" perinnönä.

Abstraktit luokat ja objektien luominen

Joillekin ohjelmointikielille seuraava käsite pätee.

On olemassa "abstrakteja" luokkia (julistetaan sellaisiksi mielivaltaisesti tai niille määritettyjen abstraktien menetelmien vuoksi ); niillä voidaan kuvata kenttiä ja menetelmiä . Objektien (instanssien) luominen tarkoittaa konkretisointia , jota voidaan soveltaa vain ei-abstrakteihin luokkiin (mukaan lukien abstraktien ei-abstraktit jälkeläiset), joiden edustajia tuloksena ovat luodut objektit.

Esimerkki: Olkoon perusluokka " Yliopiston työntekijä ", josta luokat " Jatko-opiskelija " ja " Professori " periytyvät, olla abstrakti. Luokkien yhteiset kentät ja funktiot (esimerkiksi kenttä "Syntymävuosi") voidaan kuvata perusluokassa. Ja ohjelma luo objekteja vain johdetuista luokista: "Jatko-opiskelija" ja "Professori"; ei yleensä ole järkevää luoda perusluokkien objekteja.

Moniperintö

Moniperinnössä luokassa voi olla useampi kuin yksi vanhempi. Tässä tapauksessa luokka perii kaikkien esi -isiensä menetelmät . Tämän lähestymistavan etuna on suurempi joustavuus.

Moninkertainen periytyminen on toteutettu C++ :ssa . Muita tämän ominaisuuden tarjoavia kieliä ovat Python ja Eiffel . UML tukee useampaa periytymistä .

Moniperintö on mahdollinen virhelähde, joka voi johtua samoista menetelmänimistä esivanhemmissa. Kielissä, jotka on asetettu C++ :n seuraajiksi ( Java , C# ja muut), päätettiin luopua moninkertaisesta periytymisestä rajapintojen hyväksi . Voit melkein aina tehdä ilman tämän mekanismin käyttöä. Jos tällainen tarve kuitenkin ilmaantui, niin samannimisen perittyjen menetelmien käytön ristiriitojen ratkaisemiseksi on mahdollista esimerkiksi käyttää näkyvyyslaajennustoimintoa - "::" - kutsua tiettyä menetelmää tietty vanhempi.

Eiffel -kielellä yritettiin ratkaista ongelma, joka koskee samojen menetelmänimien käyttöä esivanhemmissa , jossa uutta luokkaa kuvattaessa on välttämätöntä ilmoittaa erikseen kunkin perityn luokan tuodut jäsenet ja niiden nimeäminen lasten luokka.

Useimmat nykyaikaiset olio-ohjelmointikielet ( C# , Java , Delphi ja muut) tukevat kykyä periä samanaikaisesti esivanhemmilta luokalta ja toteuttaa useiden saman luokan rajapintojen menetelmiä. Tämän mekanismin avulla voit suurelta osin korvata useita perinnöllisiä - rajapintamenetelmät on määriteltävä uudelleen, mikä eliminoi virheet, kun peritään eri esivanhempainluokkien samojen menetelmien toimivuutta.

Yksi perusluokka

Useissa ohjelmointikielissä kaikki luokat, joko eksplisiittisesti tai implisiittisesti, perivät jostain perusluokasta. Smalltalk oli yksi ensimmäisistä kielistä, jotka käyttivät tätä käsitettä. Näitä kieliä ovat myös: Objective-C (luokka NSObject), Perl ( UNIVERSAL), Eiffel ( ANY), Java ( java.lang.Object), C# ( System.Object), Delphi ( TObject), Scala ( Any).

Ohjelmointikielien periytyminen

C++

Periytys C++ :ssa :

luokka A { }; // Perusluokka luokka B : julkinen A {}; // Julkinen perintöluokka C : suojattu A {}; // Suojattu perintöluokka Z : yksityinen A { }; // Yksityinen perintö

C++ : ssa on kolmenlaisia ​​perintöjä : julkinen , suojattu , yksityinen . Perusluokan jäsenten käyttöoikeusmääritykset muuttuvat jälkeläisissä seuraavasti:

  • Jos luokka on ilmoitettu toisen luokan perusluokaksi käyttöoikeusmäärityksellä...
    • ... julkinen :
      • perusluokan julkiset jäsenet - saatavilla johdetun luokan julkisina jäseninä;
      • perusluokan suojatut jäsenet - saatavilla johdetun luokan suojattuina jäseninä;
    • … suojattu :
      • perusluokan julkiset ja suojatut jäsenet ovat saatavilla johdetun luokan suojattuina jäseninä;
    • … yksityinen :
      • perusluokan julkiset ja suojatut jäsenet ovat saatavilla johdetun luokan yksityisinä jäseninä.

Yksi julkisen perinnön tärkeimmistä eduista on se, että johdettuihin luokkiin johtava osoitin voidaan muuntaa implisiittisesti perusluokkaan johtavaksi osoittimeksi, joten yllä olevaan esimerkkiin voit kirjoittaa:

A * a = uusiB ( );

Tämä mielenkiintoinen ominaisuus avaa mahdollisuuden dynaamiseen tyyppitunnistukseen (RTTI).

Delphi (Object Pascal)

Jotta voit käyttää perintömekanismia Delphissäclass , sinun on määritettävä esivanhempien luokka luokkailmoituksessa suluissa :

Esi-isä:

TAncestor = luokka yksityinen suojattu julkinen // Virtuaalinen proseduuri VirtualProcedure ; virtuaalinen ; abstrakti ; menettely StaticProcedure ; loppu ;

Perillinen:

TDescendant = luokka ( TAncestor ) yksityinen suojattu julkinen // Virtuaaliproseduurin ohitusmenettely VirtualProcedure ; ohittaa ; menettely StaticProcedure ; loppu ;

Ehdottomasti kaikki Delphin luokat ovat jälkeläisiä . Jos esi-isäluokkaa ei ole määritetty, uuden luokan oletetaan olevan :n suora jälkeläinen . TObjectTObject

Delphin moninkertaista perintöä ei alunperin tueta periaatteessa, mutta niille, jotka eivät tule toimeen ilman sitä, on edelleen tällaisia ​​mahdollisuuksia esimerkiksi auttajaluokkien (Class Helpers) avulla.

Python

Python tukee sekä yksi- että moniperintöä. Attribuuttia käytettäessä johdettujen luokkien katselu tapahtuu menetelmän  resoluutiojärjestyksen (MRO ) järjestyksessä [1] .

luokka Ancestor1 ( objekti ): # Ancestor-1 def m1 ( itse ): läpäissyt luokan Ancestor2 ( objekti ): # Ancestor-2 def m1 ( itse ): läpäissyt luokan Jälkiläinen ( Ancestor1 , Ancesstor2 ): # Descendant def m2 ( itse ): kulkea d = jälkeläinen () # Instanssitulostus d . __luokka__ . __mro__ # Menetelmän ratkaisujärjestys: ( < luokka ' __main__ . Jälkeläinen '>, <luokka ' __main__ . Ancesstor1 '>, <class ' __main__ . Ancesstor2 '>, <type ' object '>)

Python 2.2 : sta lähtien kielessä on rinnakkain "klassiset" luokat ja "uudet" luokat. Jälkimmäiset ovat perillisiä object. "Klassisia" luokkia tuetaan versioon 2.6 asti, mutta ne poistetaan Python 3.0:n kielestä.

Pythonissa käytetään moniperintöä erityisesti yhdistämään pääluokkaan . 

PHP

Periytysmekanismin käyttämiseksi PHPextends :ssä on tarpeen määrittää sana ja esivanhempien luokan nimi ilmoitetun seuraajaluokan nimen jälkeen luokkailmoituksessa :

luokan jälkeläinen laajentaa esi-isän { }

Jos johdettu luokka on päällekkäinen esivanhempien menetelmien kanssa, esivanhempainmenetelmiin pääsee käyttämällä parent:

class A { funktio esimerkki () { echo "Methode A::example() kutsutaan.<br /> \n " ; } } luokka B laajentaa A { funktio esimerkki () { echo "Methode B::example() kutsutaan.<br /> \n " ; vanhempi :: esimerkki (); } }

On mahdollista estää johdettua luokkaa ohittamasta esi-isän menetelmiä; tehdäksesi tämän sinun on määritettävä avainsana final:

class A { lopullinen funktio esimerkki () { echo "Methode A::example() kutsutaan.<br /> \n " ; } } luokka B laajentaa A { funktio esimerkki () { //heittää virheen vanhemman :: esimerkki (); //ja ei koskaan suorita } }

Jotta periytymisen aikana viitataan emoluokan konstruktoriin, on aliluokan määritettävä konstruktorissa parent::__construct();[2]

Objective-C

@rajapinta A  : NSObject - ( mitätön ) esimerkki ; @loppu @toteutus - ( mitätön ) esimerkki { NSLog ( @"ClassA" ); } @loppu @käyttöliittymä B  : A - ( tyhjä ) esimerkki ; @loppu @toteutus - ( mitätön ) esimerkki { NSLog ( @"ClassB" ); } @loppu

Käyttöliittymä määrittelee menetelmät, jotka näkyvät luokan ulkopuolella (julkinen).

Sisäiset menetelmät voidaan toteuttaa ilman rajapintaa. Jos haluat ilmoittaa lisäominaisuuksia, käytä toteutustiedostossa interface-laajennusta.

Kaikki Objective-C:n menetelmät ovat virtuaalisia.

Java

Esimerkki periytymisestä yhdestä luokasta ja kahdesta rajapinnasta :

julkinen luokka A { } julkinen liitäntä I1 { } julkinen liitäntä I2 { } julkinen luokka B laajentaa A toteuttaa I1 , I2 { }

Luokkailmoituksessa finaloleva käsky tekee siitä perimisen mahdottomaksi.

C#

Esimerkki periytymisestä yhdestä luokasta ja kahdesta rajapinnasta :

julkinen luokka A { } julkinen liitäntä I1 { } julkinen liitäntä I2 { } julkinen luokka B : A , I1 , I2 { }

Tyypitetyistä luokista periminen voidaan tehdä määrittämällä kiinteä tyyppi tai siirtämällä tyyppimuuttuja perittyyn luokkaan:

julkinen luokka A < T > { } julkinen luokka B : A < int > { } julkinen luokka B2 < T > : A < T > { }

On myös mahdollista periä sisäkkäisiä luokkia luokilta, jotka sisältävät niitä:

luokka A // oletusluokka A on sisäinen, ei julkinen luokka B ei voi olla julkinen { luokka B : A { } }

Luokkailmoituksessa sealedoleva käsky tekee siitä perimisen mahdottomaksi. [3]

Ruby

luokan vanhempi def public_method "Julkinen menetelmä" end yksityinen def private_method "Yksityinen menetelmä" end loppu luokkalapsi < vanhempi _ def public_method "Uudelleenmääritetty julkinen menetelmä" end def call_private_method "Esivanhemman yksityinen menetelmä: " + private_method end loppu

Luokka Parenton sen luokan esi-isä, Childjonka menetelmä on ohitettu public_method.

lapsi = lapsi . uusi lapsi . _ public_method #=> "Uudelleenmääritetty julkinen menetelmä" lapsi . call_private_method #=> "Esivanhemman yksityinen menetelmä: Yksityinen menetelmä"

Esivanhemman yksityiset menetelmät voidaan kutsua jälkeläisistä.

JavaScript

class Parent { rakentaja ( data ) { this . data = data ; } publicMethod () { return 'Julkinen menetelmä' ; } } class Child extens Parent { getData () { return `Data: ${ this . data } ` ; } publicMethod () { return 'Uudelleenmääritetty julkinen menetelmä' ; } } const testi = newChild ( ' testi' ); testi . getdata (); // => 'Data: testi' testi . publicMethod (); // => 'Uudelleenmääritetty julkinen menetelmä' -testi . tiedot ; // => 'testi'

Luokka Parenton sen luokan esi-isä, Childjonka menetelmä on ohitettu publicMethod.

JavaScript käyttää prototyyppiperintöä.

Rakentajat ja tuhoajat

C++ : ssa konstruktoreita kutsutaan peräkkäin perinnön aikana vanhimmasta esi-isästä viimeisimpään lapseen, ja päinvastoin, destruktoreita kutsutaan uusimmasta lapsesta vanhimpaan esi-isään.

luokka ensimmäinen _ { julkinen : Ensimmäinen () { cout << ">>Ensimmäinen konstruktori" << endl ; } ~ Ensimmäinen () { cout << ">>Ensimmäinen tuhoaja" << endl ; } }; luokka Toinen : julkinen ensimmäinen { julkinen : Toinen () { cout << ">Toinen konstruktori" << endl ; } ~ Toinen () { cout << ">Toinen tuhoaja" << endl ; } }; luokka Kolmas : julkinen Toinen { julkinen : Kolmas () { cout << "Kolmas konstruktori" << endl ; } ~ Kolmas () { cout << "Kolmas tuhoaja" << endl ; } }; // koodin suoritus Kolmas * th = uusi Kolmas (); poista th ; // tulostulos /* >>Ensimmäinen konstruktori >Toinen konstruktori Kolmas konstruktori Kolmas tuhoaja > toinen tuhoaja >> ensimmäinen tuhoaja */

Linkit

Muistiinpanot

  1. menetelmän resoluutiojärjestyksestä Pythonissa
  2. Mikä on olio-ohjelmointi . wh-db.com (30. kesäkuuta 2015).
  3. C#-kielimääritysten versio 4.0, Copyright © Microsoft Corporation 1999-2010