Olio-ohjelmointi Periytyminen ja monimuotoisuus. 1. Periytyminen

Koko: px
Aloita esitys sivulta:

Download "Olio-ohjelmointi Periytyminen ja monimuotoisuus. 1. Periytyminen"

Transkriptio

1 Olio-ohjelmointi Periytyminen ja monimuotoisuus Edellisessä osassa tarkasteltiin olio-ohjelmoinnin ensimmäistä perusominaisuutta: sitä, että luokat muodostavat kapseloinnin ja tiedon kätkennän toteuttavia tietotyyppejä. Kun tähän lisätään vielä periytyminen ja monimuotoisuus, päästään täysipainoiseen olio-ohjelmointiin. Periytymistä ja monimuotoisuutta C++-kielessä käsitellään esimerkiksi kirjan [Eck] luvuissa 14 ja 15 sekä kirjan [Hie] luvuissa Periytyminen Periytyminen tarkoittaa luokan ominaisuuksien sisällyttämistä uuteen luokkaan. Perittävää luokkaa nimitetään kantaluokaksi tai yliluokaksi, perivää luokkaa nimitetään aliluokaksi. Ensin tässä käsitellään periytymistä yleisesti kirjan [Bud] (luku 8) pohjalta ja sitten esitetään, miten C++-kielessä toteutetaan periytyminen. Oliosuunnittelussa voidaan käyttää ns. is-a -testiä yleissääntönä kuvaamaan, onko kahden luokan välillä periytyvyyssuhde. Mikäli luokan A oliot ovat erikoistapauksia luokan B olioista ( an A is a B ), luokka A voi periä luokan B. Esimerkiksi kala on eläin ja ahven on kala, joten kalaa kuvaava luokka voisi periä eläintä kuvaavan luokan ja ahventa kuvaava luokka voisi periä kalaa kuvaavan luokan. Sen sijaan kalaa ja evää kuvaavien luokkien välillä ei ole vastaavaa suhdetta, joten kala-luokan ei ole syytä periä evä-luokkaa, vaikka joskus näkeekin tämän tyyppistä ohjelmointia; se edustaa kuitenkin epäonnistunutta suunnittelua. Luontevampaa onkin määritellä tällaisessa tapauksessa luokkien välillä koostumussuhde: kala-luokka voi sisältää eväolion osaolionaan. Periytyminen on vahva mekanismi, jolla saavutetaan monia hyötyjä. Ehkä tärkein periytymisen etu on uudelleenkäyttö: Kun jo valmis ja testattu luokka peritään, saadaan usein merkittävä osa ohjelmaa valmiina ja vältetään koodin uudelleen kirjoittaminen. Koodin luotettavuuskin paranee. Periytyminen mahdollistaa uudelleen käytettävien ohjelmistokomponenttien laatimisen. Koska aliluokka perii (tavallisessa periytymisen muodossa) kantaluokan julkisen rajapinnan, periytymisen avulla voidaan taata, että rajapinnat samankaltaisiin olioihin ovat samanlaiset. Periytyminen sallii myös olio-ohjelmoinnissa ilmenevän erittäin tärkeän tyypin monimuotoisuudesta, jota käsitellään kappaleessa 2. Olioiden ja periytymisen sisällyttäminen ohjelmaan tuo luonnollisesti myös mukanaan varjopuolia. Oliotekniikoilla rakennettu ohjelma on yleensä hieman tehottomampi kuin puhtaasti proseduraalinen ohjelma. Tosin ero on useimmiten jokseenkin merkityksetön, jos ohjelma on asianmukaisesti suunniteltu ja toteutettu. Olio-ohjelma on myös yleensä kooltaan hieman suurempi; tälläkään ei ole tavallisesti olennaista merkitystä. Monimutkaisen luokkarakenteen liittäminen ohjelmaan voi kuitenkin lisätä merkittävästi ohjelman loogista kompleksisuutta ja siten tehdä siitä vaikeasti hallittavan. Tästä syystä kannattaa välttää erityisesti periytymisen liikakäyttöä Julkinen periytyminen C++:ssa Periytymistä ei ole toteutettu kaikissa oliokielissä samalla tavoin. Esimerkiksi Java-kielessä periytymisen malli on varsin yksinkertainen: Kaikkien luokkien yhteinen kantaluokka on Javan Object-luokka ja jokainen muu luokka perii täsmälleen yhden luokan. Periytymisen mekanismi on aina sama. C++-kielessä sen sijaan luokalla ei välttämättä ole lainkaan kantaluokkaa, ja 1

2 periytyminen voi tapahtua kolmella mekanismilla (julkinen, suojattu ja yksityinen). Lisäksi luokka voi periä useamman kuin yhden luokan. Ylivoimaisesti yleisimmin käytetty periytymisen muoto on yhden luokan julkinen periminen. Tätä tapaa käsitellään seuraavaksi ja muut tapaukset jätetään lyhyelle maininnalle. Julkista periytymistä tulee käyttää, kun perivää tyyppiä voidaan käyttää aina samassa yhteydessä kuin kantaluokkaa. Tällöin sanotaan että aliluokka on kantaluokan alityyppi. Tässä tapauksessa aliluokka perii kantaluokaltaan sekä liittymän että toteutustavan ja periytyminen näkyy luokkahierarkiasta ulospäin. Tämä on Java-kielessä ainoa mahdollinen periytymisen muoto. Ohjelmakoodissa julkinen periytyminen merkitään seuraavasti: class Ali: public Kanta // Ali-luokan attribuutit ja metodit ; Edellä Ali-luokka perii siis Kanta-luokan. Huomaa, että aliluokka perii kaikki kantaluokan attribuutit riippumatta niiden näkyvyysmääreistä; aliluokan olio sisältää osanaan ilmentymän kantaluokasta. Seuraavat kaaviot hahmottavat tilannetta. ColoredPoint-luokka perii Point-luokan. ColoredPoint-olio sisältää ilmentymän Point-luokasta. Edellä olevassa kaaviossa ColoredPoint perii Point-luokan. Näin ollen ColoredPoint-luokan oliot sisältävät myös Point-luokan jäsenmuuttujat x_coord ja y_coord. Julkisessa periytymisessä (eikä missään muussakaan periytymisen muodossa) kantaluokan yksityiset (private-tyyppiset) jäsenet eivät kuitenkaan näy aliluokassa, joten niitä ei voi suoraan aliluokassa käyttääkään. Näin ollen muuttujia x_coord ja y_coord ei voi suoraan käyttää ColoredPoint-luokassa. Mikäli aliluokan on käytettävä kantaluokan yksityisiä attribuutteja, kantaluokkaan on tehtävä sopivat julkiset tai suojatut metodit, jotka palauttavat tai asettavat attribuuttien arvot. Kantaluokan suojatut (protected-tyyppiset) ja julkiset (public-tyyppiset) jäsenet näkyvät aliluokissa, joten ne ovat suoraan käsiteltävissä, kun luokka peritään. Jäsenten näkyvyys ei myöskään muutu julkisessa periytymisessä, joten esimerkiksi suojatut jäsenet näkyvät läpi koko luokkahierarkian. 2

3 Edellä esiintynyt luokka ColoredPoint perii myös Point-luokan metodit print ja move. Koska move on julkinen metodi, sitä voidaan kutsua myös ColoredPoint-olion kautta. Point-luokan print-metodi toteutetaan uudelleen ColoredPoint-luokassa, joten ColoredPoint-olion kautta kutsuttaessa suoritettaisiin uudelleen toteutettu print. Metodi changecolor on olemassa ainoastaan luokassa ColoredPoint, joten tätä metodia ei luonnollisestikaan voisi kutsua Pointluokan olion kautta. Kun aliluokan olio luodaan, ensimmäiseksi kutsutaan jotakin kantaluokan muodostinta, ts. olio rakennetaan kantaluokasta lähtien. Kantaluokan muodostimen kutsu voi olla ohjelmoijan tekemä, jolloin sen täytyy sijoittua aliluokan muodostimen alustuslistaan. Ellei ohjelmoija tee kantaluokan muodostimen kutsua itse, kutsutaan automaattisesti kantaluokan oletusmuodostinta. Hajottimien kutsujärjestys on päinvastainen kuin muodostimien: olio tuhotaan aliluokasta kantaluokkaa kohti, ts. ensin kutsutaan aliluokan hajotinta ja sitten kantaluokan hajotinta. Esimerkiksi seuraava ohjelma #include <iostream> using namespace std; class Kanta Kanta() cout << "Kanta-luokan oletusmuodostin" << endl; Kanta(int i) cout << "Kanta-luokan kokonaislukumuodostin" << endl; ~Kanta() cout << "Kanta-luokan hajotin" << endl; ; class Ali : public Kanta Ali() cout << "Ali-luokan oletusmuodostin" << endl; Ali(int i) : Kanta(i) cout << "Ali-luokan kokonaislukumuodostin" << endl; ~Ali() cout << "Ali-luokan hajotin" << endl; ; int main() tulostaa Ali a; return 0; Ali a(10); 3

4 Kanta-luokan oletusmuodostin Ali-luokan oletusmuodostin Ali-luokan hajotin Kanta-luokan hajotin Kanta-luokan kokonaislukumuodostin Ali-luokan kokonaislukumuodostin Ali-luokan hajotin Kanta-luokan hajotin koska ensin luodaan Ali-luokan olio käyttämällä sen oletusmuodostinta, joka kutsuu ensiksi automaattisesti Kanta-luokan oletusmuodostinta. Tämän jälkeen luotu olio tuhotaan: ensin kutsutaan Ali-luokan hajotinta ja sitten Kanta-luokan hajotinta. Seuraavaksi luodaan Ali-luokan olio käyttämällä muodostinta, joka ottaa parametrikseen kokonaisluvun. Tämä muodostin kutsuu alustuslistassaan Kanta-luokan kokonaislukumuodostinta, minkä jälkeen suoritetaan Ali-luokan muodostin. Lopuksi luotu olio tuhotaan jo tuttuun tapaan. HUOM! Edellisessä esimerkkiohjelmassa luokat on kirjoitettu pääohjelmatiedostoon esitysteknisistä syistä. Normaalisti luokka määritellään omassa otsikkotiedostossaan Muut periytymisen muodot C++:ssa Edellisessä kappaleessa käsiteltiin yksinkertaista julkista periytymistä. C++:ssa on myös mahdollista käyttää suojattua ja yksityistä periytymistä sekä moniperiytymistä. Näitä käsitellään lyhyesti tässä. Päivi Hietasen kirjan [Hie] luvuissa 27 ja 28 perehdytään mainittuihin periytymisen muotoihin. Toteutustavan periytyminen Jos kantaluokka peritään tavallista, julkista periytymistä käyttäen aliluokkaan, kantaluokan julkinen rajapinta on näkyvissä aliluokan olioiden käyttäjille. Tämä onkin useimmiten tarkoituksenmukaista. Joskus kuitenkin halutaan aliluokassa peittää kantaluokan julkinen rajapinta ja periä ainoastaan kantaluokan toteutus. Sama tietorakenne voidaan esimerkiksi toteuttaa monen eri tallennusrakenteen päälle. Tietorakenteen käyttäjien ei kuitenkaan yleensä ole aiheellista päästä käyttämään tallennusrakenteen palveluja. Tällaisissa tapauksissa voidaan käyttää yksityistä tai suojattua periytymistä. Näitä periytymisen muotoja nimitetään toteutustavan periytymiseksi (implementation inheritance). Yksityisessä periytymisessä kantaluokan kaikkien jäsenten näkyvyys muuttuu privatetyyppiseksi. Näin ollen ne eivät näy edes aliluokasta perittävissä luokissa. Suojatussa periytymisessä kantaluokan protected- ja public-jäsenet ovat näkyvyydeltään protected-tyyppisiä, joten ne eivät näy luokkahierarkiasta ulospäin, mutta ovat näkyvissä luokkahierarkian sisällä. Yksityinen periytyminen toteutetaan C++:ssa muuttamalla luokkaa perittäessä avainsana public avainsanaksi private; suojattu periytyminen taas käyttämällä avainsanaa protected. Ellei periytymisessä anneta lainkaan näkyvyysmäärettä, oletetaan periytymisen olevan privatetyyppistä. HUOM! Tällä kurssilla laadittavissa ohjelmissa periytyminen on aina julkista eikä toteutustavan periytymiseen enää palata. 4

