Peruskäsitteitä

Perintä (inheritance)

Perintä on yksi keskeisimmistä toiminnoista olio-ohjelmoinnissa. Jos luokilla tunnistetaan samanlaisia ominaisuuksia ja/tai toiminnallisuutta, voidaan käyttää hyväksi perintää. Tällöin samanlaisia ominaisuudet ja/tai toiminnallisuus voidaan määritellä vain yhdessä paikassa, josta käytetään nimitystä kantaluokka ja periyttää siitä periytettäviin luokkiin. (Suomenkielessä käytetään myös nimityksiä yliluokka ja aliluokka). Näin olemassa olevan luokan ominaisuudet ja toiminnot saadaan toisen luokan käyttöön.

Olio-ohjelmoinnissa on tärkeää, ettei samanlaista koodia kirjoitella useisiin luokkiin. Esimerkiksi tietokonepelissä pelaajan hahmo ja viholliset liikkuvat ja toimivat samojen sääntöjen mukaisesti (esim. PacMan-peli). Tuolloin PacManin liikkeistä päättää pelaaja ja haamujen liikkeistä tietokoneelle ohjelmoitu tekoäly. Molemmille tapauksille löytyy kuitenkin paljon yhteisiä ominaisuuksia ja toimintoja. Nämä yhteiset toiminnallisuudet voidaan kirjoittaa yhteiseen kantaluokkaan ja molempien omat yksityiset ominaisuudet ja toiminnot kirjoitetaan omiin aliluokkiinsa. Kantaluokkien ja aliluokkien kokonaisuutta kutsutaan luokkahierarkiaksi.

Erikoistuminen ja yleistäminen (Specialization and Generalization)

Luokat ja niiden instanssit, oliot eivät ole olemassa tyhjiössä, vaan enemmänkin keskinäisten riippuvuuksien ja suhteiden verkostossa. Is-a (vapaasti tekijän suomentamana "kuuluu") -suhde on erikoistumisen (specialization) muodoista. Voimme sanoa, että Koira kuuluu Nisäkkäisiin. Olio-ohjelmoinnissa voisimme sanoa, että koska Koira-luokka voidaan periyttää Nisäkäs-luokasta niin näiden kahden luokan välinen suhde on Is-a. Ja koska koirat ovat tietytyyppisiä nisäkkäitä, niillähän on yleensä neljä jalkaa, kuono, kaksi korvaa, karvat häntä ja ne osaavat haukkua ja murista, jota taas kaikki nisäkkäät eivät osaa tehdä. Voimme sanoa, että koira on tietyntyyppinen erikoistunut nisäkäs.

Perinnän etuina ovat mm. koodin uudelleenkäyttö, ohjelmoinnin ylläpidon selkiytyminen, suurempien ohjelmointikokoisuuksien pilkkominen pienemmäksi.

Korvaaminen eli ylikirjoittaminen (override)

Periytetyt ominaisuudet ja/tai toiminnallisuus voidaan tarvittaessa jopa korvata toisenlaisilla ominaisuuksilla ja/tai toiminnallisuudella. Tätä kutsutaan ylikirjoittamiseksi (override).
Ylikirjoittaminen voidaan tarvittaessa estää luokan Sealad-määreellä. Myöskään luokan sisäisiä eli yksityisiä jäseniä (private-suojamääreellä määritellyt) ei voi ylikirjoittaa. Tätä varten on mahdollista käyttää suojattuja (protected) ominaisuuksia ja/tai toimintoja, jotka näkyvät yliluokasta aliluokkiin, mutta eivät näy näiden luokkien ulkopuolelle.

Perinnän määrittely

Periytyvyys merkitään alla olevan mallin mukaisesti luokkamäärittelyn yhteydessä. Aliluokka (derived class) ja Yliluokka (base class).



    

Esimerkki: Person-yliluokka

Alla olevassa esimerkissä yliluokkana toimii Person-luokka, joka käsittelee yleisesti henkilölle kuuluvia ominaisuuksia ja toimintoja. Person-luokasta on peritty Teacher- ja Student-luokat, joilla on omat niille kuuluvat ominaisuudet ja toiminnot. Näin ollen yleisiä henkilölle kuuluvia ominaisuuksia ja toimintoja ei ole ohjelmoitu sekä Teacher- ja Student-luokkiin.

check_circleUML-luokkakaaviossa perintä merkitään valkopäisellä nuolella, joka osoittaa aliluokasta yliluokkaan päin.

check_circle C#:n luokat periytyvät Object-luokasta ellei kantaluokkaa ole määritelty.

Alla olevassa esimerkissä Dog-luokka periytyy Object-kantaluokasta, vaikka sitä ei erikseen määritellekään.


	

Jos halutaan, että luokka Dog periytyy Mammal-luokasta, niin silloin koodi näyttäisi tältä.


	
    

Perinnän rajoitukset

C#:ssa ei ole käytössä moninperintää eli luokka voi periytyä vain yhdestä kantaluokasta (yliluokasta). Huom: Muissa ohjelmointikielissä ehkä esiintyvää moniperintää vastaava toteutus toteutetaan C#:ssa rajapintojen (interface) avulla. Tällöin luokan "luvataan" toteuttavan yhden tai useamman rajapinnan "vaatiman" toiminnallisuuden.

