- TituCPP 6. luento 25.10.
- Materiaali
- Esimerkit
- Kalvot
- luokan toiminnallisuuden laajentamismahdollisuuksia
- muutetaan luokkaa (aikacla6)
- [ http://www.mit.jyu.fi/%7Evesal/kurssit/cpp/moniste/esim/olioalk/aikacla6.cpp ]
- koostetaan luokka osaksi uutta (aikacla7)
- [ http://www.mit.jyu.fi/%7Evesal/kurssit/cpp/moniste/esim/olioalk/aikacla7.cpp ]
- peritään uusi luokka (IS-A -suhde, aikacla8)
- [ http://www.mit.jyu.fi/~vesal/kurssit/cpp/moniste/esim/olioalk/aikacla8.cpp ]
- Aliluokan oliot tulkitaan automaattisesti yliluokan olioiksi (mutta ei päinvastoin - tyyppimuunnoksella voidaan pakottaa)
- polymorfisten metodien toteutukset voi syrjäyttää aliluokissa ja näin muuttaa olion käyttäytymistä
- Vaihtelua eri kielissä:
- C++:ssa metodi voidaan määritellä virtuaalifunktioksi (suorituskyky)
- Delphissä override-määritys virtuaalifunktioille
- Javassa kaikki metodit ovat virtuaalisia, ellei anneta määritystä final (tällöin samannimistä metodia ei voida kirjoittaa aliluokassa)
- C++:ssa myös moniperintä mahdollista, mm. Delphissä ja Javassa moniperintä korvataan rajapinnoilla ja koostamisella
- soveltuu mm. käyttöliittymiin
- esim. monirivinen tekstikenttä on tavallisen tekstikentän aliluokka
- windowsissa lähes kaikki käyttöliittymäkomponentit (ml. menut, ikkunat, painikkeet, tekstikentät jne) ovat "ikkunoita"
- luokkahierarkiat
- käsitteellistä mallintamista
- uudelleenkäyttö
- perintä helpottaa uudelleenkäyttöä, mutta saattaa myös monimutkaistaa koodia, jos metodi on "palasina" monessa eri luokassa - koodin riippuvuuksien seuranta hankalampaa (IDE:t auttavat tässä huomattavasti)
- c++ -periytymisen perusteet
- oliot
- syntaksi
- näkyvyys
- rakentajat ja purkajat
- periytymisen käyttö laajentamiseen
- virtuaalifunktiot
- kirja-luokan laajentaminen
- virtuaalifunktiot (ja yleensäkin oliolähestymistapa) mahdollistavat switch/case-ehtolauseiden vähentämisen koodista
- rtti
- c-tyylisen tyypinmuunnoksen korvaavat muunnosoperaattorit
- static_cast - "samantyyppisten" luokkien tarkistamaton muunnos (esim. muunnos osoittimesta konkreettiseen tyyppiin kielletty)
- dynamic_cast - tyypin tarkistava muunnos
- const_cast - const-määreen muuttaminen samantyyppisille olioille
- reinterpret_cast - c-tyylinen tarkistamaton muunnos
- virtuaalisia metodeja sisältävä olio sisältää (toteutustasolla) viitteen luokkansa virtuaalitauluun, joka sisältää edelleen viitteet omiin (virtuaalisiin) metodeihinsa (ks. oo-moniste)
- [ http://www.mit.jyu.fi/vesal/kurssit/winohj/html/cpp/m56.htm ]
- polymorfismi ja dynaaminen sidonta
- ks. aikacla9
- [ http://www.mit.jyu.fi/~vesal/kurssit/cpp/moniste/esim/olioalk/aikacla9.cpp ]
- polymorfismi == monimuotoisuus, sama merkintä voi asiayhteydestä riippuen useita eri asioita
- Funktioiden ja operaattorien kuormitus (overloading)
- Myöhäinen (dynaaminen) sidonta
- myöhäinen == ajonaikainen (vrt. "varhainen sidonta" == käännösaikainen, "normaali" metodin liittäminen luokkaan)
- Virtuaalifunktiot: jos perintähierarkiassa on useita samannimisiä metodeja, kutsutaan sen olion metodia, johon muuttuja toxdellisuudessa osoittaa
- edellyttää c++:ssa metodin merkintää virtual-määreellä vähintään yliluokassa
- (muuten kutsuttaisiin olion staattisen tyypin mukaista metodia)
- Hyödyllistä erityisesti olio-osoittimia (tai viitteitä) käytettäessä
- olion luokan selvittäminen
- jos luokassa on yksikin virtuaalifunktio, voidaan käyttää RTTI:tä (luokassa on virtuaalitaulu, jonka avulla ajonaikainen tyyppi voidaan selvittää)
- typeinfon name()-metodin palauttama merkkijonomuoto vaihtelee eri kääntäjillä - itse typeinfon vertailu on turvallista
- ei-virtuaalifunktiot ja peittäminen
- virtuaalifunktiot rakentajissa ja purkajissa
- elukat-esimerkki
- kutsupino perittyjen konstruktorien osalta (elukat-esimerkki)
- polymorfisen tietorakenteen läpikäynti
- konstruktori vastaa olion tilan alustamisesta
- jos aliluokan konstruktorissa ei ole mainittu kutsuttavaa yliluokan konstruktoria, kutsutaan oletuksena parametritonta oletusmuodostajaa ()
- huom. c++:ssa luokan attribuutteja ei alusteta automaattisesti - myös 0-alustukset ovat tarpeen
- varo virtuaalifunktioiden käyttöä konstruktorissa
- erityisesti, jos yliluokan konstruktori kutsuu aliluokassa olevaa metodia, joka käyttää vielä alustamattomia attribuutteja!
- turvallisinta on, jos konstruktorissa kutsutaan vain private- tai ei-virtuaalisia metodeita
- destruktoria kutsutaan oliota tuhottaessa automaattisesti
- VAROITUS: konstruktorien (ja destruktorien) tarkka käyttäytyminen luokkahierarkiassa vaihtelee eri oliokielissä (esim. C++, Java ja Object Pascal -kielissä on jokaisessa hieman erilainen logiikka, vaikka kielet ovat muuten hyvin samankaltaisia!)
- Kokeile esim. debug-tulosteilla eri tason konstruktoreilla ja destruktoreilla
- muista myös oletuskonstruktorien käyttö - lisäksi joissakin kielissä konstruktoritoteutuksia luodaan aliluokkiin automaattisesti
- esim. c++ vs object pascal, ks. delphi-pikakurssi
- [ http://www.mit.jyu.fi/~vesal/kurssit/winohj/html/delphi/m26.htm ]
- abstraktit ja rajapintaluokat
- abstrakti luokka == luokka, joka sisältää vähintään yhden pure virtual -metodin
- rajapinta == täysin abstrakti luokka, sisältää vain julkisten metodien määrityksiä ilman toteutusta
- perintä voidaan (mutta ei välttämättä kannata) korvata koostamisella ja rajapinnoilla
- Esim. omaa säiliöluokkaa tehdessä sisäinen toteutus saatetaan koostaa jostain Javan säiliöluokasta - perintää käyttämällä rajapinnasta saattaisi tulla sotkuinen, koska perityssä luokassa näkyvät kaikki alkuperäisen säiliöluokan julkiset metodit
- c++:n private- ja protected-perintä on toteutuksen kannalta lähellä koostamista (ehdolla, että luokassa on vain yksi "koostettava": yliluokka)
- koostaminen vaatii perintää enemmän koodia, koska täytyy kirjoittaa koostetun luokan metodeja kutsuvia "delegointimetodeja" koostavaan luokkaan
- rajapintojen käyttäminen johtaa laajassa luokkahierarkiassa helposti malliin, jossa lähes kaikki luokat toteuttavat useita rajapintoja - tällöin ongelma muuttuu luokkien suunnittelusta rajapintojen suunnitteluksi
- moniperintä ja rajapinnat
- moniperinnästä ks. oo-moniste
- [ http://www.mit.jyu.fi/vesal/kurssit/winohj/html/cpp/m65.htm ]
- käyttökohteita
- rajapintojen yhdistäminen
- luokkien (toteutuksen) yhdistäminen
- koostaminen valmiista ominaisuuskokoelmista (mixin)
- Rajapinnoilla perintä on yksinkertaista, koska yliluokilla ei ole attribuutteja
- Jos yliluokilla on attribuutteja, mutta ei yhteistä kantaluokkaa (eikä samannimisiä metodeja), perintä on melko helppoa hahmottaa (erotteleva moniperintä)
- jos samannimisiä (moniselitteisiä) metodeja, aliluokassa on yksilöitävä ::-operaattorilla, mitä kutsutaan
- aliluokka on samalla myös jokaisen yliluokkansa instanssi ja sisältää yliluokkiensa attribuutit
- Jos kantaluokilla on yhteinen yliluokka, vaaditaan lisämäärittelyjä
- ks. oo-moniste
- [ http://www.mit.jyu.fi/vesal/kurssit/winohj/html/cpp/m69.htm ]
- oletuksena aliluokkaan tulee useita kopioita yhteisen yliluokan attribuuteista (toistuva moniperiytyminen)
- tämä voi olla sovellusalueesta riippuen järkevää tai (yleensä) ei
- esim. oo-monisteen "ympyräneliö" sisältäisi koordinaatit erikseen sekä ympyrälle että neliölle!
- kopioituminen voidaan estää käyttämällä "virtuaalista" (yhdistävää) perintää - tällöin varmistetaan, että moniperittävä (yli)luokka sisällytetään vain yhden kerran
- yhteisen kantaluokan konstruktoria kutsuttava suoraan alaluokasta
- periytyminen vai kooste?
- HUOM! Mietittäessä, pitäisikö perintää käyttää, tulee muistaa ns. korvausperiaate: aliluokan olion tulee aina olla "korvattavissa" yliluokan oliolla