5 Moniperiytyminen C++:ssa luokka voi periä useamman kuin yhden kantaluokan. Kantaluokat merkitään pilkulla erotettuna seuraavasti class Ali: public EkaKanta, public TokaKanta // jne Normaalitapauksessa C++-kielessä moniperiytyminen on erottelevaa moniperiytymistä. Tämä konkretisoituu, kun luokka perii saman kantaluokan kahta eri kautta esimerkiksi seuraavasti: class Kanta // JNE class EkaSolmu: public Kanta // JNE class TokaSolmu: public Kanta // JNE class Ali: public EkaSolmu, public TokaSolmu // JNE Nyt luokka Ali perii luokan Kanta sekä luokan EkaSolmu että luokan TokaSolmu kautta. Tällöin Ali-luokan oliolla on kaksi eri ilmentymää Kanta-luokassa esitellyistä tiedoista. Tämä voi joskus aiheuttaa ongelmia. Tilanteen muuttamiseksi C++:ssa voidaan käyttää ns. yhdistävää eli virtuaalista moniperiytymistä seuraavaan tapaan: class Kanta // JNE class EkaSolmu: public virtual Kanta // JNE class TokaSolmu: public virtual Kanta // JNE class Ali: public EkaSolmu, public TokaSolmu // JNE Nyt luokat EkaSolmu ja TokaSolmu perivät Kanta-luokan virtuaalisesti, jolloin luokat perivään Ali-luokkaan tulee vain yksi ilmentymä Kanta-luokasta. Moniperiytyminen on monessa tilanteessa kätevä ominaisuus, mutta sitä kannattaa käyttää harkiten. Tällä kurssilla moniperiytymistä harrastetaan ainoastaan rajapintaperiytymisenä. Tämä tarkoittaa sitä, että luokan periessä useamman eri luokan, yhtä lukuun ottamatta perittävät luokat ovat rajapintoja, ts. niiden kaikki metodit ovat puhtaita virtuaalimetodeja. Tällaisiin metodeihin tutustutaan tämän dokumentin kohdassa 2.2 Uudelleenmäärittely. 2. Monimuotoisuus Monimuotoisuus (polymorfismi) tarkoittaa löyhästi sanottuna sitä, että tilanteesta riippuen oliot voivat reagoida samaan viestiin eri lailla. Termiä käytetään eri yhteyksissä eri tavoin, joten termi itsekin on tavallaan polymorfinen. Nimenomaan monimuotoisuus erottaa olio-ohjelmoinnin selvimmin muista ohjelmointiparadigmoista. Olio-ohjelmoinnissa monimuotoisuus ilmenee neljällä eri tavalla: metodien (funktioiden) ylikuormittamisena, metodien uudelleen määrittelemisenä, muuttujien monimuotoisuutena ja geneerisyytenä. Kaikki nämä ilmenemismuodot edistävät omalla tavallaan koodin uudelleenkäyttöä. Seuraavassa käsitellään kolmea ensimmäistä ilmenemismuotoa, geneerisyys jätetään myöhemmäksi. Esitettävät asiat sisältyvät pääosin teoksen [Bud] lukuihin

6 2.1. Ylikuormittaminen Ylikuormittamisessa metodin nimi on monimuotoinen, toisin sanoen samannimisellä metodilla (tai yleisemmin funktiolla) on useita eri toteutuksia, joista kutsuttaessa valitaan tilanteeseen sopiva. Tyypillisesti tämä tapahtuu siten, että eri toteutuksien parametrilistat ovat erilaiset ja kutsuttaessa metodia päätellään syöteparametrien määrästä ja tyypeistä, mikä toteutus valitaan. Valinta voidaan tehdä staattisesti eli käännösaikana, koska kaikki tarvittava informaatio kutsun sitomiseksi on jo silloin saatavana. Huomaa, että ylikuormittaminen ei edellytä oliomaisuutta; monessa ohjelmointikielessä ylikuormittaminen on mahdollista, vaikka oliotukea ei olisikaan. Hyvin usein luokan olioita voidaan luoda eri parametriyhdistelmien perusteella; tällöin on tavallista ylikuormittaa luokan muodostin. Monesti tarvitaan esimerkiksi oletusmuodostin, ts. muodostin, jota voidaan kutsua ilman parametreja ja joka luo olion joillakin oletusarvoilla. Esimerkiksi Java-kielen merkkijonoa mallintavalla String-luokalla on mm. seuraavat konstruktorit: String() Initializes a newly created String object so that it represents na empty character sequence. String(char[] value) Allocates a new String so that it represents the sequence of characters currently contained in the character array argument. String(String original) Initializes a newly created String object so that it represents the same sequence of characters as the argument; in other words, the newly created string is a copy of the argument string. Näin ollen uusi String-olio voidaan luoda Java-ohjelmassa esimerkiksi seuraavilla tavoilla: String s = new String(); // s = char merkit[] = h, e, i ; String t = new String(merkit); // t = hei String u = new String(t); // u = hei Oletetaan, että C++-kielellä on kirjoitettu luokka, joka mallintaa tason pisteitä. Kahden pisteen yhteenlasku on luonnollista toteuttaa laskemalla pisteiden x- ja y-koordinaatit yhteen, jolloin tulokseksi saadaan uusi piste. Luettavuuden ja yhtenäisyyden kannalta voisi olla toivottavaa käyttää +-operaattoria esimerkiksi seuraavaan tapaan: Piste p(2,3); Piste q (4,5); Piste r = p+q; // r = (6,8); Automaattisesti tämä ei kuitenkaan toimi, sillä itse laaditun luokan olioihin ei voi soveltaa +- operaattoria, ellei ohjelmoija itse ylikuormita operaattoria sopivasti ottamaan parametreinaan ko. luokan olioita. Jos operaattoria ei ylikuormiteta, pitäisi luokkaan kirjoittaa oma metodi pisteiden yhteenlaskua varten. Tämä saattaa kuitenkin heikentää ohjelmakoodin intuitiivista ymmärtämistä, joten operaattorin toteuttaminen on perusteltua. C++-kielessä voidaankin lähes mikä tahansa operaattori ylikuormittaa, koska operaattorit on toteutettu funktioina, joiden ylikuormittaminen on sallittua. 6

7 Esimerkiksi Piste-luokkaan voitaisiin lisätä operaattori += ja ylikuormittaa operaattori + seuraavasti: class Piste private: double x_coord; double y_coord; ; Piste(double x,double y); Piste(const Piste& p); ~Piste(); Piste& operator+=(const Piste &p); Piste operator+(const Piste& p1,const Piste& p2); Operaattorit voitaisiin toteuttaa seuraavaan tapaan: Piste::Piste(double x,double y):x_coord(x),y_coord(y) Piste::Piste(const Piste& p) x_coord = p.x_coord; y_coord = p.y_coord; Piste::~Piste() Piste& Piste::operator+=(const Piste &p) x_coord = x_coord+p.x_coord; y_coord = y_coord+p.y_coord; return *this; Piste operator+(const Piste& p1,const Piste& p2) Piste p(p1); p += p2; return p; Nyt ohjelmassa esiintyvä koodi Piste p1(2.1,3.2); Piste p2(0.5,1.1); Piste p3 = p1+p2; toimisi asianmukaisesti. Kaikilla olio-ohjelmointikielillä vastaavaa ominaisuutta ei voi toteuttaa; esimerkiksi Javalla tämä ei onnistu, sillä Javassa ei ole mahdollista kuormittaa operaattoreita. Javassa tulisi siis toteuttaa luokkaan oma metodi pisteiden yhteenlaskuun. Ylikuormitus voi perustua myös näkyvyysalueisiin. Koska luokka muodostaa oman näkyvyysalueensa, kahdessa eri luokassa voi olla täsmälleen samanniminen metodi samoin parametrein, eikä hämmennystä aiheudu. Tällöin ei myöskään välttämättä oleteta, että metodeilla olisi semanttista yhteyttä. 7

8 Seuraavassa kappaleessa käsitellään metodien uudelleen määrittelyllä aikaan saatavaa monimuotoisuutta Uudelleenmäärittely Aliluokan metodin sanotaan uudelleenmäärittelevän (override) sen yliluokan metodin, mikäli aliluokassa on toteutettu metodi, jolla on täsmälleen sama parametrilista ja paluuarvo kuin yliluokan metodilla. Sanotaan myös että aliluokan metodi korvaa yliluokan metodin. Tällöin kutsuttaessa aliluokan olion metodia yliluokan toteutus peittyy, ja käytetään aliluokassa määriteltyä toteutusta. Uudelleenmääritellyn metodin näkyvyyden muuttamisen säännöt ovat kielikohtaisia, esimerkiksi Javassa yliluokan public-tyyppistä metodia ei voi aliluokassa uudelleen määritellä private-tyyppiseksi. Sen sijaan C++-kielessä näin voi tehdä. Yleensä uudelleenmääriteltyjen metodien näkyvyyttä ei ole syytä muutella. Jos metodin kutsu sidotaan staattisesti käännösaikana, ei voida uudelleenmäärittelyn yhteydessä vielä puhua monimuotoisuudesta. Uudelleenmäärittelystä tuleekin vasta todella hyödyllinen, kun käytetään hyväksi kahta ominaisuutta: 1. Metodin kutsu sidotaan dynaamisesti ajon aikana 2. Aliluokan oliota voidaan käsitellä yliluokan oliona Jälkimmäistä ominaisuutta sanotaan alityyppiperiaatteeksi: Aliluokan olio voi esiintyä kaikissa yhteyksissä, joissa yliluokan olio esiintyy. Tämä periaate tunnetaan myös nimellä Liskov substitution principle, koska Barbara Liskov ja John Guttag käsittelivät periaatteen ideaa vuonna 1986 teoksessaan Abstraction and Specification in Program Development. Java-kielen aliluokat ovat aina yliluokkansa alityyppejä. C++-kielessä näin ei välttämättä ole, koska siinä voidaan käyttää erilaisia perinnän muotoja, jotka rikkovat alityyppiperiaatteen. Käytettäessä julkista yksinkertaista periytymistä myös C++-kielessä on alityyppiperiaate voimassa. Alityyppiperiaate aiheuttaa uudelleenmäärittelyyn semanttisen ongelman: Aliluokka voi määritellä yliluokan metodin uudelleen miten tahansa. Mikään ei takaa, että uudelleenmääritelty metodi muistuttaisi toiminnaltaan alkuperäistä, vaan se jää ohjelmoijan vastuulle. Dynaamisesti sidottavaa metodia sanotaan virtuaalioperaatioksi. Javassa kaikki metodit ovat virtuaalioperaatioita, sen sijaan C++-kielessä ohjelmoijan on erikseen määriteltävä halutut luokan metodit virtuaalisiksi, muuten ne sidotaan staattisesti. Mikäli virtuaalioperaatiolla on toteutus sekä yli- että aliluokassa, sanotaan operaatiota kiinnitetyksi. Tällöin yliluokassa toteutettu metodi on oletusoperaatio, joka voidaan syrjäyttää aliluokissa. Mikäli yliluokassa operaatio on esitelty, mutta sillä ei ole toteutusta, kyseessä on avoin virtuaalioperaatio eli abstrakti metodi. C++:ssa abstrakti metodi määritellään syntaktisesti hieman oudolla tavalla kirjoittamalla metodin esittelyn perään sijoitus =0. Esimerkiksi dokumentin lopussa olevassa esimerkissä esiintyvän Esine-luokan kaikki metodit ovat abstrakteja. On selvää, että tällaisesta luokasta ei voi luoda olioita, koska sillä olisi metodi, jota ei voi kutsua. Tällaista luokkaa sanotaan abstraktiksi luokaksi. Staattisesti tyypitetyissä kielissä abstrakteilla metodeilla on tärkeä asema, koska niiden avulla luokkahierarkian kantaluokkaan voi liittää metodeja, joiden toteuttaminen pakotetaan kaikissa hierarkian ei-abstrakteissa luokissa. Joissakin kielissä (esimerkiksi Javassa) luokan voi pakottaa abstraktiksi jollakin avainsanalla. C++-kielessä näin ei ole, vaan luokasta tulee abstrakti täsmälleen silloin, kun se sisältää vähintään yhden abstraktin metodin. 8

