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öä .
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.
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 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 .
"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 luominenJoillekin 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.
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.
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).
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:
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).
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 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 .
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]
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.
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.
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]
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ä.
Luokka Parenton sen luokan esi-isä, Childjonka menetelmä on ohitettu publicMethod.
JavaScript käyttää prototyyppiperintöä.
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 */