Luokan perintä voidaa estää määritellemälle sille sealed-avainsana. Alla olevaa Police-luokkaa ei voi enää periyttää.


    
    

Samannimisten ominaisuuksien ja metodien yhteydessä käytettävät avainsanat

C#:ssa voidaan käyttää samannimisiä ominaisuuksia ja metodeja yli- ja aliluokissa. Tällöin voidaan käyttää seuraavia avainsanoja:

virtualmäärittelee metodin ensimmäisen toteutuksen (käytetään yliluokassa)
overridemäärittelee metodin korvaavan toteutuksen aliluokassa
sealedmäärittelee metodin viimeisen toteutuksen (ei voi enää korvata tai peittää aliluokassa)
newmäärittelee metodin peittävän toteutuksen aliluokassa

Yllä esitettyjen Person-, Teacher-, ja Student-luokkien toteuttaminen ja käyttäminen pääohjelmasta

PersonApplication

Toteutetaan opettajan ohjeiden mukaisesti PersonApplication-projekti konsoliohjelmana, joka käyttää apunaan Person-luokkaa.
1. Käynnistä Visual Studio ja tee uusi projekti nimelle PersonApplication
2. Tee uusi luokka nimelle Person (valitse PersonApplication oikealla hiiren painikkeella)
2.1 Valitse Add > Class... ja valitse Class
2.2 Anna nimeksi Person ja paina Add-painiketta
=> Nyt projekti sisältää sovelluksen pääohjelmatiedoston Program.cs ja vielä tällä hetkellä tyhjän Person.cs person-luokkatiedoston.

Person-luokan ohjelmointi

Toteutetaan opettajan ohjeita noudatellen Person-luokan ohjelmointi (käytetään apuna yllä määriteltyä Person-luokan UML-kaaviota). Rivillä 30 ylikirjoitetaan Object-luokassa määritelty ToString()-metodi tulostamaan Person-luokan tietoja.


    

Yllä olevassa Person-luokassa olisi voitu jättää kaikki luokan alustajat eli konstruktorit tekemättä, mutta tässä on nyt haluttu korostaa sitä, että luokalla voi olla useita eri konstruktoreita. Nyt Person-luokasta voi tehdä olioita käyttämällä oletuskonstruktoria tai kutsumalla parametrillistä konstruktoria, joka alustaa olion luonnin yhteydessä oliolle parametrien kautta etu- ja sukunimen.

Teacher-luokan ohjelmointi

Toteutetaan opettajan ohjeita noudatellen Teacher-luokan ohjelmointi (käytetään apuna yllä määriteltyä Teacher-luokan UML-kaaviota). Huomaa kuinka Teacher-luokan parametrillisessä konstruktorissa käytetään base-avainsanaa kutsumaan yliluokan konstruktoria, jolle välitetään etu- ja sukunimi parametrinä.


    

Student-luokan ohjelmointi

Toteutetaan opettajan ohjeita noudatellen Student-luokan ohjelmointi (käytetään apuna yllä määriteltyä Student-luokan UML-kaaviota).


    

Toteutettujen luokkien käyttäminen Program-luokassa

Nyt Teacher- ja Student-luokat ovat käytettävissä sovelluksen Program-pääluokassa (myös Person-luokka, mutta sitä ei ole tarkoitus käyttää, koska se toimii Teacher- ja Student-luokille yliluokkana). Luodaan yksi Teacher- ja Student-luokan olio ja tulostetaan olioiden tietoja näyttölaitteelle.


    

Yhteenveto

Yllä olevassa esimerkissä opettajan ja oppilaan yhteiset ominaisuudeet on siirretty henkilön ominaisuuksia käsittelevään luokkaan. Näin ollen samoja asioita ei ole tarvittu ohjelmoida useampaan kertaan, joka on yksi keskeisimmistä tavoitteista perinnän osalta. Jatkossa opintojaksolla perittävänä luokkana on useasti myös C#:n ohjelmointikirjaston luokkia, joita käytetään omassa ohjelmoinnissa apuna.

Demo: arvokas omaisuuteni

Muista että kun määrittelet kantaluokan ja sinne metodeja ja ominaisuuksia, joita halutaan ylikirjoittaa niin ne on merkittävä määreellä virtual, abstract tai override. Muuten käännettäessä koodia kääntäjä antaa virheilmoituksen:


	

Alla olevassa esimerkissä on luotu kantaluokka Asset, josta periytetään luokka Stock. Ominaisuus Value on ylikirjoitettu Stock-luokassa.


	 
    

Yhteenveto

Virtual-määrettä käytetään yliluokan ominaisuuksissa ja/tai toiminnoissa silloin, kun halutaan toteuttaa uusi toteutus aliluokissa.

Override-määrettä käytetään laajentamaan/muuttamaan yliluokan ominaisuuksia/toimintoja aliluokassa. Sidonta tapahtuu sovelluksen suorituksen aikana ("runtime polymorphism" / "late binding")

New-määrettä käytetään piilottamaan yliluokan ominaisuuksia/toimintoja aliluokassa. Sidonta tapahtuu käännöksen aikana ("compile-time polymorphism" / "early binding").

Lisätietoa

Inheritance (C# Programming Guide)