9 Uudelleenmäärittely voidaan ohjelmointikielissä toteuttaa periaatteessa kahdella tavalla: korvaamalla (replacement) tai tarkentamalla (refinement). Korvaamista kutsutaan joskus amerikkalaiseksi semantiikaksi. Siinä aliluokan metodi korvaa yliluokan metodin siten, että ainoastaan aliluokan metodi suoritetaan. Useimmissa nykyisissä ohjelmointikielissä käytetään kumpaakin muotoa, mutta enimmäkseen korvaamista. Tarkentaminen tunnetaan myös skandinaavisen semantiikan nimellä. Tarkentamismenetelmässä suoritetaan ensin yliluokan metodi ja sitten aliluokan metodi. Yleisesti käytettävissä kielissä tarkentamista käytetään vain muodostimissa automaattisesti, esimerkiksi sekä Javassa että C++:ssa oliota luotaessa kutsutaan aina jotakin sen yliluokan muodostinta. Muita metodeja suoritettaessa tarkentaminen voidaan saada aikaan kutsumalla erikseen yliluokan metodia. Kuten edellä mainittiin, C++-kielessä metodin dynaamista sidontaa ei tehdä automaattisesti vaan ainoastaan erikseen kantaluokassa virtual-määreellä esitellyille metodeille. Kun kantaluokassa metodi on määritelty virtuaaliseksi, se on dynaamisesti sidottava läpi koko luokkahierarkian, ominaisuutta ei voi poistaa periytymisessä. Milloin ohjelmakoodissa oleva metodikutsu voi johtaa siihen, että se sidotaan eri toteutuksiin? C++:ssa olio voi esiintyä normaalina muuttujana tai siihen osoittava muuttuja voi olla viite- tai osoitintyyppinen. Jos olio on normaali muuttuja, metodikutsu sidotaan aina ko. olion luokkaan, sen sijaan viite- tai osoitintyyppinen muuttuja voi olla kantaluokan tyyppinen, mutta osoittaa johonkin aliluokan olioon. Tällöin metodikutsu voi sitoutua eri toteutuksiin, jos metodi on määritelty virtual-tyyppiseksi. Tarkastellaan alla olevaa esimerkkiohjelmaa: #include <iostream> using namespace std; class Kanta virtual void dynamet(); void statmet(); virtual ~Kanta() ; void Kanta::dynaMet() cout << "Kanta dynamet() kutsuttu " << endl; void Kanta::statMet() cout << "Kanta statmet() kutsuttu " << endl; class Lapsi : public Kanta void dynamet(); void statmet(); ~Lapsi() ; void Lapsi::dynaMet() cout << "Lapsi dynamet() kutsuttu " << endl; void Lapsi::statMet() cout << "Lapsi statmet() kutsuttu " << endl; 9

10 int main() Kanta* ptr = new Lapsi(); ptr->dynamet(); ptr->statmet(); delete ptr; ; return 0; Kanta-luokan metodi dynamet on määritelty virtuaaliseksi, kun taas statmet ei. Pääohjelmassa Kanta-luokan tyyppinen osoitin osoittaa Lapsi-luokan olioon; osoittimen kautta kutsutaan kumpaakin yllämainittua metodia. Koska dynamet on virtuaalisena dynaamisesti sidottava, sen toteutus haetaan Lapsi-luokasta. Sen sijaan statmet on staattisesti sidottava ja sen kutsu sidotaan jo käännösaikana Kanta-luokan metodiin. Näin ollen ohjelma tulostaa Lapsi dynamet() kutsuttu Kanta statmet() kutsuttu Metodin uudelleenmäärittelyllä aikaan saatava monimuotoisuus toteutetaan siis C++:ssa käyttämällä virtual-tyyppisiä metodeja ja osoittimia tai viitteitä olioihin. Luokkahierarkian kantaluokassa on syytä määritellä ainakin hajotin virtuaaliseksi, muussa tapauksessa ajaudutaan helposti resurssivuotoihin. Lisätään edelliseen esimerkkiohjelmaan luokkien hajottimiin tulostuskomennot seuraavasti: class Kanta virtual void dynamet(); void statmet(); virtual ~Kanta() cout << Kanta-luokan hajotin << endl; ; class Lapsi : public Kanta void dynamet(); void statmet(); ~Lapsi() cout << Lapsi-luokan hajotin << endl; ; Tällöin ohjelma tulostaa Lapsi dynamet() kutsuttu Kanta statmet() kutsuttu Lapsi-luokan hajotin Kanta-luokan hajotin Toisin sanoen oliota tuhottaessa kutsutaan ensin aliluokan ja sitten kantaluokan hajotinta, niin kuin asiaan kuuluukin. Jos kuitenkin poistetaan virtual-määre Kanta-luokan hajottimesta: 10

11 class Kanta virtual void dynamet(); void statmet(); ~Kanta() cout << Kanta-luokan hajotin << endl; ; niin tulostuu Lapsi dynamet() kutsuttu Kanta statmet() kutsuttu Kanta-luokan hajotin Nyt hajotin on staattisesti sidottava ja koska pääohjelmassa delete-operaatio kohdistetaan Kantaluokan osoittimeen (vaikka osoitin osoittaakin Lapsi-luokan olioon), kutsutaan ainoastaan Kantaluokan hajotinta. Mikäli Lapsi-luokan hajottimessa tehtäisiin tärkeitä resurssin vapauttamisia, ne jätettäisiin tässä tapauksessa suorittamatta. Kirjoita siis aina luokkaan virtuaalinen hajotin, jos on mahdollista, että luokka peritään! Joissakin tilanteissa voi olla tarpeellista estää metodin uudelleenmäärittely. Kaikissa kielissä se ei ole mahdollista, mutta esimerkiksi Javassa se onnistuu määrittelemällä luokan metodi finaltyyppiseksi. Tällöin sitä ei voi aliluokissa uudelleen määritellä. Menetelmällä saavutetaan ainakin se etu, että tällöin metodin kutsu voidaan sitoa staattisesti, jolloin suorituskyky paranee. C++-kielessä uudelleenmäärittelyä ei voi estää, mutta jättämällä kantaluokassa metodi määrittelemättä virtuaaliseksi varmistetaan, että metodi sidotaan aina staattisesti. Yleensä uudelleenmäärittelyssä aliluokan metodin tyypin oltava täsmälleen sama kuin aliluokan, ts. sekä paluuarvon että parametrilistan muuttujien tyyppien on oltava täsmälleen samat. Oletetaan esimerkiksi, että luokkaan nimeltä Kanta on toteutettu metodi vertaa, joka ottaa kantaluokan tyyppisen viiteparametrin. Luokka peritään Kovar-nimiseen luokkaan, jossa yritetään uudelleen määritellä vertailumetodi. Kovar-luokan metodin parametrin tulisi olla Kovar-tyyppinen, koska yleensä yhtäsuuruutta voi vertailla vain kahden saman luokan olion välillä. Onnistuuko tällainen uudelleenmäärittely? Kuvatun kaltaista tilannetta, jossa parametrin tyyppi muuttuu samaan suuntaan luokkahierarkian kanssa, sanotaan kovarianssiksi (covariant change). Testataan asiaa yksinkertaisella ohjelmalla: 11

12 #include <iostream> class Kanta virtual bool vertaa(kanta &k) std::cout << "Vertaillaan kahta Kantaluokan oliota" << std::endl; return true; ; class Kovar: public Kanta Kovar(double d):dup(d) bool vertaa(kovar &k) std::cout << "Vertaillaan kahta Kovarluokan oliota" << std::endl; return dup == k.dup; private: double dup; ; int main(int argv, char** args) Kovar *k1 = new Kovar(1.1); Kanta *k2 = new Kovar(1.5); if (k2->vertaa(*k1)) std::cout << "TOTTA!" << std::endl; else std::cout << "SE OLI VALHETTA VAIN!" << std::endl; delete k1; delete k2; return 0; Mikäli luokan Kovar metodi vertaa korvaisi Kanta-luokan metodin vertaa, kutsuttaisiin ohjelmassa luokan Kovar metodia. Ohjelmaa suoritettaessa huomataan kuitenkin sen tulostuksesta, että siinä kutsutaan metodia vertaa Kanta-luokasta, joten metodia ei ole uudelleenmääritelty vaan metodit tulkitaan kahdeksi eri metodiksi. Yleensä kovarianssi ei olekaan mahdollinen metodin parametrien suhteen. Sen sijaan paluuarvon suhteen kovarianssi on semanttisesti mahdollista toteuttaa. C++:ssakin ominaisuus on sallittu. 12

13 Esimerkki: #include <iostream> class Yli virtual void nimi() std::cout << "Mahtava Yliluokan olio" << std::endl; ; class Ali: public Yli void nimi() std::cout << "Kurja Aliluokan olio" << std::endl; ; class Kovar virtual Yli* teeolio() return new Yli(); ; class KovarAli: public Kovar Ali* teeolio() return new Ali(); ; int main(int argv, char** args) Kovar *k1 = new Kovar(); Kovar *k2 = new KovarAli(); Yli *y = k1->teeolio(); y->nimi(); Yli *yy = k2->teeolio(); yy->nimi(); delete y; delete yy; delete k1; delete k2; return 0; Ohjelma voidaan kääntää ja suorittaa. Ohjelman tulostuksesta huomataan, että osoitin y osoittaa luokan Yli olioon ja osoitin yy luokan Ali olioon. Näin ollen metodi teeolio määritellään uudelleen luokassa KovarAli. Tällainen uudelleenmäärittely on kuitenkin sallittu vain jos korvaavan metodin paluuarvo on korvattavan metodin paluuarvon alityyppi. Jos luokka Ali ei periytyisi luokasta Yli, ohjelma ei kääntyisi. Samoin, jos hierarkia oli toisinpäin, ts. jos luokka Yli perisi luokan Ali, uudelleenmäärittely luokissa Kovar ja KovarAli ei olisi sallittua. 13

14 Mikäli parametrit muuttuvat luokkahierarkiassa päinvastaiseen suuntaan kuin luokkahierarkia, tilannetta sanotaan kontravarianssiksi (contravariant change). Tällöin siis aliluokan metodin parametrit ovatkin yleisempää tyyppiä kuin vastaavan metodin sen yliluokassa. Yllä olevasta esimerkistä kävi jo ilmi, että kontravarianssi ei ole yleensä sallittua metodien paluuarvoissa. Sen sijaan parametreissa kontravarianssi ei aiheuta kääntäjälle ongelmaa. Esimerkiksi edellinen ohjelma voitaisiin muokata seuraavanlaiseksi (luokat Yli ja Ali kuten ennenkin): class Kontravar virtual void tulostanimi(ali &a) std::cout << "Kontravar-luokan metodi" << std::endl; a.nimi(); ; class KontravarAli: public Kontravar void tulostanimi(yli &y) std::cout << "KontravarAli-luokan metodi" << std::endl; y.nimi(); ; int main(int argv, char** args) KontravarAli *k = new KontravarAli(); Ali a; Yli y; k->tulostanimi(a); k->tulostanimi(y); delete k; return 0; Ohjelma voidaan kääntää ja suorittaa ja tulostuksesta huomataan, että ohjelma kutsuu luokan KontravarAli metodia myös, kun parametri on Ali-luokan tyyppinen. Kuitenkaan metodi tulostanimi ei ole uudelleenmääritelty aliluokassa, vaan itse asiassa ylikuormitettu. Tämän havaitsee muuttamalla pääohjelman muotoon int main(int argv, char** args) Kontravar *k = new KontravarAli(); Ali a; k->tulostanimi(a); delete k; return 0; Mikäli metodi tulostanimi olisi uudelleenmääritelty, sitä kutsuttaisiin luokasta KontravarAli. Tulostuksesta huomataan kuitenkin, että metodia kutsutaan luokasta Kontravar, joten metodia ei ole uudelleenmääritelty. Joissakin kielissä kontravarianssi parametreissa on 14

15 eräissä tilanteissa mahdollinen (tällainen kieli on esimerkiksi Eiffel), edellisen testin perusteella ei kuitenkaan C++:ssa Monimuotoiset muuttujat Dynaamisesti tyypitetyissä kielissä mikä tahansa muuttuja voi säilyttää minkä tahansa tyyppistä tietoa. Monet skriptikielet ovat dynaamisesti tyypitettyjä. Näissä kielissä kaikki muuttujat ovat monimuotoisia. Sen sijaan staattisesti tyypitetyissä kielissä, kuten Java ja C++, kaikilla muuttujilla on hyvin määritelty tyyppi, joka annetaan muuttujan esittelyn yhteydessä. Näissä kielissä muuttujan monimuotoisuus tarkoittaa sitä, että muuttuja voi viitata tyyppinsä alityypin mukaiseen arvoon. Yleensä aliluokka on yliluokkansa alityyppi, jolloin yliluokan tunnuksella voidaan viitata sen alapuolella luokkahierarkiassa oleviin olioihin. C++:ssa tällainen muuttuja on välttämättä joko viittaus- tai osoitintyyppinen. Javassa kaikki oliomuuttujat ovat viitetyyppisiä. Monimuotoisia muuttujia käytetään yleisesti monimuotoisten säiliöiden laatimisessa. Säiliöön tallennetaan viitteitä jonkin luokkahierarkian kantaluokkaan, mutta viitteet voivat tosiasiassa olla viitteitä joihinkin hierarkiassa syvemmällä sijaitseviin olioihin. Kun säiliöstä otetaan tällaisia olioita, ne ovat eräässä mielessä menettäneet identiteettinsä: ohjelmoija ei tiedä minkä luokan oliota käsitellään. Ohjelmoitaessa tätä ei aina tarvitsekaan tietää. Varsinkin, jos kantaluokka sisältää vähintään esittelyt kaikista olioihin sovellettavista metodeista, näitä voidaan kutsua tarkemmin selvittämättä olion todellista luokkaa. Joskus kuitenkin on tiedettävä, onko jokin tietty metodi käytettävissä, mikä vaatii luokan tuntemisen ainakin jollakin tarkkuudella. Usein oliokielissä on olemassa tällainen mekanismi. C++-kielessä monimuotoiset säiliöt toteutetaan tallentamalla kantaluokan osoittimia säiliöön; olio varataan kekodynaamisesti ja kantaluokan osoitin laitetaan osoittamaan varattuun olioon. Edellä mainittua ominaisuutta, jonka avulla voi selvittää jonkin olion luokan ominaisuuksia, sanotaan reflektioksi. C++-kielessä reflektion toteutus on varsin vaatimaton, mutta perusominaisuudet voidaan saavuttaa ajonaikaisen tyyppitunnistuksen mekanismilla (RTTI, Run-Time Type Identification). Mekanismi perustuu kahteen operaattoriin: 1. typeid, joka palauttaa olion tyyppiä kuvaavan olion, 2. dynamic_cast, jonka avulla osoittimen tai viitteen tyyppiä voidaan muuttaa luokkahierarkiassa turvallisesti. Jotta mekanismi toimisi asianmukaisesti, on sen kohteena olevan luokkahierarkian oltava monimuotoinen, ts. hierarkian kantaluokassa on oltava ainakin yksi virtuaalinen metodi. Yleensä perittävään luokkaan onkin syytä kirjoittaa ainakin virtuaalinen hajotin, joten mekanismi soveltuu useimpiin käytännössä esiintyviin luokkahierarkioihin. Käytännön ohjelmoinnissa dynamic_cast-operaattori esiintyy huomattavasti useammin kuin typeid. Operaattoria dynamic_cast voidaan soveltaa sekä viitteeseen että osoittimeen, jolloin tyypinmuunnoksen epäonnistuminen johtaa erilaisiin toimintoihin: kun kohteena on osoitin, osoittimen arvoksi tulee nolla, mutta viitteen tapauksessa ohjelmassa aiheutetaan poikkeus. Seuraavassa esimerkissä sovelletaan operaattoria osoittimeen. 15

16 Oletetaan, että ohjelmassa käytetään seuraavia luokkia (Henkilo, Ajattelija, Koomikko ja Kirjailija): #include <iostream> #include <string> using namespace std; class Henkilo private: string nimi; Henkilo(const string &ihmisnimi); void muutanimi(const string &uusinimi); string annanimi() const; void tulostanimi() const; virtual ~Henkilo(); ; Henkilo::Henkilo(const string &ihmisnimi):nimi(ihmisnimi) void Henkilo::muutaNimi(const string &uusinimi) nimi = uusinimi; string Henkilo::annaNimi() const return nimi; void Henkilo::tulostaNimi() const cout << "Nimeni on " +nimi << endl; class Ajattelija virtual string ajattele() = 0; ; class Koomikko: public Ajattelija private: string ajatus; Koomikko(const string &nimi, const string &aatos); string ajattele(); ; Koomikko::Koomikko(const string &nimi, const string &aatos): ajatus(aatos) string Koomikko::ajattele() return ajatus; 16

17 class Kirjailija: public Henkilo, public Ajattelija private: string aforismi; Kirjailija(const string &nimi, const string &aatos); string ajattele(); ; Kirjailija::Kirjailija(const string &nimi, const string &aatos): Henkilo(nimi),aforismi(aatos) string Kirjailija::ajattele() return aforismi; Henkilo-luokasta todettakoon, että henkilöllä on attribuuttina nimi, joka saadaan kutsumalla metodia annanimi. Luokat Koomikko ja Kirjailija perivät kumpikin Ajattelija-luokan, mutta ainoastaan Kirjailija perii Henkilo-luokan. Jos säiliöön tallennetaan sekä Koomikko- että Kirjailija-luokkien olioita Ajattelija-luokan olioina (ts. säiliöön tallennetaan osoittimia, joiden kohdetyyppi on Ajattelija), niin voidaan olla varmoja, että niistä löytyy metodi ajattele. Sen sijaan ei voida tietää, onko mahdollista kutsua metodia annanimi, joka on olemassa vain Kirjailija-luokassa. Siten mikäli ko. metodia halutaan kutsua säiliöstä otettaessa on selvitettävä voidaanko oliota kohdella myös Henkilo-luokan oliona esimerkiksi seuraavasti: void tulostaajatukset(ajattelija* viisaat[], int length ) for(int i=0; i< length; i++) Henkilo *h; h = dynamic_cast<henkilo *>(viisaat[i]); if( h!= 0) // Tyypinmuunnos onnistui cout << h->annanimi() + " sanoo:" << endl; cout << viisaat[i]->ajattele() << endl; 17

18 int main(int argv, char** args) string ajatus = "En voisi kuulua kerhoon, joka ottaa minunlaisiani ihmisiä jäsenikseen."; string aforismi = "Vain itseoppineet ovat oppineita. \nkaikki muut ovat opetettuja."; Koomikko *gm = new Koomikko("Groucho Marx",ajatus); Kirjailija *ep = new Kirjailija("Erno Paasilinna",aforismi); Ajattelija** filosofit = new Ajattelija*[2]; filosofit[0] = gm; filosofit[1] = ep; tulostaajatukset(filosofit,2); Ohjelmassa yritetään tehdä tyyppimuunnos Henkilo-luokan osoittimeksi käyttäen dynamic_castoperaattoria, minkä jälkeen tarkistetaan osoittimen arvosta, onko tyyppimuunnos onnistunut. Ellei muunnos onnistu, osoitin saa arvon nolla ja tällöin ei metodia annanimi voi kutsua. Jos arvo on erisuuri kuin nolla, tyyppimuunnos on laillinen ja voidaan kutsua metodia annanimi. Tyyppimuunnosta, jolla tyyppi vaihdetaan luokkahierarkiassa alaspäin, kutsutaan nimellä downcasting. Tällaista tyyppimuunnosta käytettäessä on aina varmistettava, että muunnos on laillinen. Jos monimuotoisuutta käytetään oikein, downcasting- tyyppimuunnoksia ei ohjelmassa pitäisi juuri koskaan esiintyä. Joskus ne ovat kuitenkin tarpeen. Javassa on huomattavasti kehittyneempi reflektiomekanismi kuin C++:ssa. Siihen ei kuitenkaan paneuduta tässä. Lopuksi perehdytään esimerkkiin, jossa yhdistellään edellä esiintyneitä monimuotoisuuden muotoja. Esimerkki. Kuten alussa mainittiin, ylikuormittaminen tehdään staattisesti käännösaikana. Usein eteen tulee kuitenkin tilanteita, joissa olisi hyödyllistä kutsua metodia siten, että sen parametrien tyypit määräytyvät vasta ajon aikana. Kääntäjä ei kuitenkaan hyväksy tätä. Halutaan esimerkiksi tehdä kivi-paperi-sakset -peli. Kivi, paperi ja sakset periytyvät Esine-luokasta: #include <iostream> #include <cstdlib> #include <string> using namespace std; class Esine ; class Kivi: public Esine ; class Paperi : public Esine ; class Sakset : public Esine ; 18

19 Esine* arvoesine() switch(rand()%3)) default: case 0: return new Sakset(); case 1: return new Paperi(); case 2: return new Kivi(); string vertaa(kivi &k, Kivi &k2) return "Tasapeli"; string vertaa(kivi &k, Paperi &p) return "Tappio"; string vertaa(kivi &k, Sakset &s) return "Voitto"; string vertaa(paperi &p, Kivi &k) return "Voitto"; string vertaa(paperi &p, Paperi &p2) return "Tasapeli"; string vertaa(paperi &p, Sakset &s) return "Tappio"; string vertaa(sakset &s, Kivi &k) return "Tappio"; string vertaa(sakset &s, Paperi &p) return "Voitto"; string vertaa(sakset &s, Sakset &s2) return "Tasapeli"; int main(int args, char** argv) Esine *pa, *pb; pa = arvoesine(); pb = arvoesine(); cout << vertaa(*pa,*pb) << endl; delete pa; delete pb; Jokaiselle parille on tehty vertailufunktio. Pääohjelmassa arvotaan kaksi esinettä, joita vertaillaan keskenään. Metodin vertaa() kutsu ei kuitenkaan kelpaa kääntäjälle, koska käännösvaiheessa ei voida tietää, mitä esinetyyppejä parametrit ovat. Tämä voidaan ratkaista niin sanotulla double-dispatch-tekniikalla. Olio itse tietää oman tyyppinsä, joten perustetaan oikean metodin kutsuminen luokan metodin kutsuun. Jokaiseen luokkaan kirjoitetaan vertailumetodi 19

20 kantaluokalle ja perityille luokille; lisäksi kantaluokkaan tarvitaan ainakin prototyypit samoista metodeista. Vertailumetodissa kutsutaan toisen parametriolion metodia, joka taas tuntee oman tyyppinsä. Tällöin ohjelma muuttuu seuraavaan muotoon: #include <iostream> #include <cstdlib> #include <string> using namespace std; // Luokkien esittelyt Esine-luokkaa varten class Kivi; class Sakset; class Paperi; class Esine ; virtual string name()=0; virtual string vertaa(esine &e)=0; virtual string vertaakiveen(kivi &k)=0; virtual string vertaapaperiin(paperi &p)=0; virtual string vertaasaksiin(sakset &s)=0; class Kivi: public Esine string name() return "Kivi"; string vertaa(esine &e) return e.vertaakiveen(*this); string vertaakiveen(kivi &k) return "Tasapeli"; string vertaapaperiin(paperi &p) return "Tappio"; ; string vertaasaksiin(sakset &s) return "Voitto"; 20

21 class Sakset : public Esine string name() return "Sakset"; string vertaa(esine &e) return e.vertaasaksiin(*this); string vertaakiveen(kivi &k) return "Tappio"; string vertaapaperiin(paperi &p) return "Voitto"; ; string vertaasaksiin(sakset &s) return "Tasapeli"; class Paperi : public Esine string name() return "Paperi"; string vertaa(esine &e) return e.vertaapaperiin(*this); string vertaakiveen(kivi &k) return "Voitto"; string vertaapaperiin(paperi &p) return "Tasapeli"; ; string vertaasaksiin(sakset &s) return "Tappio"; Esine* arvoesine() switch(rand()%3) default: case 0: return new Sakset(); case 1: return new Paperi(); case 2: return new Kivi(); string vertaa(esine &e1, Esine &e2) return e2.vertaa(e1); 21

22 int main(int args, char** argv) Esine *pa, *pb; pa = arvoesine(); pb = arvoesine(); cout << "pa = " << pa->name() << " pb = " << pb->name() << endl; cout << "Tulos: " << vertaa(*pa,*pb) << endl; delete pa; delete pb; Huomaa, että edellisessä esimerkissä on toimimaton ylikuormittaminen korvattu metodien uudelleen määrittelyllä aikaan saatavalla monimuotoisuudella. Esine-tyyppiset osoitinmuuttujat ovat monimuotoisia muuttujia. Lähteet [Bud] Budd, Timothy A: An Introduction to Object-Oriented Programming, Addison-Wesley 2002 [Eck] Eckel, Bruce: Thinking in C++, 2 nd edition, Volume 1, Saatavissa osoitteesta: [Hie] Hietanen, P.: C++ ja olio-ohjelmointi, 3. laitos, Docendo

812347A Olio-ohjelmointi, 2015 syksy 2. vsk. IV Periytyminen ja monimuotoisuus

812347A Olio-ohjelmointi, 2015 syksy 2. vsk. IV Periytyminen ja monimuotoisuus 812347A Olio-ohjelmointi, 2015 syksy 2. vsk IV Periytyminen ja monimuotoisuus Sisältö 1. Periytyminen 2. Johdanto monimuotoisuuteen 3. Ylikuormittaminen 4. Uudelleenmäärittely 5. Muuttujien monimuotoisuus

Lisätiedot

815338A Ohjelmointikielten periaatteet 2015-2016. Harjoitus 5 Vastaukset

815338A Ohjelmointikielten periaatteet 2015-2016. Harjoitus 5 Vastaukset 815338A Ohjelmointikielten periaatteet 2015-2016. Harjoitus 5 Vastaukset Harjoituksen aiheena ovat aliohjelmat ja abstraktit tietotyypit sekä olio-ohjelmointi. Tehtävät tehdään C-, C++- ja Java-kielillä.

Lisätiedot

T740103 Olio-ohjelmointi Osa 5: Periytyminen ja polymorfismi Jukka Jauhiainen OAMK Tekniikan yksikkö 2010

T740103 Olio-ohjelmointi Osa 5: Periytyminen ja polymorfismi Jukka Jauhiainen OAMK Tekniikan yksikkö 2010 12. Periytyminen Johdantoa Käytännössä vähänkään laajemmissa ohjelmissa joudutaan laatimaan useita luokkia, joiden pitäisi pystyä välittämään tietoa toisilleen. Ohjelmien ylläpidon kannalta olisi lisäksi

Lisätiedot

Sisällys. JAVA-OHJELMOINTI Osa 6: Periytyminen ja näkyvyys. Luokkahierarkia. Periytyminen (inheritance)

Sisällys. JAVA-OHJELMOINTI Osa 6: Periytyminen ja näkyvyys. Luokkahierarkia. Periytyminen (inheritance) Sisällys JAVA-OHJELMOINTI Osa 6: Periytyminen ja näkyvyys Periytyminen (inheritance) Näkyvyys (visibility) Eero Hyvönen Tietojenkäsittelytieteen laitos Helsingin yliopisto 13.10.2000 E. Hyvönen: Java Osa

Lisätiedot

9. Periytyminen Javassa 9.1

9. Periytyminen Javassa 9.1 9. Periytyminen Javassa 9.1 Sisällys Periytymismekanismi Java-kielessä. Piirteiden näkyvyys periytymisessä. Ilmentymämetodien korvaaminen. Luokkametodien peittäminen. Super-attribuutti. Override-annotaatio.

Lisätiedot

815338A Ohjelmointikielten periaatteet

815338A Ohjelmointikielten periaatteet 815338A Ohjelmointikielten periaatteet 2015-2016 V Abstraktit tietotyypit ja olioohjelmointi Sisältö I. Abstraktit tietotyypit II. 1. Johdatus abstrakteihin tietotyyppeihin 2. Abstraktit tietotyypit Adassa

Lisätiedot

12. Monimuotoisuus 12.1

12. Monimuotoisuus 12.1 12. Monimuotoisuus 12.1 Sisällys Johdanto. Periytymismekanismi määrittää alityypityksen. Viitteiden sijoitus ja vertailu. Staattinen ja dynaaminen luokka. Myöhäinen ja aikainen sidonta. Parametrinvälitys

Lisätiedot

9. Periytyminen Javassa 9.1

9. Periytyminen Javassa 9.1 9. Periytyminen Javassa 9.1 Sisällys Periytymismekanismi Java-kielessä. Piirteiden näkyvyys periytymisessä. Metodien korvaaminen ja super-attribuutti. Attribuutin peittäminen periytymisen kautta. Rakentajat

Lisätiedot

Olio-ohjelmoinnissa luokat voidaan järjestää siten, että ne pystyvät jakamaan yhteisiä tietoja ja aliohjelmia.

Olio-ohjelmoinnissa luokat voidaan järjestää siten, että ne pystyvät jakamaan yhteisiä tietoja ja aliohjelmia. 4. Periytyminen 4.1. Johdantoa Käytännössä vähänkään laajemmissa ohjelmissa joudutaan laatimaan useita luokkia, joiden pitäisi pystyä välittämään tietoa toisilleen. Ohjelmien ylläpidon kannalta olisi lisäksi

Lisätiedot

Sisällys. 9. Periytyminen Javassa. Periytymismekanismi Java-kielessä. Periytymismekanismi Java-kielessä

Sisällys. 9. Periytyminen Javassa. Periytymismekanismi Java-kielessä. Periytymismekanismi Java-kielessä Sisällys 9. Periytyminen Javassa Periytymismekanismi Java-kielessä. Piirteiden näkyvyys periytymisessä. Metodien korvaaminen ja super-attribuutti. Attribuutin peittäminen periytymisen kautta. Rakentajat

Lisätiedot

Operaattoreiden ylikuormitus. Operaattoreiden kuormitus. Operaattoreiden kuormitus. Operaattoreista. Kuormituksesta

Operaattoreiden ylikuormitus. Operaattoreiden kuormitus. Operaattoreiden kuormitus. Operaattoreista. Kuormituksesta C++ - perusteet Java-osaajille luento 5/7: operaattoreiden ylikuormitus, oliotaulukko, parametrien oletusarvot, komentoriviparametrit, constant, inline, Operaattoreiden ylikuormitus Operaattoreiden kuormitus

Lisätiedot

Sisällys. 9. Periytyminen Javassa. Periytymismekanismi Java-kielessä. Periytymismekanismi Java-kielessä

Sisällys. 9. Periytyminen Javassa. Periytymismekanismi Java-kielessä. Periytymismekanismi Java-kielessä Sisällys 9. Periytyminen Javassa Periytymismekanismi Java-kielessä. Piirteiden näkyvyys periytymisessä. Metodien korvaaminen ja super-attribuutti. Attribuutin peittäminen periytymisen kautta. Rakentajat

Lisätiedot

815338A Ohjelmointikielten periaatteet Harjoitus 3 vastaukset

815338A Ohjelmointikielten periaatteet Harjoitus 3 vastaukset 815338A Ohjelmointikielten periaatteet 2015-2016. Harjoitus 3 vastaukset Harjoituksen aiheena ovat imperatiivisten kielten muuttujiin liittyvät kysymykset. Tehtävä 1. Määritä muuttujien max_num, lista,

Lisätiedot

1. Olio-ohjelmointi 1.1

1. Olio-ohjelmointi 1.1 1. Olio-ohjelmointi 1.1 Sisällys Olio-ohjelmointi on eräs ohjelmointiparadigma. Olio-ohjelmoinnin muotoja. Ohjelmiston analyysi ja suunnittelu. Olioparadigman etuja ja kritiikkiä. 1.2 Ohjelmointiparadigmoja

Lisätiedot

12. Monimuotoisuus 12.1

12. Monimuotoisuus 12.1 12. Monimuotoisuus 12.1 Sisällys Johdanto. Periytymismekanismi määrittää alityypityksen. Viitteiden sijoitus ja vertailu. Staattinen ja dynaaminen luokka. Parametrinvälitys eräs monimuotoisuuden sovellus.

Lisätiedot

Luokassa määriteltävät jäsenet ovat pääasiassa tietojäseniä tai aliohjelmajäseniä. Luokan määrittelyyn liittyvät varatut sanat:

Luokassa määriteltävät jäsenet ovat pääasiassa tietojäseniä tai aliohjelmajäseniä. Luokan määrittelyyn liittyvät varatut sanat: 1. Luokan jäsenet Luokassa määriteltävät jäsenet ovat pääasiassa tietojäseniä tai aliohjelmajäseniä. Luokan määrittelyyn liittyvät varatut sanat: class luokan_nimi tyypit: enum, struct, class, typedef

Lisätiedot

Olio-ohjelmointi Javalla

Olio-ohjelmointi Javalla 1 Olio-ohjelmointi Javalla Olio-ohjelmointi Luokka Attribuutit Konstruktori Olion luominen Metodit Olion kopiointi Staattinen attribuutti ja metodi Yksinkertainen ohjelmaluokka Ohjelmaluokka 1 Olio-ohjelmointi

Lisätiedot

12 Mallit (Templates)

12 Mallit (Templates) 12 Mallit (Templates) Malli on määrittely, jota käyttämällä voidaan luoda samankaltaisten aliohjelmien ja luokkien perheitä. Malli on ohje kääntäjälle luoda geneerisestä tyyppiriippumattomasta ohjelmakoodista

Lisätiedot

Rajapinnasta ei voida muodostaa olioita. Voidaan käyttää tunnuksen tyyppinä. Rajapinta on kuitenkin abstraktia luokkaa selvästi abstraktimpi tyyppi.

Rajapinnasta ei voida muodostaa olioita. Voidaan käyttää tunnuksen tyyppinä. Rajapinta on kuitenkin abstraktia luokkaa selvästi abstraktimpi tyyppi. 11. Rajapinnat 11.1 Sisällys Johdanto. Abstrakti luokka vai rajapinta? Rajapintojen hyötyjä. Kuinka rajapinnat määritellään ja otetaan käyttöön? Eläin, nisäkäs, kissa ja rajapinta. Moniperiytyminen rajapintojen

Lisätiedot

Geneeriset luokat. C++ - perusteet Java-osaajille luento 6/7: Template, tyyppi-informaatio, nimiavaruudet. Geneerisen luokan käyttö.

Geneeriset luokat. C++ - perusteet Java-osaajille luento 6/7: Template, tyyppi-informaatio, nimiavaruudet. Geneerisen luokan käyttö. Geneeriset luokat C++ - perusteet Java-osaajille luento 6/7: Template, tyyppi-informaatio, nimiavaruudet Geneerinen luokka tarkoittaa parametroitua luokkamallia, jonka avulla voidaan muodostaa useita,

Lisätiedot

Virtuaalifunktiot ja polymorfismi

Virtuaalifunktiot ja polymorfismi Virtuaalifunktiot ja polymorfismi 16 Virtuaalifunktiot ja polymorfismi Polymorfismi on niin tehokas olio-ohjelmoinnin ominaisuus, että tulet varmastikin käyttämään sitä lähes kaikissa C++-ohjelmissasi.

Lisätiedot

C++ rautaisannos. Kolme tapaa sanoa, että tulostukseen käytetään standardikirjaston iostreamosassa määriteltyä, nimiavaruuden std oliota cout:

C++ rautaisannos. Kolme tapaa sanoa, että tulostukseen käytetään standardikirjaston iostreamosassa määriteltyä, nimiavaruuden std oliota cout: C++ rautaisannos Kolme tapaa sanoa, että tulostukseen käytetään standardikirjaston iostreamosassa määriteltyä, nimiavaruuden std oliota cout: # include #include main ( ) main (

Lisätiedot

Taulukot. Jukka Harju, Jukka Juslin 2006 1

Taulukot. Jukka Harju, Jukka Juslin 2006 1 Taulukot Jukka Harju, Jukka Juslin 2006 1 Taulukot Taulukot ovat olioita, jotka auttavat organisoimaan suuria määriä tietoa. Käsittelylistalla on: Taulukon tekeminen ja käyttö Rajojen tarkastus ja kapasiteetti

Lisätiedot

JAVA-PERUSTEET. JAVA-OHJELMOINTI 3op A274615 JAVAN PERUSTEET LYHYT KERTAUS JAVAN OMINAISUUKSISTA JAVAN OMINAISUUKSIA. Java vs. C++?

JAVA-PERUSTEET. JAVA-OHJELMOINTI 3op A274615 JAVAN PERUSTEET LYHYT KERTAUS JAVAN OMINAISUUKSISTA JAVAN OMINAISUUKSIA. Java vs. C++? JAVA-OHJELMOINTI 3op A274615 JAVAN PERUSTEET LYHYT KERTAUS Teemu Saarelainen teemu.saarelainen@kyamk.fi Lähteet: http://java.sun.com/docs/books/tutorial/index.html Vesterholm, Kyppö: Java-ohjelmointi,

Lisätiedot

T Olio-ohjelmointi Osa 3: Luokka, muodostin ja hajotin, this-osoitin Jukka Jauhiainen OAMK Tekniikan yksikkö 2010

T Olio-ohjelmointi Osa 3: Luokka, muodostin ja hajotin, this-osoitin Jukka Jauhiainen OAMK Tekniikan yksikkö 2010 11. Luokka Opetellaan seuraavaksi, miten omia luokkia kirjoitetaan. Aikaisemmin olikin jo esillä, että luokka on tietorakenne, joka sisältää sekä tiedot (attribuutit) että niitä käsittelevät aliohjelmat

Lisätiedot

Opintojakso TT00AA11 Ohjelmoinnin jatko (Java): 3 op Rajapinnat ja sisäluokat

Opintojakso TT00AA11 Ohjelmoinnin jatko (Java): 3 op Rajapinnat ja sisäluokat Opintojakso TT00AA11 Ohjelmoinnin jatko (Java): 3 op Rajapinnat ja sisäluokat Rajapinnat Java-kieli ei tue luokkien moniperintää. Jokaisella luokalla voi olla vain yksi välitön yliluokka. Toisinaan olisi

Lisätiedot

ITKP102 Ohjelmointi 1 (6 op)

ITKP102 Ohjelmointi 1 (6 op) ITKP102 Ohjelmointi 1 (6 op) Tentaattori: Antti-Jussi Lakanen 22. huhtikuuta 2016 Vastaa kaikkiin tehtäviin. Tee jokainen tehtävä erilliselle konseptiarkille! Kirjoittamasi luokat, funktiot ja aliohjelmat

Lisätiedot

Sisällys. 1. Omat operaatiot. Yleistä operaatioista. Yleistä operaatioista

Sisällys. 1. Omat operaatiot. Yleistä operaatioista. Yleistä operaatioista Sisällys 1. Omat operaatiot Yleistä operaatioista. Mihin operaatioita tarvitaan? Oman operaation määrittely. Yleisesti, nimeäminen ja hyvä ohjelmointitapa, määreet, parametrit ja näkyvyys. HelloWorld-ohjelma

Lisätiedot

Sisällys. 11. Rajapinnat. Johdanto. Johdanto

Sisällys. 11. Rajapinnat. Johdanto. Johdanto Sisällys 11. ajapinnat. bstrakti luokka vai rajapinta? ajapintojen hyötyjä. Kuinka rajapinnat määritellään ja otetaan käyttöön? Eläin, nisäkäs, kissa ja rajapinta. Moniperiytyminen rajapintojen avulla.

Lisätiedot

1. Omat operaatiot 1.1

1. Omat operaatiot 1.1 1. Omat operaatiot 1.1 Sisällys Yleistä operaatioista. Mihin operaatioita tarvitaan? Oman operaation määrittely. Yleisesti, nimeäminen ja hyvä ohjelmointitapa, määreet, parametrit ja näkyvyys. HelloWorld-ohjelma

Lisätiedot

Olio-ohjelmointi Syntaksikokoelma

Olio-ohjelmointi Syntaksikokoelma C++-kielen uusia ominaisuuksia Olio-ohjelmointi Syntaksikokoelma 31.10.2008 Bool-tietotyyppi: Totuusarvo true (1), jos ehto on tosi ja false (0) jos ehto epätosi. Dynaaminen muistinvaraus: Yhden muuttuja

Lisätiedot

Metodit. Metodien määrittely. Metodin parametrit ja paluuarvo. Metodien suorittaminen eli kutsuminen. Metodien kuormittaminen

Metodit. Metodien määrittely. Metodin parametrit ja paluuarvo. Metodien suorittaminen eli kutsuminen. Metodien kuormittaminen Metodit Metodien määrittely Metodin parametrit ja paluuarvo Metodien suorittaminen eli kutsuminen Metodien kuormittaminen 1 Mikä on metodi? Metodi on luokan sisällä oleva yhteenkuuluvien toimintojen kokonaisuus

Lisätiedot

Opintojakso TT00AA11 Ohjelmoinnin jatko (Java): 3 op Taulukot & Periytyminen

Opintojakso TT00AA11 Ohjelmoinnin jatko (Java): 3 op Taulukot & Periytyminen Opintojakso TT00AA11 Ohjelmoinnin jatko (Java): 3 op Taulukot & Periytyminen Taulukot: Array Taulukko Javassa pitää aina perustaa (new) Yksinkertaisessa tilanteessa taulukon koko tiedetään etukäteen ja

Lisätiedot

Olio-ohjelmointi Olioperusteinen ohjelmointi C++-kielellä. 1. Johdanto

Olio-ohjelmointi Olioperusteinen ohjelmointi C++-kielellä. 1. Johdanto Olio-ohjelmointi Olioperusteinen ohjelmointi C++-kielellä Tässä osassa käsitellään olioperusteista (object-based) ohjelmointia, ts. olio-ohjelmointia ilman periytymisen hyödyntämistä. Olio-ohjelmoinnin

Lisätiedot

15. Ohjelmoinnin tekniikkaa 15.1

15. Ohjelmoinnin tekniikkaa 15.1 15. Ohjelmoinnin tekniikkaa 15.1 Sisällys For-each-rakenne. Lueteltu tyyppi enum. Override-annotaatio. Geneerinen ohjelmointi. 15.2 For-each-rakenne For-rakenteen variaatio taulukoiden ja muiden kokoelmien

Lisätiedot

on ohjelmoijan itse tekemä tietotyyppi, joka kuvaa käsitettä

on ohjelmoijan itse tekemä tietotyyppi, joka kuvaa käsitettä LUOKAN MÄÄRITTELY Luokka, mitä se sisältää Luokan määrittely Olion ominaisuudet eli attribuutit Olion metodit Olion muodostimet ja luonti Olion tuhoutuminen Metodin kutsu luokan ulkopuolelta Olion kopioiminen

Lisätiedot

Harjoitus 7. 1. Olkoon olemassa luokat Lintu ja Pelikaani seuraavasti:

Harjoitus 7. 1. Olkoon olemassa luokat Lintu ja Pelikaani seuraavasti: Harjoitus 7 1. Olkoon olemassa luokat Lintu ja Pelikaani seuraavasti: class Lintu //Kentät private int _siivenpituus; protected double _aivojenkoko; private bool _osaakolentaa; //Ominaisuudet public int

Lisätiedot

Osoitin ja viittaus C++:ssa

Osoitin ja viittaus C++:ssa Osoitin ja viittaus C++:ssa Osoitin yksinkertaiseen tietotyyppiin Osoitin on muuttuja, joka sisältää jonkin toisen samantyyppisen muuttujan osoitteen. Ohessa on esimerkkiohjelma, jossa määritellään kokonaislukumuuttuja

Lisätiedot

Tehtävä 1. TL5302 Olio-ohjelmointi Koe Malliratkaisuja. Tässä sekä a)- että b)-kohdan toimiva ratkaisu:

Tehtävä 1. TL5302 Olio-ohjelmointi Koe Malliratkaisuja. Tässä sekä a)- että b)-kohdan toimiva ratkaisu: TL5302 Olio-ohjelmointi Koe 19.4.2005 Malliratkaisuja Tehtävä 1 Tässä sekä a)- että b)-kohdan toimiva ratkaisu: #include using namespace std; int main() int taul[5]=1,2,3,4,5; int *p,&r=taul[0];

Lisätiedot

Ohjelmoinnin jatkokurssi, kurssikoe 28.4.2014

Ohjelmoinnin jatkokurssi, kurssikoe 28.4.2014 Ohjelmoinnin jatkokurssi, kurssikoe 28.4.2014 Kirjoita jokaiseen palauttamaasi konseptiin kurssin nimi, kokeen päivämäärä, oma nimi ja opiskelijanumero. Vastaa kaikkiin tehtäviin omille konsepteilleen.

Lisätiedot

C++11 Syntaksi. Jari-Pekka Voutilainen Jari-Pekka Voutilainen: C++11 Syntaksi

C++11 Syntaksi. Jari-Pekka Voutilainen Jari-Pekka Voutilainen: C++11 Syntaksi 1 C++11 Syntaksi Jari-Pekka Voutilainen 13.4.2012 2 Range-for Iteroi säiliön kaikki alkiot for-silmukassa. Säiliöltä vaaditaan begin- ja end-iteraattorit. Pätee kaikille C++11 STL-säiliöille, taulukoille,

Lisätiedot

A) on käytännöllinen ohjelmointitekniikka. = laajennetaan aikaisemmin tehtyjä luokkia (uudelleenkäytettävyys)

A) on käytännöllinen ohjelmointitekniikka. = laajennetaan aikaisemmin tehtyjä luokkia (uudelleenkäytettävyys) 1(37) PERIYTYMINEN (inheritance) YLILUOKKA (superclass) ALILUOKKA (subclass) A) on käytännöllinen ohjelmointitekniikka = laajennetaan aikaisemmin tehtyjä luokkia (uudelleenkäytettävyys) B) on käsitteiden

Lisätiedot

812341A Olio-ohjelmointi, IX Olioiden välisistä yhteyksistä

812341A Olio-ohjelmointi, IX Olioiden välisistä yhteyksistä 2016 IX Olioiden välisistä yhteyksistä Sisältö 1. Johdanto 2. Kytkentä 3. Koheesio 4. Näkyvyydestä 2 Johdanto n Ohjelmassa syntyy kytkentöjä olioiden välille Toivottuja ja epätoivottuja n Näkyvyys vaikuttaa

Lisätiedot

Sisällys. Yleistä attribuuteista. Näkyvyys luokan sisällä. Tiedonkätkentä. Aksessorit. 4.2

Sisällys. Yleistä attribuuteista. Näkyvyys luokan sisällä. Tiedonkätkentä. Aksessorit. 4.2 4. Attribuutit 4.1 Sisällys Yleistä attribuuteista. Näkyvyys luokan sisällä. Tiedonkätkentä. Aksessorit. 4.2 Yleistä Luokan lohkossa, mutta metodien ulkopuolella esiteltyjä muuttujia ja vakioita. Esittely

Lisätiedot

812341A Olio-ohjelmointi Peruskäsitteet jatkoa

812341A Olio-ohjelmointi Peruskäsitteet jatkoa 812341A Olio-ohjelmointi 2106 Peruskäsitteet jatkoa Luokkakohtaiset piirteet n Yhteisiä kaikille saman luokan olioille n Liittyvät luokkaan, eivät yksittäiseen olioon n Kaikki ko. luokan oliot voivat käyttää

Lisätiedot

Abstraktit tietotyypit ja olio-ohjelmointi

Abstraktit tietotyypit ja olio-ohjelmointi Abstraktit tietotyypit ja olio-ohjelmointi Edellisessä osassa käsiteltiin aliohjelmia prosessiabstraktion välineenä. Prosessiabstraktio onkin vanhimpia ohjelmointikielten suunnittelukäsitteitä ja sisältynyt

Lisätiedot

15. Ohjelmoinnin tekniikkaa 15.1

15. Ohjelmoinnin tekniikkaa 15.1 15. Ohjelmoinnin tekniikkaa 15.1 Sisällys For-each-rakenne. Geneerinen ohjelmointi. Lueteltu tyyppi enum. 15.2 For-each-rakenne For-rakenteen variaatio taulukoiden ja muiden kokoelmien silmukoimiseen:

Lisätiedot

Java-kielen perusteet

Java-kielen perusteet Java-kielen perusteet Tunnus, varattu sana, kommentti Muuttuja, alkeistietotyyppi, merkkijono, literaalivakio, nimetty vakio Tiedon merkkipohjainen tulostaminen 1 Tunnus Java tunnus Java-kirjain Java-numero

Lisätiedot

Sisällys. Yleistä attribuuteista. Näkyvyys luokan sisällä ja ulkopuolelta. Attribuuttien arvojen käsittely aksessoreilla. 4.2

Sisällys. Yleistä attribuuteista. Näkyvyys luokan sisällä ja ulkopuolelta. Attribuuttien arvojen käsittely aksessoreilla. 4.2 4. Attribuutit 4.1 Sisällys Yleistä attribuuteista. Näkyvyys luokan sisällä ja ulkopuolelta. Attribuuttien arvojen käsittely aksessoreilla. 4.2 Yleistä Luokan lohkossa, mutta metodien ulkopuolella esiteltyjä

Lisätiedot

Sisällys. Metodien kuormittaminen. Luokkametodit ja -attribuutit. Rakentajat. Metodien ja muun luokan sisällön järjestäminen. 6.2

Sisällys. Metodien kuormittaminen. Luokkametodit ja -attribuutit. Rakentajat. Metodien ja muun luokan sisällön järjestäminen. 6.2 6. Metodit 6.1 Sisällys Metodien kuormittaminen. Luokkametodit ja -attribuutit. Rakentajat. Metodien ja muun luokan sisällön järjestäminen. 6.2 Oliot viestivät metodeja kutsuen Olio-ohjelmoinnissa ohjelma

Lisätiedot

Sisällys. JAVA-OHJELMOINTI Osa 7: Abstrakti luokka ja rajapinta. Abstraktin luokan idea. Abstrakti luokka ja metodi. Esimerkki

Sisällys. JAVA-OHJELMOINTI Osa 7: Abstrakti luokka ja rajapinta. Abstraktin luokan idea. Abstrakti luokka ja metodi. Esimerkki Sisällys JAVA-OHJELMOINTI Osa 7: Abstrakti luokka ja rajapinta Abstrakti luokka ja metodi Rajapintamäärittely (interface) Eero Hyvönen Tietojenkäsittelytieteen laitos Helsingin yliopisto 13.10.2000 E.

Lisätiedot

812347A Olio-ohjelmointi, 2015 syksy 2. vsk. VII Suunnittelumallit Adapter ja Composite

812347A Olio-ohjelmointi, 2015 syksy 2. vsk. VII Suunnittelumallit Adapter ja Composite 2015 syksy 2. vsk VII Suunnittelumallit Adapter ja Composite Sisältö 1. Johdanto rakennemalleihin 2. Adapter (Sovitin) 3. Composite (Rekursiokooste) Suunnittelumallit Adapter ja Composite 2 VII.1 Johdanto

Lisätiedot

Sisällys. 6. Metodit. Oliot viestivät metodeja kutsuen. Oliot viestivät metodeja kutsuen

Sisällys. 6. Metodit. Oliot viestivät metodeja kutsuen. Oliot viestivät metodeja kutsuen Sisällys 6. Metodit Oliot viestivät metodeja kutsuen. Kuormittaminen. Luokkametodit (ja -attribuutit).. Metodien ja muun luokan sisällön järjestäminen. 6.1 6.2 Oliot viestivät metodeja kutsuen Oliot viestivät

Lisätiedot

Olion elinikä. Olion luominen. Olion tuhoutuminen. Olion tuhoutuminen. Kissa rontti = null; rontti = new Kissa();

Olion elinikä. Olion luominen. Olion tuhoutuminen. Olion tuhoutuminen. Kissa rontti = null; rontti = new Kissa(); Sisällys 7. Oliot ja viitteet Olio Java-kielessä. Olion luominen, elinikä ja tuhoutuminen. Viitteiden käsittelyä: sijoitus, vertailu ja varautuminen null-arvoon. Viite metodin paluuarvona.. 7.1 7.2 Olio

Lisätiedot

812336A C++ -kielen perusteet, 21.8.2010

812336A C++ -kielen perusteet, 21.8.2010 812336A C++ -kielen perusteet, 21.8.2010 1. Vastaa lyhyesti seuraaviin kysymyksiin (1p kaikista): a) Mitä tarkoittaa funktion ylikuormittaminen (overloading)? b) Mitä tarkoittaa jäsenfunktion ylimääritys

Lisätiedot

16. Javan omat luokat 16.1

16. Javan omat luokat 16.1 16. Javan omat luokat 16.1 Sisällys Johdanto. Object-luokka: tostring-, equals-, clone- ja getclass-metodit. Comparable-rajapinta: compareto-metodi. Vector- ja ArrayList-luokat. 16.2 Javan omat luokat

Lisätiedot

812347A Olio-ohjelmointi, 2015 syksy 2. vsk. X Poikkeusten käsittelystä

812347A Olio-ohjelmointi, 2015 syksy 2. vsk. X Poikkeusten käsittelystä 812347A Olio-ohjelmointi, 2015 syksy 2. vsk X Poikkeusten käsittelystä Sisältö 1. Yleistä poikkeusten käsittelystä 2. Poikkeuskäsittelyn perusteita C++:ssa 3. Standardissa määritellyt poikkeukset 4. Poikkeusvarmuus

Lisätiedot

Java kahdessa tunnissa. Jyry Suvilehto

Java kahdessa tunnissa. Jyry Suvilehto Java kahdessa tunnissa Jyry Suvilehto Ohjelma Ohjelmointiasioita alkeista nippelitietoon n. 45 min Tauko 10 min Oliot, luokat ja muut kummajaiset n. 45 min Kysykää Sisältöä ei oikeasti ole 2x45 min täytteeksi,

Lisätiedot

Luokat ja oliot. Ville Sundberg

Luokat ja oliot. Ville Sundberg Luokat ja oliot Ville Sundberg 12.9.2007 Maailma on täynnä olioita Myös tietokoneohjelmat koostuvat olioista Σ Ο ω Μ ς υ φ Ϊ Φ Θ ψ Љ Є Ύ χ Й Mikä on olio? Tietokoneohjelman rakennuspalikka Oliolla on kaksi

Lisätiedot

TIE-20200 Ohjelmistojen suunnittelu. Luento 8..9: moniperintä

TIE-20200 Ohjelmistojen suunnittelu. Luento 8..9: moniperintä TIE-20200 Ohjelmistojen suunnittelu Luento 8..9: moniperintä 1 Ajankohtaista Harjoitustyön suunnittelusessiot pidetty, työt jatkuvat, välivaiheen esittely seuraavana Viimeinen viikkoharjoituskerta, palataan

Lisätiedot

Periytyminen. Luokat ja olio-ohjelmointi

Periytyminen. Luokat ja olio-ohjelmointi Periytyminen 15 Periytyminen Tässä luvussa käsittelemme aihetta, joka on olio-ohjelmoinnin kaikkein tärkein osa - periytyvyys. Periytyvyyden avulla voimme luoda uusia luokkia uudelleenkäyttämällä ja laajentamalla

Lisätiedot

Ohjelmistojen mallintaminen Luokkakaaviot Harri Laine 1

Ohjelmistojen mallintaminen Luokkakaaviot Harri Laine 1 Ohjelmistojen mallintaminen Luokkakaaviot 5.12.2008 Harri Laine 1 Olioiden palvelut Palvelun kuvauksessa annettavat tiedot näkyvyys (kuten attribuuttien kohdalla) nimi (ainoa välttämätön osa) parametrit

Lisätiedot

812347A Olio-ohjelmointi, 2015 syksy 2. vsk. II Johdanto olio-ohjelmointiin

812347A Olio-ohjelmointi, 2015 syksy 2. vsk. II Johdanto olio-ohjelmointiin 812347A Olio-ohjelmointi, 2015 syksy 2. vsk II Johdanto olio-ohjelmointiin Sisältö 1. Abstraktiosta 2. Olio-ohjelmoinnin historiaa 3. Olioparadigmasta 4. Peruskäsitteiden esittely 2 II.1 Abstraktiosta

Lisätiedot

Javan perusteita. Janne Käki

Javan perusteita. Janne Käki Javan perusteita Janne Käki 20.9.2006 Muutama perusasia Tietokone tekee juuri (ja vain) sen, mitä käsketään. Tietokone ymmärtää vain syntaksia (sanojen kirjoitusasua), ei semantiikkaa (sanojen merkitystä).

Lisätiedot

4. Luokan testaus ja käyttö olion kautta 4.1

4. Luokan testaus ja käyttö olion kautta 4.1 4. Luokan testaus ja käyttö olion kautta 4.1 Olion luominen luokasta Java-kielessä olio määritellään joko luokan edustajaksi tai taulukoksi. Olio on joukko keskusmuistissa olevia tietoja. Oliota käsitellään

Lisätiedot

Ohjelmistojen mallintaminen luokkamallin lisäpiirteitä

Ohjelmistojen mallintaminen luokkamallin lisäpiirteitä 582104 Ohjelmistojen mallintaminen luokkamallin lisäpiirteitä 1 Luokkamallin lisäpiirteitä Erilaiset yhteystyypit kooste kompositio Muita luokkien välisiä suhteita riippuvuudet periytyminen eli luokkahierarkia

Lisätiedot

Opintojakso TT00AA11 Ohjelmoinnin jatko (Java): 3 op Pakkaukset ja määreet

Opintojakso TT00AA11 Ohjelmoinnin jatko (Java): 3 op Pakkaukset ja määreet Opintojakso TT00AA11 Ohjelmoinnin jatko (Java): 3 op Pakkaukset ja määreet Pakkaukset ja määreet Toisiinsa liittyvät luokkatiedostot voidaan koota pakkauksiksi. Luo hierarkiaa ja järjestystä ohjelmistotuotteeseen.

Lisätiedot

7. Oliot ja viitteet 7.1

7. Oliot ja viitteet 7.1 7. Oliot ja viitteet 7.1 Sisällys Olio Java-kielessä. Olion luominen, elinikä ja tuhoutuminen. Viitteiden sijoitus. Viitteiden vertailu. Varautuminen null-arvoon. Viite metodin paluuarvona. Viite metodin

Lisätiedot

Olio-ohjelmointi Poikkeusten käsittelystä. 1. Johdanto

Olio-ohjelmointi Poikkeusten käsittelystä. 1. Johdanto Olio-ohjelmointi Poikkeusten käsittelystä Virheiden käsittely liittyy olennaisesti kaikkeen ohjelmointiin. Monissa sovelluksissa virhetilanteiden käsittelemiseen liittyvää koodia on merkittävä osuus koko

Lisätiedot

C# olio-ohjelmointi perusopas

C# olio-ohjelmointi perusopas Paavo Räisänen C# olio-ohjelmointi perusopas www.ohjelmoimaan.net Tätä opasta saa vapaasti kopioida, tulostaa ja levittää ei kaupallisissa tarkoituksissa. Kuitenkaan omille nettisivuille opasta ei saa

Lisätiedot

Kompositio. Mikä komposition on? Kompositio vs. yhteyssuhde Kompositio Javalla Konstruktorit set-ja get-metodit tostring-metodi Pääohjelma

Kompositio. Mikä komposition on? Kompositio vs. yhteyssuhde Kompositio Javalla Konstruktorit set-ja get-metodit tostring-metodi Pääohjelma 1 Kompositio Mikä komposition on? Kompositio vs. yhteyssuhde Kompositio Javalla Konstruktorit set-ja get-metodit tostring-metodi Pääohjelma 1 Mikä kompositio on? Tili - : String - : double 1 1 Kayttoraja

Lisätiedot

Tietueet. Tietueiden määrittely

Tietueet. Tietueiden määrittely Tietueet Tietueiden määrittely Tietue on tietorakenne, joka kokoaa yhteen eri tyyppistä tietoa yhdeksi asiakokonaisuudeksi. Tähän kokonaisuuteen voidaan viitata yhteisellä nimellä. Auttaa ohjelmoijaa järjestelemään

Lisätiedot

19. Olio-ohjelmointia Javalla 19.1

19. Olio-ohjelmointia Javalla 19.1 19. Olio-ohjelmointia Javalla 19.1 Sisällys Olioiden esittely ja alustus. Metodit Yleistä metodeista. Mihin metodeja tarvitaan? Metodien määrittely. Omat metodit: nimeäminen, paikka, kutsuminen, parametrit

Lisätiedot

Ohjelmointitaito (ict1td002, 12 op) Kevät 2008. 1. Java-ohjelmoinnin alkeita. Tietokoneohjelma. Raine Kauppinen raine.kauppinen@haaga-helia.

Ohjelmointitaito (ict1td002, 12 op) Kevät 2008. 1. Java-ohjelmoinnin alkeita. Tietokoneohjelma. Raine Kauppinen raine.kauppinen@haaga-helia. Ohjelmointitaito (ict1td002, 12 op) Kevät 2008 Raine Kauppinen raine.kauppinen@haaga-helia.fi 1. Java-ohjelmoinnin alkeita Tietokoneohjelma Java-kieli ja Eclipse-ympäristö Java-ohjelma ja ohjelmaluokka

Lisätiedot

Sisällys. 19. Olio-ohjelmointia Javalla. Yleistä. Olioiden esittely ja alustus

Sisällys. 19. Olio-ohjelmointia Javalla. Yleistä. Olioiden esittely ja alustus Sisällys 19. Olio-ohjelmointia Javalla Olioiden esittely ja alustus. Metodit Yleistä metodeista. Mihin metodeja tarvitaan? Metodien määrittely. Omat metodit: nimeäminen, paikka, kutsuminen, parametrit

Lisätiedot

Operaattorin ylikuormitus ja käyttäjän muunnokset

Operaattorin ylikuormitus ja käyttäjän muunnokset 13 Operaattorin ylikuormitus ja käyttäjän muunnokset Luvussa 7, "Ominaisuudet, taulukot ja indeksoijat," opit, miten luokan yhteydessä käytetään ohjelmallisesti []-operaattoria, jolloin objektia voidaan

Lisätiedot

Sisällys. Mitä on periytyminen? Yksittäis- ja moniperiytyminen. Oliot ja perityt luokat. Periytymisen käyttö. 8.2

Sisällys. Mitä on periytyminen? Yksittäis- ja moniperiytyminen. Oliot ja perityt luokat. Periytymisen käyttö. 8.2 8. Periytyminen 8.1 Sisällys Mitä on periytyminen? Yksittäis- ja moniperiytyminen. Oliot ja perityt luokat. Periytymisen käyttö. 8.2 Mitä on periytyminen? Periytyminen (inheritance) tarkoittaa luokan piirteiden

Lisätiedot

2. Olio-ohjelmoinista lyhyesti 2.1

2. Olio-ohjelmoinista lyhyesti 2.1 2. Olio-ohjelmoinista lyhyesti 2.1 Sisällys Yleistä. Oliot ja luokat. Attribuutit. Olioiden esittely ja alustus. Rakentajat. Olion operaation kutsuminen. 2.2 Yleistä Olio-ohjelmointia käsitellään hyvin

Lisätiedot

Sisällys. 15. Lohkot. Lohkot. Lohkot

Sisällys. 15. Lohkot. Lohkot. Lohkot Sisällys 15. Lohkot Tutustutaan lohkoihin. Muuttujien ja vakioiden näkyvyys sekä elinikä erityisesti operaation lohkossa. Nimikonfliktit. Muuttujat operaation alussa vai myöhemmin? 15.1 15.2 Lohkot Aaltosulkeet

Lisätiedot

Aalto Yliopisto T-106.2001 Informaatioverkostot: Studio 1. Oliot ja luokat Javaohjelmoinnissa

Aalto Yliopisto T-106.2001 Informaatioverkostot: Studio 1. Oliot ja luokat Javaohjelmoinnissa Aalto Yliopisto T-106.2001 Informaatioverkostot: Studio 1 Oliot ja luokat Javaohjelmoinnissa Vesa Laakso 22.9.2012 Sisällysluettelo Sisällysluettelo... 1 Johdanto... 2 1. Luokka... 2 2. Olio... 2 3. Luokan

Lisätiedot

ITKP102 Ohjelmointi 1 (6 op)

ITKP102 Ohjelmointi 1 (6 op) ITKP102 Ohjelmointi 1 (6 op) Tentaattori: Antti-Jussi Lakanen 20. huhtikuuta 2018 Vastaa kaikkiin tehtäviin. Tee kukin tehtävä omalle konseptiarkille. Noudata ohjelmointitehtävissä kurssin koodauskäytänteitä.

Lisätiedot

Lohkot. if (ehto1) { if (ehto2) { lause 1;... lause n; } } else { lause 1;... lause m; } 16.3

Lohkot. if (ehto1) { if (ehto2) { lause 1;... lause n; } } else { lause 1;... lause m; } 16.3 16. Lohkot 16.1 Sisällys Tutustutaan lohkoihin. Muuttujien ja vakioiden näkyvyys sekä elinikä erityisesti operaation lohkossa. Nimikonfliktit. Muuttujat operaation alussa vai myöhemmin? 16.2 Lohkot Kaarisulut

Lisätiedot

Olio-ohjelmointi Johdanto olio-ohjelmointiin

Olio-ohjelmointi Johdanto olio-ohjelmointiin Olio-ohjelmointi Johdanto olio-ohjelmointiin Ohjelmistoa kehitettäessä voidaan tunnistaa ainakin kaksi abstraktiota: prosessiabstraktio ja dataabstraktio. Prosessiabstraktio huomattiin jo varhain, koska

Lisätiedot

Oliot viestivät metodeja kutsuen

Oliot viestivät metodeja kutsuen 6. Metodit 6.1 Sisällys Oliot viestivät metodeja kutsuen. Kuormittaminen. Luokkametodit (ja -attribuutit). Rakentajat. Metodien ja muun luokan sisällön järjestäminen. 6.2 Oliot viestivät metodeja kutsuen

Lisätiedot

Lohkot. if (ehto1) { if (ehto2) { lause 1;... lause n; } } else { lause 1;... lause m; } 15.3

Lohkot. if (ehto1) { if (ehto2) { lause 1;... lause n; } } else { lause 1;... lause m; } 15.3 15. Lohkot 15.1 Sisällys Tutustutaan lohkoihin. Muuttujien ja vakioiden näkyvyys sekä elinikä erityisesti operaation lohkossa. Nimikonfliktit. Muuttujat operaation alussa vai myöhemmin? 15.2 Lohkot Aaltosulkeet

Lisätiedot

\+jokin merkki tarkoittaa erikoismerkkiä; \n = uusi rivi.

\+jokin merkki tarkoittaa erikoismerkkiä; \n = uusi rivi. 1. Johdanto 1.1 Yleistä Suurten ohjelmien organisointi vaikeaa C:ssä. 1980 Stroustrup lisäsi C:hen olio-ohjelmoinnin (OOP = Object Oriented Programming). C C++: C-ohjelma on (muutamia poikkeuksia lukuunottamatta)

Lisätiedot

Ohjelman virheet ja poikkeusten käsittely

Ohjelman virheet ja poikkeusten käsittely Ohjelman virheet ja poikkeusten käsittely 17 Ohjelman virheet ja poikkeusten käsittely Poikkeukset ovat tapa ilmoittaa virheistä ja odottamattomista tilanteista C++-ohjelmassasi. Poikkeusten käyttö virheiden

Lisätiedot

Mikä yhteyssuhde on?

Mikä yhteyssuhde on? 1 Yhteyssuhde Mikä yhteyssuhde on? Yhteyssuhde Javalla Konstruktorit set-ja get-metodit tostring-metodi Pääohjelma 1 Mikä yhteyssuhde on? Tili - : String - : double * 1 Asiakas - hetu: String - : String

Lisätiedot

Java-kielen perusteet

Java-kielen perusteet Java-kielen perusteet String-merkkijonoluokka 1 Ohjelmointikielten merkkijonot Merkkijonot ja niiden käsittely on välttämätöntä ohjelmoinnissa Valitettavasti ohjelmointikielten tekijät eivät tätä ole ottaneet

Lisätiedot

Java-kielen perusteet

Java-kielen perusteet Java-kielen perusteet Tunnus, varattu sana, kommentti Muuttuja, alkeistietotyyppi, merkkijono, Vakio Tiedon merkkipohjainen tulostaminen Ohjelmointi (ict1tx006) Tunnus (5.3) Javan tunnus Java-kirjain Java-numero

Lisätiedot

4. Olio-ohjelmoinista lyhyesti 4.1

4. Olio-ohjelmoinista lyhyesti 4.1 4. Olio-ohjelmoinista lyhyesti 4.1 Sisällys Yleistä. Oliot ja luokat. Attribuutit. Olioiden esittely ja alustus. Rakentajat. Olion operaation kutsuminen. 4.2 Yleistä Olio-ohjelmointia käsitellään hyvin

Lisätiedot

Periytyminen (inheritance)

Periytyminen (inheritance) 1 Periytyminen (inheritance) Mitä periytyminen on? Yli- ja aliluokka Konstruktorit Get- ja set-metodi Muut metodit tostring Yksinkertainen pääohjelma 1 Mitä periytyminen on? Periytymisen avulla olemassa

Lisätiedot

13 Operaattoreiden ylimäärittelyjä

13 Operaattoreiden ylimäärittelyjä 248 13 C++-kielessä voidaan operaattoreita ylimäärittää. Ylimääriteltävää operaattoria voidaan pitää ikäänkuin metodina, joka esitellään luokan esittelyssä ja määritellään luokan ulkopuolella kuten metoditkin.

Lisätiedot

Olio-ohjelmointi Geneerisyys. 1. Johdanto

Olio-ohjelmointi Geneerisyys. 1. Johdanto Olio-ohjelmointi Geneerisyys Aiemmin käsiteltiin kolme monimuotoisuuden muotoa. Tässä osassa tutustutaan niistä neljänteen geneerisyyteen. Esitys perustuu pääosin teoksen [Bud] lukuun 18. Java-kielen geneerisyyden

Lisätiedot

Mitä on periytyminen?

Mitä on periytyminen? 8. Periytyminen 8.1 Sisällys Mitä on periytyminen? Yksittäis- ja moniperiytyminen. Oliot ja perityt luokat. Filosofinen ja käytännönläheinen näkökulma periytymiseen. Periytymisen soveltaminen. 8.2 Mitä

Lisätiedot

Ohjelmointitaito (ict1td002, 12 op) Kevät Java-ohjelmoinnin alkeita. Tietokoneohjelma. Raine Kauppinen

Ohjelmointitaito (ict1td002, 12 op) Kevät Java-ohjelmoinnin alkeita. Tietokoneohjelma. Raine Kauppinen Ohjelmointitaito (ict1td002, 12 op) Kevät 2009 Raine Kauppinen raine.kauppinen@haaga-helia.fi 1. Java-ohjelmoinnin alkeita Tietokoneohjelma Java-kieli ja Eclipse-kehitysympäristö Java-ohjelma ja luokka

Lisätiedot

Informaatioteknologian laitos Olio-ohjelmoinnin perusteet / Salo 15.2.2006

Informaatioteknologian laitos Olio-ohjelmoinnin perusteet / Salo 15.2.2006 TURUN YLIOPISTO DEMO III Informaatioteknologian laitos tehtävät Olio-ohjelmoinnin perusteet / Salo 15.2.2006 1. Tässä tehtävässä tarkastellaan erääntyviä laskuja. Lasku muodostaa oman luokkansa. Laskussa

Lisätiedot

Oliosuunnitteluesimerkki: Yrityksen palkanlaskentajärjestelmä

Oliosuunnitteluesimerkki: Yrityksen palkanlaskentajärjestelmä Oliosuunnitteluesimerkki: Yrityksen palkanlaskentajärjestelmä Matti Luukkainen 10.12.2009 Tässä esitetty esimerkki on mukaelma ja lyhennelmä Robert Martinin kirjasta Agile and Iterative Development löytyvästä

Lisätiedot

Rajapinta (interface)

Rajapinta (interface) 1 Rajapinta (interface) Mikä rajapinta on? Rajapinta ja siitä toteutettu luokka Monimuotoisuus ja dynaaminen sidonta Rajapinta vs periytyminen 1 Mikä rajapinta on? Rajapintoja käytetään, kun halutaan määritellä

Lisätiedot

Ohjelmointikieli TIE Principles of Programming Languages Syksy 2017 Ryhmä 19

Ohjelmointikieli TIE Principles of Programming Languages Syksy 2017 Ryhmä 19 Ohjelmointikieli TIE-20306 Principles of Programming Languages Syksy 2017 Ryhmä 19 Juho Kärnä Ville Mäntysaari 1. Johdanto D on yleiskäyttöinen, strukturoitu, staattisesti tyypitetty, käännettävä ohjelmointikieli

Lisätiedot