C++-KIELI - Oamkjjauhiai/opetus/olio/Olio-ohjelmointi-40.pdf · 2007. 1. 5. · C++-kieli...

175
C++-KIELI Versio 4.0

Transcript of C++-KIELI - Oamkjjauhiai/opetus/olio/Olio-ohjelmointi-40.pdf · 2007. 1. 5. · C++-kieli...

Page 1: C++-KIELI - Oamkjjauhiai/opetus/olio/Olio-ohjelmointi-40.pdf · 2007. 1. 5. · C++-kieli Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved. 4 5.7.2 OSOITTIMET TIETUEESEEN.....33

C++-KIELI

Versio 4.0

Page 2: C++-KIELI - Oamkjjauhiai/opetus/olio/Olio-ohjelmointi-40.pdf · 2007. 1. 5. · C++-kieli Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved. 4 5.7.2 OSOITTIMET TIETUEESEEN.....33

C++-kieli

Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved.

1

RAJOITUKSET Kunnes toisin määrätään, tätä materiaalia voivat monistaa omaan henkilökohtaiseen käyttöön OAMK/Tekniikan yksikön opiskelijat. Tämän materiaalin käyttö kaikenlaisessa kaupallisessa toiminnassa on kielletty. Materiaalin edelleen levitys on myös kielletty. Materiaalin laittaminen imuroitavaksi esimerkiksi omille kotisivuille on kielletty. Omille kotisivuille voi laittaa ainoastaan linkin, josta pääsee sivuilleni, missä tämä materiaali on ladatavissa/imuroitavissa omalle koneelle.

Page 3: C++-KIELI - Oamkjjauhiai/opetus/olio/Olio-ohjelmointi-40.pdf · 2007. 1. 5. · C++-kieli Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved. 4 5.7.2 OSOITTIMET TIETUEESEEN.....33

C++-kieli

Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved.

2

ALKUSANAT Tämä materiaali käsittelee suurimmaksi osaksi C++-kielen keskeisiä olio-piirteitä, joitakin C++-kielen perusasioita on materiaalin alkuun sijoitettu. Lisäksi materiaalin loppuun on sijoitettu kolme osaa, jotka käsittelevät kellonajan ja tiedostojen käsittelyä sekä nimiavaruuden käyttöä. Materiaali ei ole täydellinen oppikirja, vaan se on tehty osaksi Oulun seudun ammattikorkeakoulun / Tekniikan yksikön olio-ohjelmointi –kurssin kurssimateriaalia. Materiaali on koottu monista eri lähteistä. Keskeisenä ajatuksena on ollut juuri se, että keskeisimmät olio-ohjelmoinnin piirteet on saatu esitettyä.

Page 4: C++-KIELI - Oamkjjauhiai/opetus/olio/Olio-ohjelmointi-40.pdf · 2007. 1. 5. · C++-kieli Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved. 4 5.7.2 OSOITTIMET TIETUEESEEN.....33

C++-kieli

Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved.

3

SISÄLLYSLUETTELO 1. JOHDANTO.......................................................................................................................................................................................................................7 1.1 C++....................................................................................................................................................................................................................................7 1.2 OLIO-OHJELMOINTI...................................................................................................................................................................................................8 2. C++ TYYLINEN TULOSTUS: CIN JA COUT ..............................................................................................................................................................9 2.1 COUT................................................................................................................................................................................................................................9 2.2 CIN..................................................................................................................................................................................................................................10 2.3 ESIMERKKEJÄ............................................................................................................................................................................................................11 2.3.1 HARVASTI.CPP.........................................................................................................................................................................................................11 3. EHTO- JA VERTAILULAUSEET ................................................................................................................................................................................13 3.1 TOTUUSARVOT...........................................................................................................................................................................................................13 3.2 IF-LAUSE.......................................................................................................................................................................................................................14 3.3 SWITCH-LAUSE ..........................................................................................................................................................................................................15 3.4 OPERAATTORI ?: .......................................................................................................................................................................................................16 4. SILMUKAT .....................................................................................................................................................................................................................18 4.1 FOR-SILMUKKA..........................................................................................................................................................................................................18 4.2 WHILE-SILMUKKA....................................................................................................................................................................................................18 4.3 DO-SILMUKKA............................................................................................................................................................................................................19 4.4 ESIMERKKEJÄ............................................................................................................................................................................................................20 4.4.1 LUUPPEJA.CPP.........................................................................................................................................................................................................20 4.4.2 ASCIIT.CPP................................................................................................................................................................................................................21 4.4.3 CONTINUE.CPP ........................................................................................................................................................................................................22 5. TYYPIT, MUUTTUJAT JA VAKIOT...........................................................................................................................................................................24 5.1 TYYPPIEN YLEISESITTELY ....................................................................................................................................................................................24 5.2 PERUSTIETOTYYPIT JA MERKKIJONO ..............................................................................................................................................................24 5.2.1 KOKONAISLUVUT...................................................................................................................................................................................................24 5.2.2 REAALILUVUT.........................................................................................................................................................................................................25 5.2.3 TOTUUSARVO BOOL..............................................................................................................................................................................................26 5.2.4 MERKKI .....................................................................................................................................................................................................................26 5.2.5 MERKKIJONO ..........................................................................................................................................................................................................26 5.2.6 C++-TYYLINEN STRING-MERKKIJONO............................................................................................................................................................27 5.3 VAKIOT.........................................................................................................................................................................................................................27 5.3.1 ENUM..........................................................................................................................................................................................................................27 5.3.2 CONST ........................................................................................................................................................................................................................28 5.3.3 #DEFINE .....................................................................................................................................................................................................................29 5.4 MAKRO .........................................................................................................................................................................................................................29 5.5 TAULUKKO..................................................................................................................................................................................................................30 5.6 TIETUE..........................................................................................................................................................................................................................30 5.6.1 STRUCT......................................................................................................................................................................................................................30 5.7 OSOITTIMET ...............................................................................................................................................................................................................32 5.7.1 OSOITINOPERAATTORIT .....................................................................................................................................................................................32

Page 5: C++-KIELI - Oamkjjauhiai/opetus/olio/Olio-ohjelmointi-40.pdf · 2007. 1. 5. · C++-kieli Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved. 4 5.7.2 OSOITTIMET TIETUEESEEN.....33

C++-kieli

Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved.

4

5.7.2 OSOITTIMET TIETUEESEEN................................................................................................................................................................................33 5.10 ESIMERKKEJÄ..........................................................................................................................................................................................................34 5.10.1 STRINGIT.CPP ........................................................................................................................................................................................................34 6. TUNNUKSET JA MUUTTUJAT...................................................................................................................................................................................36 6.1 TUNNUSTEN MÄÄRITTELYALUE JA NÄKYVYYSALUE..................................................................................................................................36 6.2 GLOBAALIIN MUUTTUJAAN VIITTAUS ::-OPERAATTORILLA ....................................................................................................................38 6.3 TUNNUKSEN ELINIKÄ ..............................................................................................................................................................................................38 7. VARATUT SANAT .........................................................................................................................................................................................................40 8. OPERAATTORIT...........................................................................................................................................................................................................42 9. C++-STANDARDIKIRJASTO.......................................................................................................................................................................................44 10. ESIKÄSITTELIJÄ ........................................................................................................................................................................................................46 11. OTSIKKOTIEDOSTOT ...............................................................................................................................................................................................47 11.1 C++-OTSIKKOTIEDOSTOJEN KÄYTTÖ (”UUSI TAPA”) .................................................................................................................................47 11.2 UUDISTETTUJEN C-OTSIKKOTIEDOSTOJEN KÄYTTÖ ................................................................................................................................47 11.3 VANHEMPIEN C- JA C++-OTSIKKOTIEDOSTOJEN KÄYTTÖ.......................................................................................................................47 13. FUNKTIOT....................................................................................................................................................................................................................48 13.1 MÄÄRITTELY............................................................................................................................................................................................................48 13.1.1 FUNKTION ESITTELY ..........................................................................................................................................................................................48 13.1.2 FUNKTION KUTSU ................................................................................................................................................................................................48 13.1.3 FUNKTION MÄÄRITYS.........................................................................................................................................................................................49 13.1.4 ESIMERKKEJÄ.......................................................................................................................................................................................................49 13.2 PARAMETRIT ............................................................................................................................................................................................................50 13.2.1 PERUSTYYPIT ARGUMENTTEINA....................................................................................................................................................................50 13.2.2 OSOITINPARAMETRI...........................................................................................................................................................................................51 13.2.3 TIETUETYYPPINEN PARAMETRI .....................................................................................................................................................................51 13.2.4 TAULUKKOTYYPPINEN PARAMETRI.............................................................................................................................................................52 13.3 ALIOHJELMIEN KUORMITUS (OVERLOADING).............................................................................................................................................53 13.3.1 ONGELMATILANTEITA.......................................................................................................................................................................................54 13.3.2 LUETELLUN TYYPIN (ENUM) KUORMITUS...................................................................................................................................................55 13.4 ESIMERKKEJÄ..........................................................................................................................................................................................................56 13.4.1 SUURUUS.CPP.........................................................................................................................................................................................................56 14. VIITTAUS......................................................................................................................................................................................................................59 14.1 VIITTAUSMUUTTUJA (REFERENSSIMUUTTUJA) ...........................................................................................................................................59 14.1.1 NULL-OSOITTIMET JA NULL-VIITTAUKSET ................................................................................................................................................60 14.1.2 VIITTAUS TIETUEESEEN ....................................................................................................................................................................................61 14.1.3 VIITTAUS OSOITTIMEEN....................................................................................................................................................................................61 14.2 PERUSTIETOTYYPPI MUUTTUJAPARAMETRINA (VIITTAUS-PARAMETRI)..........................................................................................62 14.2.1 VIITTAUSPARAMETRINA VÄLIAIKAINEN MUUTTUJA .............................................................................................................................63 15. DYNAAMINEN MUISTI..............................................................................................................................................................................................65 15.1 MUISTINHALLINNAN OPERAATTORIT.............................................................................................................................................................65 15.1.1 NEW-OPERAATTORI ............................................................................................................................................................................................65 15.1.2 DELETE-OPERAATTORI......................................................................................................................................................................................65 15.2 TAULUKON DYNAAMINEN KÄSITTELY............................................................................................................................................................66 15.2.1 YKSIULOTTEINEN TAULUKKO ........................................................................................................................................................................66

Page 6: C++-KIELI - Oamkjjauhiai/opetus/olio/Olio-ohjelmointi-40.pdf · 2007. 1. 5. · C++-kieli Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved. 4 5.7.2 OSOITTIMET TIETUEESEEN.....33

C++-kieli

Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved.

5

16. LUOKKA JA OLIO ......................................................................................................................................................................................................67 16.1 LUOKKA .....................................................................................................................................................................................................................67 16.2 OLIOT JA NIIDEN KOMMUNIKOINTI.................................................................................................................................................................68 16.3 VALMIIDEN LUOKKIEN KÄYTTÖ.......................................................................................................................................................................70 17. LUOKKATYYPIT (CLASS TYPES) ............................................................................................................................................................................71 17.1 YLLÄPIDETTÄVYYS JA UUDELLEENKÄYTETTÄVYYS................................................................................................................................71 17.2 LUOKAN MÄÄRITTELYSSÄ KÄYTETTÄVÄT TYYPIT ...................................................................................................................................71 17.2.1 UNION-MÄÄRE.......................................................................................................................................................................................................71 17.2.2 STRUCT-MÄÄRE....................................................................................................................................................................................................74 17.2.3 CLASS-MÄÄRE .......................................................................................................................................................................................................74 18. LUOKKAN MÄÄRITTELY.........................................................................................................................................................................................76 18.1 LUOKKATYYPPI CLASS .........................................................................................................................................................................................76 18.1.1 REKURSIO...............................................................................................................................................................................................................77 18.1.2 TYHJÄ LUOKKA ....................................................................................................................................................................................................78 18.2 ALIOHJELMAJÄSENET ..........................................................................................................................................................................................78 18.3 ESIMERKKEJÄ..........................................................................................................................................................................................................79 18.3.1 AUTO.CPP................................................................................................................................................................................................................79 18.3.2 ELAIMET.CPP.........................................................................................................................................................................................................80 19. OLIOIDEN MUISTINVARAUSLUOKAT .................................................................................................................................................................82 20. OLION LUONTI ELI TILANVARAUS......................................................................................................................................................................83 20.1 AUTOMAATTISEN OLION ESITTELY JA MÄÄRITTELY ...............................................................................................................................83 20.2 DYNAAMISEN OLION ESITTELY JA MÄÄRITTELY .......................................................................................................................................83 20.2.1 OLION ESITTELY JA MÄÄRITTELY ERIKSEEN ...........................................................................................................................................84 20.2.2 OLION ESITTELY JA MÄÄRITTELY YHTÄAIKAISESTI .............................................................................................................................84 20.3 STAATTISEN OLION ESITTELY JA MÄÄRITTELY..........................................................................................................................................85 21. OLION TILANVAPAUTUS.........................................................................................................................................................................................86 22. KONSTRUKTORI (CONSTRUCTOR) ......................................................................................................................................................................87 22.1 OLION LUONTI JA TUHOAMINEN.......................................................................................................................................................................87 22.2 OLION TIETOJÄSENTEN ALUSTUS OLETUSARVOILLA JA OLETUSMUODOSTIN................................................................................87 22.3 OLION TIETOJÄSENTEN ALUSTUS MÄÄRÄTYILLÄ ARVOILLA JA PARAMETRILLINEN MUODOSTIN ........................................91 22.4 KOPIOINTIMUODOSTIN.........................................................................................................................................................................................92 22.5 ESIMERKKEJÄ..........................................................................................................................................................................................................93 22.5.1 STACK.CPP..............................................................................................................................................................................................................93 23. HAJOTIN (DESTRUCTOR) ........................................................................................................................................................................................97 23.1 DYNAMISIA TIETOJÄSENIÄ SISÄLTÄVÄN OLION TYHJENNYS JA HAJOTIN......................................................................................100 23.2 ESIMERKKEJÄ........................................................................................................................................................................................................101 23.2.1 STACKD.CPP.........................................................................................................................................................................................................101 24. THIS-OSOITIN (THIS-POINTER, THIS-POINTTERI).........................................................................................................................................106 24.1 PARAMETRILLA JA DATAJÄSENELLÄ SAMA NIMI.....................................................................................................................................108 25. MALLIT (TEMPLATES) ...........................................................................................................................................................................................110 25.1 ALIOHJELMAMALLIT ..........................................................................................................................................................................................110 25.2 LUOKKAMALLIT (CLASS TEMPLATE) ............................................................................................................................................................111 25.3 ESIMERKKEJÄ........................................................................................................................................................................................................113 25.3.1 STACKT.CPP .........................................................................................................................................................................................................113

Page 7: C++-KIELI - Oamkjjauhiai/opetus/olio/Olio-ohjelmointi-40.pdf · 2007. 1. 5. · C++-kieli Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved. 4 5.7.2 OSOITTIMET TIETUEESEEN.....33

C++-kieli

Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved.

6

26. OPERAATTOREIDEN KUORMITUS (OPERATOR OVERLOADING) ............................................................................................................117 26.1 SYÖTTÖ- JA TULOSTUSOPERAATTORIT >> JA <<.......................................................................................................................................119 26.2 ESIMERKKEJÄ........................................................................................................................................................................................................121 26.2.1 DARRAY.CPP ........................................................................................................................................................................................................121 27. LUOKAN YSTÄVÄT (FRIEND) ...............................................................................................................................................................................127 27.1 ESIMERKKEJÄ........................................................................................................................................................................................................128 27.1.1 FRIEND01.CPP ......................................................................................................................................................................................................129 28. JOHDANTO PERIYTYMISEEN...............................................................................................................................................................................131 28.1 PERIYTYMISEN KÄYTTÖTILANTEITA............................................................................................................................................................131 28.1.2 ALILUOKAN PALVELULIITTYMÄN LAAJENTAMINEN ALILUOKAN TOTEUTTAJAN NÄKÖKULMASTA ................................134 28.1.3 TOTEUTUSTAVAN PERIYTYMINEN...............................................................................................................................................................134 28.2 YLILUOKAN MÄÄRITTELY.................................................................................................................................................................................136 28.2.1 NÄKYVYYSSÄÄNNÖT YLILUOKASSA ...........................................................................................................................................................136 28.2.2 YLILUOKAN PALVELULIITTYMÄN JA TOTEUTUKSEN PERIYTYMISEN SUUNNITTELU..............................................................136 28.3 ALILUOKAN MÄÄRITTELY.................................................................................................................................................................................137 28.3.1 ALILUOKAN METODIEN SUUNNITTELU......................................................................................................................................................138 28.4 MUODOSTIMIEN JA HAJOTTIMIEN SUORITUSJÄRJESTYS ......................................................................................................................139 28.5 YLILUOKAN MUODOSTIMEN KUTSUMINEN.................................................................................................................................................140 29. VIRTUAALINEN METODI (VIRTUAL FUNCTION) ...........................................................................................................................................143 30. TOTEUTUSTAVAN PERIYTYMINEN PROTECTED- JA PRIVATE-PERIYTYMISTAVOILLA.................................................................145 30.1 YLILUOKAN NÄKYVYYS ALILUOKAN ASIAKKAIDEN JA TOTEUTTAJAN NÄKÖKULMISTA.........................................................145 30.2 PERIYTYMISTAVAN VAIKUTUKSEN KUMOAMINEN..................................................................................................................................147 30.3 ESIMERKKEJÄ........................................................................................................................................................................................................148 30.3.1 PANKKII.CPP ........................................................................................................................................................................................................149 30.3.2 PANKKIV.CPP.......................................................................................................................................................................................................151 36. KELLONAIKA JA PÄIVÄYS....................................................................................................................................................................................155 37. TIEDOSTOT................................................................................................................................................................................................................156 37.1 BINÄÄRIMUOTOINEN TIEDOSTOJEN KÄSITTELY ......................................................................................................................................156 37.1.1 TIEDOSTON AVAUS OPEN-METODILLA.......................................................................................................................................................156 37.1.2 BINÄÄRITIEDOSTON AVAUS KIRJOITTAMISTA VARTEN......................................................................................................................157 37.1.3 BINÄÄRITIEDOSTON AVAUS LUKEMISTA VARTEN.................................................................................................................................158 37.1.4 TIEDOSTON AVAUKSEN ONNISTUMINEN ...................................................................................................................................................159 37.1.5 TIEDOSTON SULKEMINEN CLOSE-METODILLA.......................................................................................................................................160 37.1.6 BINÄÄRITIEDOSTOON KIRJOITTAMINEN WRITE-METODILLA..........................................................................................................160 37.1.7 BINÄÄRITIEDOSTOSTA LUKEMINEN READ-METODILLA .....................................................................................................................162 37.2 BINÄÄRITIEDOSTON HAJAKÄSITTELY..........................................................................................................................................................164 37.3 TEKSTITIEDOSTOJEN KÄSITTELY...................................................................................................................................................................167 38. NIMIAVARUUS (NAMESPACE)..............................................................................................................................................................................170 38.1 NIMIAVARUUDEN MÄÄRITTELY ......................................................................................................................................................................170 38.2 NIMIAVARUUDEN KÄYTTÖÖNOTTO...............................................................................................................................................................171

Page 8: C++-KIELI - Oamkjjauhiai/opetus/olio/Olio-ohjelmointi-40.pdf · 2007. 1. 5. · C++-kieli Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved. 4 5.7.2 OSOITTIMET TIETUEESEEN.....33

C++-kieli

Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved.

7

1. JOHDANTO Oliolähestymistapa (Object-oriented approach) on ajattelutapa, systeemityön lähestymistapa ja ohjelmointitekniikka. Ensimmäinen olio-ohjelmointitekniikoita sisältävä ohjelmointikieli Simula otettiin käyttöön vuonna 1967. Seuraavalla vuosikymmenellä varsinaisen lähtölaukauksen olio-ohjelmointi antoi Smalltalk, joka oli 1980-luvulla suosittu olio-ohjelmointikieli. 1990-luvulla suosituimmaksi olio-ohjelmointikieleksi on noussut C++-kieli. Toteutusvälineiden kirjo on nykyisin monipuolinen ohjelmointikielineen ja kehittimineen. Monet välineet lupaavat tukea oliolähestymistavalle. Tuen taso vaihtelee eikä oliokeskeisyys aina ole täydellistä. Lähestymistavoista uusin on oliolähestymistapa, jossa keskeisessä asemassa ovat ohjelmistokomponenttien ylläpidettävyys ja uudelleenkäytettävyys. Näitä ominaisuuksia ei ole kuitenkaan mahdollista saavuttaa ilman kunnollista suunnittelua ja tekniikoiden hallintaa silloinkaan, kun toteutus tapahtuu oliokeskeisellä ohjelmointikielellä. Miksi sitten sana "olio" on nykyaikana keskeisessä asemassa systeemityöstä ja ohjelmointivälineistä puhuttaessa ? Olioita hyödyntävään ohjelmointiin liittyy kaksi eri näkökulmaa:

• Valmiiden luokkien hyödyntäminen. • Uudelleenkäytettävien luokkien tuottaminen.

Valmiiden luokkien hyödyntäminen tarkoittaa luokkakirjaston käyttöä. Valmiita luokkia käyttäessä ohjelmoija voi luoda olioita luokkiin ja käyttää olioita pyytämällä niiltä valmiiksi määriteltyjä palveluita. Ohjelmoijan on siis tunnettava luokkakirjaston luokkarakenne ja kunkin luokan vastuulla olevat palvelut. Oliot kapseloivat sisäänsä ulospäin näkymättömän toteutustapansa. Tämä toteutustavan piilottaminen tukee ylläpidettävyyttä. Ylläpito paikallistuu perinteistä ohjelmointitapaa paremmin tiettyihin ohjelmistokomponentteihin. Uudelleenkäytettävien luokkien tuottaminen tarkoittaa luokkakirjaston rakentamista ja täydentämistä. Tällöin olemassa olevia ohjelmistokomponentteja voidaan uudelleenkäyttää kokoamalla tai periyttämällä niistä uusia komponentteja. Oliokeskeinen ohjelmisto on toistensa kanssa vuorovaikutuksessa toimivien ohjelmistokomponenttien – luokkien – kokoelma. Ohjelmistojen rakentaminen on tuottavaa, kun ohjelmistoja voidaan koota valmiista testatuista ohjelmistokomponenteista tuottamalla mahdollisimman vähän uutta ohjelmakoodia. Ohjelmistojen rakentamista voidaan verrata esim. autoteollisuuteen. Autotehtailijan ei kannata perustaa uusia tuotantolinjoja eri komponenttien, kuten renkaiden, mittareiden yms. komponenttien tuottamiseksi. Autotehtailija ostaa komponentit ja kokoaa auton valmiista komponenteista. Komponentteja hyödyntäviltä kokoajilta vaaditaan komponenttien liittämistaitoa ja komponentteja valmistavilta tuottajilta vaaditaan yksityiskohtaista tietoutta komponenttien valmistamisesta. Sama pätee ohjelmoijiin: toiset käyttävät ohjelmistokomponentteja eli luokkia ja toiset tuottavat niitä. 1.1 C++ C++ on yleiskäyttöinen, järjestelmäohjelmointiin painottuva ohjelmointikieli.

• Jonka kantakielenä on C-kieli • Joka tukee tiedon abstrahointia • Joka tukee olio-ohjelmointia • Joka tukee geneeristä ohjelmointia

Eli toisin sanoin sama asia: C++ on suunniteltu tukemaan tiedon abstrahointia, olio-ohjelmointia ja geneeristä ohjelmointia sekä perinteisiä C-ohjelmointimenetelmiä näiden rajoituksien alaisena. C-kieli on puolestaan kehitetty BCPL-kielestä. Seuraavassa kuvassa on esitetty kielet joista C++-kieli on saanut vaikutteita.

Page 9: C++-KIELI - Oamkjjauhiai/opetus/olio/Olio-ohjelmointi-40.pdf · 2007. 1. 5. · C++-kieli Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved. 4 5.7.2 OSOITTIMET TIETUEESEEN.....33

C++-kieli

Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved.

8

BCPL Algol68 Simula67 Ada CLU

C

C++

Kuva 1-1. Kielet joista C++-kieli on saanut vaikutteita. Simula67:sta C++ on saanut seuraavat piirteet:

• Luokka-käsitteen • Periytymisen • Virtuaali-funktiot

Algol68:sta C++ on saanut seuraavat piirteet:

• Operaattoreiden ylikuormitus Ada-kielestä C++ on saanut seuraavat piirteet:

• Geneerisyyttä • Luokkamallit

CLU-kielestä C++ on saanut seuraavat piirteet:

• Poikkeuskäsittelymekanismeja 1.2 Olio-ohjelmointi Olio-ohjelmointi on ohjelmointimenetelmä – paradigma tai kaava, jonka mukaisesti kirjoitetaan ohjelmia ongelmien ratkaisemiseksi. Jos termi ”olio-ohjelmointikieli” yleensä tarkoittaa jotakin, se tarkoittaa ohjelmointikieltä, jonka mekanismit tukevat olio-ohjelmointityyliä hyvin. Tärkeää on havaita seuraava ero:

”Kielen sanotaan tukevan tiettyä ohjelmointityyliä, jos sen ominaisuudet tekevät kyseisellä tavalla ohjelmoimisen mukavaksi (melko helpoksi, turvalliseksi ja tehokkaaksi). Kieli ei tue ohjelmointityyliä, jos kyseisten ohjelmien kirjoittaminen vaatii poikkeuksellisia ponnistuksia tai taitoja; se vain mahdollistaa tyylin käyttämisen.”

Voimme esimerkiksi kirjoittaa olio-ohjelmia C-kielellä, mutta se on tarpeettoman hankalaa, koska kielessä ei ole suoraa tukea tälle menetelmälle.

Page 10: C++-KIELI - Oamkjjauhiai/opetus/olio/Olio-ohjelmointi-40.pdf · 2007. 1. 5. · C++-kieli Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved. 4 5.7.2 OSOITTIMET TIETUEESEEN.....33

C++-kieli

Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved.

9

2. C++ TYYLINEN TULOSTUS: cin JA cout Pääohjelman nimi on aina ”main”. C++-kielessä pääohjelman määrittelytapoja on useita. Alkuperäisen C-kielen mukaisen pääohjelman tyyppi on ”void” mikä tarkoittaa, että funktio main ei palauta mitään kutsuvalle ohjelmalle. Voidaan ajatella, että käyttöjärjestelmä kutsuu funktiota main silloin, kun ohjelma suoritetaan tietokoneessa. C++-kielen pääohjelman rakenne on esitetty kuvassa 2-1.

int main (){

lauseet…

return 0 ;}

Kuva 2-1. Pääohjelma määrittely. C++-kielen otsikkotiedostojen käytön ”uusi tapa” on esitetty kuvassa 2-2. Uudet otsikkotiedostot eivät sisällä .h-tarkenninta. std-nimiavaruuden käyttöönotto tapahtuu ohjelmassa yhden kerran, vaikka sisällytettäviä C++-otsikkotiedostoja olisi useita.

#include <iostream>using namespace std ;

Kuva 2-2. C++-kielen otsikkotiedostojen käyttö. 2.1 cout Kuvassa 2-3 on esitetty esimerkki cout-tulostusolion käytöstä. ”cout” on tulostusolio joka symboloi ohjelmassa näyttöruutua. Tulostusoperaattorilla ”<<” siirretään tulostusvirtaan tulostettavat tekstit ym. tulostusoliolle cout. cout lausutaan ”see-aut”. cout ym. input/output –toimintoihin liittyvät asiat on määritelty tiedostossa iostream.h tai iostream riippuen siitä käytetäänkö perinteistä vai uutta nimeämistapaa.

//// eka.cpp//// C++ ohjelmissa kommentit ovat tallaisia.// Kahden perakkaisen kauttaviivan jalkeen tuleva// teksti aina rivin loppuun saakka on kommenttia.

/* Myos C-kielen tyyliset kommentit ovat sallittuja,silla C++ on laajennus C-kielesta. */

#include <iostream>using namespace std ;

int main (){

cout << "\n\n\n Hello, world. \n\n\n" ;

return 0 ;}

Kuva 2-3. cout tulostusolion käyttöesimerkki.

Page 11: C++-KIELI - Oamkjjauhiai/opetus/olio/Olio-ohjelmointi-40.pdf · 2007. 1. 5. · C++-kieli Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved. 4 5.7.2 OSOITTIMET TIETUEESEEN.....33

C++-kieli

Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved.

10

Kuva 2-4. Edellisen esimerkin tulostus.

2.2 cin C++ ohjelmissa näppäimistöltä voidaan lukea tekstiä näppäimistöä edustavan cin-olion [”see-in”] avulla (cin siis edustaa ohjelmalle näppäimistöä ja sieltä syötettävää tietovirtaa). Yleisesti ottaen kun tietovirran lukuoperaattorilla ”>>” luetaan näppäimistöoliolta cin ”tavaraa” ohjelmaan sisään, välilyönnit toimivat tavaran osien erottimina. Tämän vuoksi välilyöntejä sisältävien merkkijonojen luku ei onnistu. Em. kaltaisten stringien lukemiseen voi käyttää funktiota getline.

#include <iostream>using namespace std ;

int main (){

int Ika ;char Nimi [12] ;

cout << "Syota ika ja nimi: " ;cin >> Ika >> Nimi ;

cout << "\nNimi oli siis " << Nimi ;cout << " ja ika " << Ika ;cout << "\n" ;cout << endl ;

return 0 ;}

Kuva 2-5. Tiedon lukeminen cin-olion avulla.

Kuva 2-6. Edellisen esimerkin tulostus.

Page 12: C++-KIELI - Oamkjjauhiai/opetus/olio/Olio-ohjelmointi-40.pdf · 2007. 1. 5. · C++-kieli Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved. 4 5.7.2 OSOITTIMET TIETUEESEEN.....33

C++-kieli

Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved.

11

2.3 Esimerkkejä 2.3.1 Harvasti.cpp Tässä ohjelmassa funktiosta ”main” kutsutaan funktiota ”tulosta_harvasti”. Koska kutsuttavan funktion varsinainen ohjelmakoodi on kirjoitettu vasta kutsuvan funktion jälkeen, tulee kutsuttava funktio esitellä prototyyppinä. Huomaa myös se, että koska funktio ”tulosta_harvasti” ei palauta mitään, niin sen paluuarvon tyyppi on void (void on näennäistyyppi ja tarkoittaa tyhjää ja yms.). Samoin on huomattavaa myös se, että funktiolle ”tulosta_harvasti” välitetään yksi parametri, joka on tulostettava stringi (annettu_stringi [ ]). Eli funktio ottaa yhden argumentin joka on stringi, siis taulukko tyyppiä char. Koska taulukot eivät kopioidu kutsuttavaan ohjelmaan (funktioon), niin niiden kokoa ei tarvitse määritellä, vaan tyhjät hakasulut riittävät.

void tulosta_harvasti ( char annettu_stringi [ ] ) ;

Stringivakiot määritellään kaksoisheittomerkkien väliin. Kun stringi presidentin_rouva alustetaan samalla kun se määritellään. Kun hakasulkujen sisällä ei kerrota stringin kokoa, niin kääntäjä tekee stringistä automaattisesti niin suuren kuin sille annettaan alustuksessa merkkejä. Tässä tapauksessa stringin koko tulee olemaan 16 tavua (tila näkyville merkeille ja stringin päättävälle nollalle eli NULLille).

char presidentin_rouva [ ] = "Pertti Arajarvi" ;

#include <iostream>using namespace std ;

// Seuraava on funktion tulosta_harvasti prototyyppi.// Prototyyppi tarvitaan jos funktion ohjelmakoodi// kirjoitetaan vasta funktion kutsumisen jalkeen.void tulosta_harvasti ( char annettu_stringi [ ] ) ;

int main (){

cout << "\n Seuraavassa tulostetaan stringeja harvasti:" << "\n\n" ;

tulosta_harvasti ( "Tarja Halonen" ) ;

char presidentin_rouva [ ] = "Pertti Arajarvi" ;

cout << "\n\n" ;tulosta_harvasti ( presidentin_rouva ) ;cout << "\n\n" ;

return 0 ;}

void tulosta_harvasti ( char annettu_stringi [ ] ){

int stringi_indeksi = 0 ;

while ( annettu_stringi [ stringi_indeksi ] != 0 ){

cout << " " << annettu_stringi [ stringi_indeksi ] ;

stringi_indeksi ++ ;}

}

Kuva 2-7. Esimerkki ohjelma Harvasti.cpp.

Page 13: C++-KIELI - Oamkjjauhiai/opetus/olio/Olio-ohjelmointi-40.pdf · 2007. 1. 5. · C++-kieli Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved. 4 5.7.2 OSOITTIMET TIETUEESEEN.....33

C++-kieli

Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved.

12

Kuva 2-8. Edellisen esimerkin tulostus.

Page 14: C++-KIELI - Oamkjjauhiai/opetus/olio/Olio-ohjelmointi-40.pdf · 2007. 1. 5. · C++-kieli Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved. 4 5.7.2 OSOITTIMET TIETUEESEEN.....33

C++-kieli

Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved.

13

3. EHTO- JA VERTAILULAUSEET Ehtolausekkeita käytetään vertailu- ja toistolauseissa ohjelman suorituksen ohjaamiseksi. Ehtolausekkeet esitetään sulkeissa ja ne muodostetaan operandeista, vertailuoperaattoreista ja loogisista operaattoreista. Operandit voivat olla muuttujia, vakioita tai lausekkeita. Seuraavassa taulukossa on esitetty C++-kielen vertailuoperaattorit. Vertailuoperaattorit palauttavat totuusarvon true, jos vertailu on tosi, ja muuten arvon false.

TAULUKKOC++-kielen vertailuoperaattorit

Operaattori Merkitys= = Yhtäsuuruus! = Erisuuruus> Suurempi kuin> = Suurempi tai yhtäsuuri kuin< Pienempi kuin< = Pienempi tai yhtäsuuri kuin

Seuraavassa taulukossa on esitetty C++-kielen loogiset operaattorit.

TAULUKKOC++-kielen loogiset operaattoritOperaattori Merkitys

& & Ja| | Tai! Ei

3.1 Totuusarvot Alkuperäiset C++-kielen totuusarvot tulevat C-kielestä, jossa ehtolauseke on tosi, jos sen arvo on nollasta poikkeava. Ehtolauseke on epätosi, jos sen arvo on nolla. C++-kieleen on lisätty totuusarvotyyppi bool, jolla ilmaistaan loogisten operaatioiden tuloksia. Totuusarvotyypillä bool voi olla kaksi arvoa:

true (tosi) taifalse (epätosi)

bool- ja int-tyypit ovat yhteensopivia, true vastaa lukua 1 ja false lukua 0. Tyyppimuunnostilanteissa luku 1 muuntuu true-arvoksi ja luku 0 false-arvoksi. Tyyppimuunnos toimii myös bool-arvosta int-arvoksi.

void Funktio (int a, int b){

bool b1 = a == b ; // = tarkoittaa sijoitusta ja = = yhtäsuuruutta.// …

}

// Jos a on yhtä suuri kuin b, b1 on true; muuten b1 on false.

Kuva 3-1. Esimerkki bool-tyypistä. Määritelmän mukaan true vastaa kokonaisluvuksi muunnettuna arvoa 1 ja false arvoa 0. Vastaavasti kokonaisluvut voidaan muuntaa automaattisesti totuusarvoiksi; nollasta poikkeavasta kokonaisluvusta tulee true ja nollasta false.

Esimerkiksi:

bool b = 7 ; // bool (7) on tosi, joten b on true.int i = true ; // int (true) on 1, joten i on 1.

Page 15: C++-KIELI - Oamkjjauhiai/opetus/olio/Olio-ohjelmointi-40.pdf · 2007. 1. 5. · C++-kieli Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved. 4 5.7.2 OSOITTIMET TIETUEESEEN.....33

C++-kieli

Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved.

14

Aritmeettisissa ja loogisissa lausekkeissa totuusarvot muuttuvat int-arvoiksi, ja muunnettuja arvoja käsitellään loogisilla operaatioilla ja kokonaislukujen aritmeettisilla operaatioilla. Jos tulos muunnetaan takaisin totuusarvoksi, nollasta tulee false ja nollasta poikkeavasta arvosta true.

Esimerkki:

void Funktio ( ){

bool a = true ;bool b = true ;

bool x = a + b ; // a + b on 2, joten x on true.bool y = a / b ; // a / b on 1, joten y on true.

}

3.2 if-lause if-lausetta käytetään tiedon vertailuun. Seuraavassa on esitetty if-lauseen perusrunko.

if ( lauseke ) {lauset ;

}else {

lauset ;}

if-lauseen else-haara ei ole pakollinen. if-lausetta voidaan myös ketjuttaa seuraavaan tapaan.

if ( lauseke ) {lauset ;

}else if ( lauseke ) {

lauset ;}else if ( lauseke ) {

lauset ;}

else {lauset ;

}

Järjestelmä suorittaa ensimmäisen if-lauseen lohkossa olevat lauseet, jos lausekkeen arvo on tosi. Muussa tapauksessa järjestelmä suorittaa seuraavan if-lauseen lohkossa olevat lauseet, jos sen lohkon ehto on tosi. Jos minkään if-lauseen lohkon ehto ei ole tosi, niin sitten suoritetaan else-haaran sisältämät lauseet, jos else-haara on olemassa.

#include <iostream>using namespace std ;

int main (){

int luku ;

cout << "Syota luku: " ;cin >> luku ;

Page 16: C++-KIELI - Oamkjjauhiai/opetus/olio/Olio-ohjelmointi-40.pdf · 2007. 1. 5. · C++-kieli Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved. 4 5.7.2 OSOITTIMET TIETUEESEEN.....33

C++-kieli

Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved.

15

if (luku < 0) {luku = luku * -1 ;cout << "\nLuku on positiivisena: " << luku << "\n\n" ;

}else {cout << "\nLuku on positiivinen \n\n" ;

}

return 0 ;}

Kuva 3-2. Esimerkki if-rakenteen käytöstä.

Kuva 3-3. Edellisen esimerkin tulostus.

3.3 switch-lause switch-lauseessa haarautuminen tapahtuu tutkittavan lausekkeen vakioarvon perusteella. switch-rakenteessa tutkitaan, vastaako testattavan lausekkeen arvo yhdessäkän case-haarassa määriteltyä vakioarvoa. case-haarassa olevat lauseet suoritetaan, kunnes tulee vastaan break-lause. break-lause siirtää kontrollin switch-rakenteen loppuun. Jos case-haaran lopussa ei ole break-lausetta, ohjelman suoritus jatkuu suoraan seuraavaan case-lohkoon.

switch ( lauseke ){case :

// Lauseetbreak ;

case :// Lauseetbreak ;

case :// Lauseetbreak ;

default :// Lauseetbreak ;

}

switch-lauseella voidaan korvata ketjutetut if-lauseet. switch-lause voi sisältää useita eri vakioarvoihin liittyviä case-haaroja. Tutkittavan lauseen arvon on oltava kokonaislukutyyppiä tai siihen muunnettavaa typpiä (esim. char, bool, enum). case-haarassa ei saa esitellä sellaisia paikallisia muuttujia, jotka alustetaan määrittelyssä. Esittely ja alustus voi esiintyä erikseenkin.

#include <iostream>using namespace std ;

Page 17: C++-KIELI - Oamkjjauhiai/opetus/olio/Olio-ohjelmointi-40.pdf · 2007. 1. 5. · C++-kieli Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved. 4 5.7.2 OSOITTIMET TIETUEESEEN.....33

C++-kieli

Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved.

16

int main ( ){

char Merkki ;

cout << " Syota +, -, * tai / merkki: " ;cin >> Merkki ;

switch (Merkki){case '+' :

cout << " Merkki on + " << endl ;break ;

case '-' :cout << " Merkki on - " << endl ;

break ;case '*' :

cout << " Merkki on * " << endl ;break ;

case '/' :cout << " Merkki on / " << endl ;

break ;default :

cout << " Merkki on tuntematon !" << endl ;}return 0 ;

}

Kuva 3-5. Esimerkki switch-rakenteen käytöstä.

Kuva 3-4. Kuvan 3-5 esimerkin tulostus.

3.4 Operaattori ?: Operaattori ?: on ehto-operaattori. Ehto-operaattorissa on kolme operandia. Operaattorin rakenne on esitetty kuvasa 3-6.

Ehtolause ? Tosilauseke : Epätosilauseke

Kuva 3-6. Ehto-operaattorilauseen rakenne. Jos, Ehtolause on tosi, niin suoritetaan Tosilauseke muutoin Epätosilauseke.

#include <iostream>using namespace std ;

int main ( ){

int Luku ;int EkaLuku, TokaLuku ;

Page 18: C++-KIELI - Oamkjjauhiai/opetus/olio/Olio-ohjelmointi-40.pdf · 2007. 1. 5. · C++-kieli Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved. 4 5.7.2 OSOITTIMET TIETUEESEEN.....33

C++-kieli

Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved.

17

cout << "Syota eka luku: " ;cin >> EkaLuku ;cout << "Syota toka luku: " ;cin >> TokaLuku ;

Luku = (EkaLuku > TokaLuku) ? EkaLuku : TokaLuku ;

cout << "\nSuurempi luku on " << Luku << " tai luvut ovat yhtasuuria !\n\n" ;

return 0 ;}

Kuva 3-7. Esimerkki ehto-operaattorin käytöstä.

Kuva 3-8. Edellisen esimerkin tulostus.

Page 19: C++-KIELI - Oamkjjauhiai/opetus/olio/Olio-ohjelmointi-40.pdf · 2007. 1. 5. · C++-kieli Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved. 4 5.7.2 OSOITTIMET TIETUEESEEN.....33

C++-kieli

Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved.

18

4. SILMUKAT Silmukat (luupit) eli toistolauseet muodostetaan for-, while- tai do-lauseesta. 4.1 for-silmukka for-luuppi on tarkoitettu melko säännöllisten silmukoiden muodostamiseen. for-luuppia käytetään usein taulukoiden käsittelyssä.

for-luuppi:

for ( Aloituslauseke ; Toistoehto ; Toistolauseke){

Toistettavat lauseet ;}

Aloituslauseke sisältää sen lausekkeen, joka suoritetaan ohjelman suorituksen tullessa toistorakenteeseen. Aloituslauseke suoritetaan vain yhden kerran. Toistoehto määrää sen, kuinka monta kertaa toistettavat lauseet suoritetaan. Toistettavien lauseiden toistaminen loppuu, kun toistoehdon totuusarvo on epätosi. Toistolauseke suoritetaan jokaisen toistokerran lopuksi.

#include <iostream>using namespace std ;

int main (){

for (int i=0; i<5 ; i++) {cout << "Kierros nro.: " << i << endl ;

}

return 0 ;}

Kuva 4-1. Esimerkki for-luupista.

Kuva 4-2. Edellisen esimerkin tulostus.

4.2 while-silmukka while-luuppi on alkuehtoinen toistolause. Alkuehtoisessa toistolauseessa järjestelmä päättelee toistoehdon arvon ensin ja suorittaa sen jälkeen toistettavat lauseet, jos ehto on tosi.

while-luuppi:

Page 20: C++-KIELI - Oamkjjauhiai/opetus/olio/Olio-ohjelmointi-40.pdf · 2007. 1. 5. · C++-kieli Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved. 4 5.7.2 OSOITTIMET TIETUEESEEN.....33

C++-kieli

Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved.

19

while ( Toistoehto ){

Toistettavat lauseet ;}

Järjestelmä suorittaa toistettavia lauseita niin kauan, kunnes toistoehto on epätosi. Lauseita ei suoriteta yhtään kertaa, jos toistoehto on epätosi jo while-rakenteeseen tultaessa.

#include <iostream>using namespace std ;

int main (){

int Laskuri = 0 ;

while (Laskuri < 5){

cout << "Kierros nro.: " << Laskuri << endl ;Laskuri++ ;

}

return 0 ;}

Kuva 4-3. Esimerkki while-luupista.

Kuva 4-4. Edellisen esimerkin tulostus.

4.3 do-silmukka do-luuppi on loppuehtoinen toistolause. Loppuehtoisessa toistolauseessa järjestelmä suorittaa toistettavat lauseet ainakin yhden kerran, koska toistoehto sijaitsee toistorakenteen lopussa.

do-luuppi:

do{

Toistettavat lauseet ;}while ( Toistoehto ) ;

Toisto loppuu, kun toistoehto saa arvon epätosi. Huomattavaa on se, että lausekkeen loppusulun jälkeen on puolipiste.

Page 21: C++-KIELI - Oamkjjauhiai/opetus/olio/Olio-ohjelmointi-40.pdf · 2007. 1. 5. · C++-kieli Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved. 4 5.7.2 OSOITTIMET TIETUEESEEN.....33

C++-kieli

Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved.

20

#include <iostream>using namespace std ;

int main (){

int Laskuri = 0 ;do {

cout << "Kierros nro.: " << Laskuri << endl ;Laskuri++ ;

} while (Laskuri < 5) ;

return 0 ;}

Kuva 4-5. Esimerkki do-luupista.

Kuva 4-6. Edellisen esimerkin tulostus.

4.4 Esimerkkejä 4.4.1 Luuppeja.cpp

#include <iostream>using namespace std ;

int main (){

int tulostuslaskuri = 2 ;

cout << "\n Seuraavat 2 tulostusta tehdaan while-luupilla:\n" ;

while ( tulostuslaskuri > 0 ){

cout << "\n Hello, world. " ;tulostuslaskuri -- ;

}

cout << "\n\n Seuraavat 3 toivotusta tehdaan for-luupilla:\n" ;

for ( int toivotusten_lukumaara = 0 ; toivotusten_lukumaara < 3 ;toivotusten_lukumaara ++ )

{cout << "\n Hyvaa uutta vuotta 2000 !!! " ;

}

cout << "\n\n Seuraavat rivit tekee do-while silmukka:\n" ;

int tulostettujen_lauseiden_lukumaara = 0 ;

Page 22: C++-KIELI - Oamkjjauhiai/opetus/olio/Olio-ohjelmointi-40.pdf · 2007. 1. 5. · C++-kieli Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved. 4 5.7.2 OSOITTIMET TIETUEESEEN.....33

C++-kieli

Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved.

21

do{

cout << "\n All work and no play makes Jack a dull boy." ;tulostettujen_lauseiden_lukumaara ++ ;

} while ( tulostettujen_lauseiden_lukumaara < 4 ) ;

cout << "\n" ;

return 0 ;}

Kuva 4-7. Esimerkki ohjelma Luuppeja.cpp.

Kuva 4-8. Edellisen esimerkin tulostus.

4.4.2 Asciit.cpp

#include <iostream>using namespace std ;#include <iomanip>

int main (){

int koodeja_talla_rivilla = 0 ;cout << "\n Nakyvat ASCII-koodatut merkit valilla"

<< "\n 20H ... 7FH ovat seuraavat:\n\n" ;

for ( int numeerinen_koodi = 0x20 ; numeerinen_koodi < 0x80 ;numeerinen_koodi ++ )

{char ascii_merkki = numeerinen_koodi ;

cout << ascii_merkki << " " << hex // hex on I/O –manipulaattori.<< numeerinen_koodi << " " ;

koodeja_talla_rivilla ++ ;if ( koodeja_talla_rivilla == 8 ) {

cout << "\n" ;koodeja_talla_rivilla = 0 ;

}}return 0 ;

}

Kuva 4-9. Esimerkki ohjelma Asciit.cpp. Seuraavassa kuvassa on Asciit.cpp ohjelman aiheuttama tulostus ruudulle. Ascii-merkit ovat suurin piirtein samat kaikissa tietokoneissa välillä 20H … 7FH (0x20 … 0x7F). Ascii-merkeistä pienikoodisimmat välillä 00H … 1FH eivät ole näkyviä merkkejä vaan siellä on sellaisia koodeja kuin esimerkiksi escape-näppäimen koodi ja rivinvaihdon koodi.

Page 23: C++-KIELI - Oamkjjauhiai/opetus/olio/Olio-ohjelmointi-40.pdf · 2007. 1. 5. · C++-kieli Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved. 4 5.7.2 OSOITTIMET TIETUEESEEN.....33

C++-kieli

Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved.

22

Kuva 4-10. Edellisen esimerkin tulostus.

HUOMION ARVOISIA SEIKOJA OHJELMASSA asciit.cpp Koska ohjelmassa Asciit.cpp käytetään niin sanottua input/output manipulaattoria ”hex”, täytyy ohjelmaan inkluudata myös standardi kirjaston tiedosto iomanip tai iomanip.h, jossa input/output manipulaattorit on määritelty. Manipulaattorin ”hex” avulla kokonaisluku saadaan tulostumaan heksalukuna. Tulostettaessa operaattorin ”<<” avulla pistetään tulostusvirtaan, oliolle cout, tulostettavat tekstit. Kun ohjelmassa halutaan käyttää heksadesimaalisia arvoja, ne kirjoitetaan etuliitteen ”0x” avulla. Kääntäjälle ”0x20” tarkoittaa samaa kuin ”32”. Kun numeerinen koodi kopioidaan tyyppiä char olevaan muuttujaan, koodi saadaan tulostumaan merkkinä.

char ascii_merkki = numeerinen_koodi ;

cout << ascii_merkki << " " << hex << numeerinen_koodi << " " ;

4.4.3 Continue.cpp C++-kielessä on lause continue, jolla siirrytään silmukkalauseen loppuun. Kontrolli siirtyy siis toistoehdon vertailuun ennen kuin kaikki toistettavat lauseet on suoritettu loppuun. Seuraavassa on yksinkertainen esimerkki continue-lauseen käytöstä. Esimerkissä käytetään myös break-lausetta. break-lause keskeyttää toistolauseen. Toistolause voidaan siis keskeyttää ennen kuin toistoehdon arvo muuttuu epätodeksi. Kontrolli siirtyy tällöin toistolausetta seuraavaan lauseeseen.

#include <iostream>using namespace std ;

int main (){

char merkki ;int lkm = 0 ;

cout << "Kirjoita lause (keskeytys CTRL-C): " ;

while ( cin.get(merkki) ){

if (merkki == '.') { // Jos merkki on “.” eli piste, niin toistotbreak ; // lopetetaan break-lauseella.

}if (merkki == ' ') { // Välilyönnit ohitetaan continue-lauseen avulla.

continue ; // Laskuri lkm jää näin päivittämättä.}lkm++ ;

}

Page 24: C++-KIELI - Oamkjjauhiai/opetus/olio/Olio-ohjelmointi-40.pdf · 2007. 1. 5. · C++-kieli Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved. 4 5.7.2 OSOITTIMET TIETUEESEEN.....33

C++-kieli

Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved.

23

cout << "\nLauseessa oli yhteensa " << lkm << " kirjainta\n\n" ;

return 0 ;}

Kuva 4-11. Esimerkki ohjelma Continue.cpp.

Kuva 4-12. Edellisen esimerkin tulostus.

Page 25: C++-KIELI - Oamkjjauhiai/opetus/olio/Olio-ohjelmointi-40.pdf · 2007. 1. 5. · C++-kieli Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved. 4 5.7.2 OSOITTIMET TIETUEESEEN.....33

C++-kieli

Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved.

24

5. TYYPIT, MUUTTUJAT JA VAKIOT 5.1 Tyyppien yleisesittely C++-kielen tyypit voidaan jakaa kolmen ryhmään:

1) Perustietotyypit (Fundamental types), joihin kuuluvat • Kokonaisluvut: int, short, long • Reaaliluvut: float, double, long double • Totuusarvot: bool (Vain C++) • Merkki: char • Näennäistyyppi: void

2) Perustietotyypeistä johdetut tyypit (Derived types), joita ovat • Taulukot (Arrays): [ ] • Aliohjelmat (Functions): ( ) • Osoittimet (Pointers) muuttujaan tai olioon: * • Viittaukset (References): & (Vain C++) • Vakiot (Constant) • Osoittimet (Pointers) luokan jäseniin: ::* .* ->*

3) Luokkatyypit (Class types): class, struct, union • Valmiita luokkia standardikirjastossa ja kehitysympäristökohtaisissa luokkakirjastoissa. • Lisäksi ohjelmoijan itsensä laatimia olio-ohjelmoinnissa.

Perustietotyypit (Fundamental types) ovat kielen sisään rakennettuja valmiita tyyppejä ja niitä käytetään muuttujien määrittelyssä. Johdetut tyypit (Derived types) ovat ohjelmoijan perustietotyypeistä tai luokkatyypeistä johtamia uusia tyyppejä. Luokkatyypit (Class types) ovat tyyppejä, jotka ohjelmoija kokoaa muista tyypeistä. Luokkatyyppi voi siten sisältää erilaisia muuttujia ja aliohjelmia. 5.2 Perustietotyypit ja merkkijono Tässä on esitetty perustietotyypeistä kokonaisluvut, reaaliluvut ja merkit sekä johdettua tyyppiä oleva merkkijonon määrittely ja alustus. 5.2.1 Kokonaisluvut Kokonaislukutyyppejä ovat short, int ja long. C-kielessä kokonaislukuihin lasketaan kuuluvan myös merkki char, koska merkit tallentuvat ASCII-arvoina. Myös totuusarvo bool luetaan kokonaislukutyypiksi. Kokonaislukujen arvoalueeseen kuuluvat negatiiviset ja positiiviset luvut. Kokonaisluvut voidaan määritellä etumerkittömiksi määreellä unsigned. Tällöin arvoalueeseen kuuluvat vain positiiviset luvut.

Page 26: C++-KIELI - Oamkjjauhiai/opetus/olio/Olio-ohjelmointi-40.pdf · 2007. 1. 5. · C++-kieli Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved. 4 5.7.2 OSOITTIMET TIETUEESEEN.....33

C++-kieli

Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved.

25

Tietotyyppi Arvoalue Tarvittava tila

short -32768…32767 16 bittiä (2 tavua)

int -32768…32767 tai-2147483648… 2147483647

16 bittiä (2 tavua) tai32 bittiä (4 tavua)

long -2147483648… 2147483647 32 bittiä (4 tavua)unsigned short 0…65535 16 bittiä (2 tavua)

unsigned 0…655350…4294967295

16 bittiä (2 tavua) tai32 bittiä (4 tavua)

unsigned long 0…4294967295 32 bittiä (4 tavua)

Kuva 5-1. Kokonaislukutyyppien arvoalueet ja varaukseen tarvittava tila. Pelkkä unsigned vastaa tyyppiä unsigned int. int-tyypin arvoalueen ja tilanvarauksen koko on riippuvainen järjestelmästä. Muuttujien tilanvaraukset vaihtelevat järjestelmästä toiseen. C++ takaa kuitenkin seuraavat yleiset tilanvaraussäännöt: short varaa vähintään 16 bittiä, int-tyypin tilanvaraus on vähintään short-tyypin tilanvarauksen kokoinen, long varaa ainakin 32 bittiä ja on vähintään int-tyypin tilanvarauksen kokoinen. Kokonaislukuvakioiden esitysmuodot C++- ja C-kielissä kokonaislukuvakiot voidaan esittää kolmen lukujärjestelmän avulla: 10-järjestelmän lukuina, 8-järjestelmän lukuina tai 16-järjestelmän lukuina. 10-järjestelmä (Decimal)

• Desimaaliluvut, ensimmäinen vakio numero 1-9. • Esim 52.

8-järjestelmä (Octal) • Ensimmäinen numero 0, toinen 1-7. • Esim. 064 vastaa desimaalilukua 52. • UNIX-käyttöjärjestelmässä perinteinen tapa.

16-järjestelmä (Hexadecimal) • Ensimmäiset merkit 0x tai 0X, loput numeroita ja a-f tai A-F, jotka edustavat arvoja 10-15. • Esim. 0x34 vastaa desimaalilukua 52.

5.2.2 Reaaliluvut Reaaliluvut tallentuvat liukulukumuodossa. Liukulukutyyppejä ovat float, double ja long double. Reaalilukujen sisältö voi olla positiivinen tai negatiivinen. Liukuluku tallettaa arvon kahdessa osassa. Osat ovat mantissa ja eksponentti. Mantissa ilmoittaa merkitsevät numerot, eksponentti skaalattavan desimaalipisteen paikan. Esim mantissa 2.5 voidaan skaalata mm. luvuiksi 0.25 tai 2500 riippuen ilmoitettavasta eksponentista. Eksponentti E3 tarkoittaa samaa kuin 10 potenssiin 3 eli 10 * 10 * 10 eli 1000. Eksponentti E-1 tarkoittaa lukua 10-1. Eksponenttimuotoinen liukuluku 2.5E-1 tarkoittaa desimaalilukua 0.25 ja liukuluku eksponenttimuodossa 2.5E3 tarkoittaa reaalilukua 2500.0. Positiivinen eksponentti skaalaa desimaalipisteen oikealle ja negatiivinen eksponentti vasemmalle. Ohjelmoija voi ilmoittaa reaalilukuvakiot yhtä hyvin tutussa desimaalimuodossa kuin eksponenttimuodossakin. Eksponenttimuoto on hyödyllinen silloin, kun käsitellään erittäin suuria tai erittäin pieniä lukuja. Reaalilukujen tarvitsema tila vaihtelee järjestelmästä toiseen.

Tietotyyppi Arvoalue Tarvittava tila

float 3.4x10-38…3.4x10+38 32 bittiä (4 tavua)double 1.7x10-308…1.7x10+308 64 bittiä (8 tavua)long double 3.4x10-4932…1.1x10+4932 80 bittiä (10 tavua)

Kuva 5-2. Reaalilukujen arvoalueet ja tilanvaraus (Borland). Liukuluvun tarkkuus määräytyy luvun mantissan mukaan. Luvun mantissa siis sisältää luvun merkitsevät numerot. float-tyyppisellä luvulla mantissan pituus on vähintään 6 numeroa, double-tyyppisillä luvuilla se on vähintään 10 numeroa. Tarkkuus vaihtelee ympäristöstä toiseen. Borland-ympäristöissä float-tyyppisen luvun tarkkuus on 6 numeroa, double-tyyppisen 15 numeroa ja long double –tyyppisen luvun tarkkuus on 18 numeroa. Microsoft Visual 6.0 –ympäristössä vastaavat tarkkuudet ovat 6, 15 ja 15 numeroa.

Page 27: C++-KIELI - Oamkjjauhiai/opetus/olio/Olio-ohjelmointi-40.pdf · 2007. 1. 5. · C++-kieli Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved. 4 5.7.2 OSOITTIMET TIETUEESEEN.....33

C++-kieli

Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved.

26

Liukuluvuilla laskennassa ovat pyöristysvirheet mahdollisia. Esimerkiksi, jos talletetaan luku 12345.67891 float-tyyppiseen muuttujaan, putoaa luvun loppuosa 7891 pois, koska mantissan pituus on 6 numeroa. Reaalilukuja alustettaessa desimaaliosa erotetaan pisteellä (.). Jos desimaaliosia ei ole, pistettä ja sitä seuraavia nollia ei tarvitse alustuksessa kirjoittaa. Reaalilukuvakiot ovat tyyppiä double. Jos reaalilukuvakio halutaan float-tyyppiseksi, sen jälkeen on laitettava liite f tai F. Jos reaaliluku halutaan long double –tyyppiseksi, sen jälkeen on laitettava liite l tai L.

2.5 // Tyyppi double.2.5E2 // Tyyppi double.2.5E2f // Tyyppi float.2.4L // Tyyppi long double.

Kuva 5-3. Esimerkkejä. Kaikki järjestelmät eivät tue f-liitettä. Tällöin voi käyttää vaihtoehtoisesti tyyppimuunnosta: (float) 2.5. Uusimmissa C++-kääntäjäympäristöissä kuten Borland C++ Builder ja Microsoft Visuall C++ 6.0 on cfloat-otsikkotiedosto (C-versio float.h-otsikkotiedosto), josta voi tutkia järjestelmäkohtaiset liukulukujen mantissan ja eksponentin suurimmat ja pienimmät arvot. 5.2.3 Totuusarvo bool Totuusarvo bool on uusi tyyppi C++-standardissa. Bool-tyyppiä ei voi käyttää C-kielisissä ohjelmissa. Varattu sana bool esittelee totuusarvoisen tiedon, jonka sisältö voi olla false eli epätosi tai true eli tosi. Totuusarvon false numeerinen arvo on 0 ja totuusarvon true numeerinen arvo on 1. bool-tyyppinen tieto muuntuu siten int-tyyppiseksi. Mikä tahansa numeerinen arvo tai osoitin on muunnettavissa bool-tyyppiseksi. Nolla-arvot ja NULL-arvoiset osoittimet muuntuvat false-arvoiksi, mikä tahansa muu arvo muuntuu true-arvoksi. Varattuja sanoja true ja false voidaan käyttää ohjelmakoodissa vakioina. Totuusarvo voidaan myös tulostaa joko numeerisena tai tekstimuotoisena. 5.2.4 Merkki Merkkityyppejä ovat char ja unsigned char.

Tietotyyppi Arvoalue Tarvittava tila

char -128…127 tai 0…255 8 bittiä (1 tavua)unsigned char 0…255 8 bittiä (1 tavua)

Kuva 5-4. Merkkitiedon arvoalue ja tilanvaraus. Kaikki ASCII-merkit numerot, kirjaimet ja välimerkit voidaan esittää unsigned char –tyyppisessä muuttujassa. char-tyyppisessä muuttujassa voidaan esittää pieniä numeroita ja ASCII-merkkejä. Perustietotyypeistä char on ainut, jonka tilanvaraus vastaa tavua (8 bittiä). char-tyyppiä voidaankin käyttää tarvittaessa korvaamaan kielestä puuttuvaa byte-tyyppiä. 5.2.5 Merkkijono C-kielessä ei ole varsinaista merkkijonotyyppiä, vaan merkkijono on merkkitaulukko, jonka kukin alkio on char-tyyppinen ja viimeisen alkion sisältö on ‘\0’. Merkkijono on siis perustietotyypistä char johdettu tyyppi. Tätä johdettua tyyppiä on käytetty myös C++-kielessä. Standardointikomitea on hyväksynyt C++-standardiin myös string-luokan, joka mahdollistaa merkkijonon käsittelyn ilman taulukkokäsittelyä.

Page 28: C++-KIELI - Oamkjjauhiai/opetus/olio/Olio-ohjelmointi-40.pdf · 2007. 1. 5. · C++-kieli Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved. 4 5.7.2 OSOITTIMET TIETUEESEEN.....33

C++-kieli

Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved.

27

char Muuttuja [pituus] ;

Kuva 5-5. C-tyylisen merkkijonon määrittely merkkitaulukkona. Merkkijonomuuttujan määrittelyssä merkkijonon pituus ilmoitetaan vakiolausekkeella hakasulkeiden välissä [ ]. Pituuteen on laskettava mukaan yksi merkki merkkijonon lopetusmerkkiä ‘\0’ varten. 5.2.6 C++-tyylinen string-merkkijono C++-kielen standardiin on hyväksytty uutena tyyppinä string-luokka, joka toteuttaa merkkijonokäsittelyn. string-luokan käyttö muistuttaa jossain määrin tavallisen monista muista kielistä löytyvän merkkijonotyypin käsittelyä. Tämä tyyppi ei ole käytettävissä C-kielessä.

#include <iostream>using namespace std ;#include <string>

int main ( ){

string Etunimi = “Markku” ;string Sukunimi = “Rahikainen” ;cout << endl << Etunimi ;cout << endl << Sukunimi ;

return 0 ;}

Kuva 5-6. C++-tyylinen merkkijono string-luokalla toteutettuna.

MarkkuRahikainen

Kuva 5-7. Edellisen esimerkin tulostus. 5.3 Vakiot C++-kielessä vakioita voidaan määritellä #define-komennolla tai const ja enum märeillä. Näistä #define on esikääntäjän komento ja const ja define ovat varattuja sanoja. 5.3.1 enum Lueteltua tyyppiä enum olevat vakiot ovat arvoluettelomuotoisia vakioita. Jokainen luettelon tunnus eli symbolinen nimi omaa jonkin kokonaislukuarvon. Ellei erikseen ole määritelty, arvoluettelon vakiot ovat kokonaislukuarvoja nollasta alkaen. Jos luettelon ensimmäisen tunnuksen arvo on 0, niin seuraavan tunnuksen arvo on edellisen arvo plus 1 jne. Tunnukset erotetaan toisistaan pilkulla. Luetellulle tyypille annetaan tyyppitunnus, jonka avulla määritellään varsinainen lueteltua tyyppiä oleva muuttuja.

enum Tyyppinimi { Arvoluettelo } ;

Kuva 5-8. Luetellun tyypin määrittely.

enum Tyyppinimi MuuttujaTyyppinimi Muuttuja

Kuva 5-9. Lueteltua tyyppiä olevan muuttujan määrittely.

Page 29: C++-KIELI - Oamkjjauhiai/opetus/olio/Olio-ohjelmointi-40.pdf · 2007. 1. 5. · C++-kieli Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved. 4 5.7.2 OSOITTIMET TIETUEESEEN.....33

C++-kieli

Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved.

28

enum Tyyppinimi { Arvoluettelo } = Muuttuja ;

Kuva 5-10. Luetellun tyypin esittely ja määrittely samalla rivillä. Kuvassa 5-11 on esimerkki enum-tyypin käytöstä.

#include <iostream>using namespace std ;

enum WEEK_DAY { MO=1, TU, WE, TH, FR, SA, SU } ;

int main ( ){

WEEK_DAY Day = FR ;

cout << "\nPaivan numero on " << Day << " ! \n\n" ;cout << "\nPaivan numero on " << WEEK_DAY(5) << " ! \n\n" ;

return 0 ;}

Kuva 5-11. Esimerkki enum-tyypin käytöstä.

Kuva 5-12. Edellisen esimerkin tulostus.

5.3.2 const Varatulla sanalla const voidaan muuttujan arvo määrätä vakioksi.

const Tyyppi Tunnus = Arvo ;

Kuva 5-13. Nimetyn vakion määrittelyn syntaksi.

#include <iostream>using namespace std ;

const int MAX_ARVO = 1000 ;

int main (){

cout << "\nRaja-arvo on " << MAX_ARVO << " !\n\n" ;

return 0 ;}

Kuva 5-14. Esimerkki nimetyn vakion määrittelystä.

Page 30: C++-KIELI - Oamkjjauhiai/opetus/olio/Olio-ohjelmointi-40.pdf · 2007. 1. 5. · C++-kieli Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved. 4 5.7.2 OSOITTIMET TIETUEESEEN.....33

C++-kieli

Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved.

29

Kuva 5-15. Edellisen esimerkin tulostus.

5.3.3 #define #define-lauseella määritellään symbolisia nimiä vakioarvoille tai –lausekkeille. #define-lauseella määriteltyjen symbolisten vakioiden käyttö selventää ohjelmatekstin luettavuutta ja parantaa ylläpidettävyyttä. #define-lause on esikäsittelijän komento, joten esikäsittelijä korvaa lähdetekstistä esiintyvät symboliset nimet ko. vakioarvoilla.

#define PII 3.14

Kuva 5-16. Symbolisen vakion määrittämisen syntaksi. 5.4 Makro Makroja määritellään #define-lauseella. Makrolle voidaan välittää parametreja ja se voi palauttaa tulosparametrin. Makron nimen ja vasemman sulkeen välissä ei saa olla välilyöntiä. Esikääntäjä kopio makrossa määritellyt koodirivit siihen kohtaan missä makron nimi esiintyy ohjelmakoodissa.

#define NIMI ( Parametrit ) Makron_ohjelmakoodi

Kuva 5-17. Makron määrittelyn yleinen muoto.

#include <iostream>using namespace std ;

#define SUURIN_LUKU(Luku1, Luku2) \if (Luku1 > Luku2) \{ \

cout << "\nLuku1 eli " << Luku1 << " on suurempi !\n\n" ; \} \else \{ \

cout << "\nLuku1 eli " << Luku1 << " on suurempi !\n\n" ; \}

int main (){

SUURIN_LUKU(100,50)

return 0 ;}

Kuva 5-18. Esimerkki makron käytöstä.

Page 31: C++-KIELI - Oamkjjauhiai/opetus/olio/Olio-ohjelmointi-40.pdf · 2007. 1. 5. · C++-kieli Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved. 4 5.7.2 OSOITTIMET TIETUEESEEN.....33

C++-kieli

Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved.

30

Kuva 5-19. Edellisen esimerkin tulostus.

5.5 Taulukko Taulukko voidaan muodostaa perustietotyypeistä, tietuetyypeistä, luokkatyypistä ja johdetuista tyypeistä eli lähes kaiksita tietotyypeistä. Taulukot voivat olla yksi- tai moniulotteisia. Taulukot määritellään kirjoittamalla määrittelyssä muuttujan nimen jälkeen hakasuluissa taulukon koko (Kts. kuva 5-21).

Tyyppi Nimi [ Alkioiden_lkm. ]Tyyppi Nimi [ Rivien_lkm. ] [ Sarakkeiden_lkm. ]

Kuva 5-20. Yksi- ja kaksiulotteisen taulukon määritys.

int Taulukko [10] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 } ;int Taulukko [2][5] = { { 1, 2, 3, 4, 5 },

{ 6, 7, 8, 9, 0 } } ;

Kuva 5-21. Yksi- ja kaksiulotteisen taulukun alustus määrittelyn yhteydessä. 5.6 Tietue Tietuetyyppi on ohjelmoijan itsensä kokoama tietotyyppi. Tietuetyyppi sisältää kenttiä, jotka voivat olla joko perustietotyyppiä tai perustietotyypeistä johdettuja tyyppejä. C++-kielessä tietuetyyppejä voi määritellä varatuilla sanoilla struct tai union. 5.6.1 struct Ohjelmoijan itsensä tekemää tietuetyyppiä voidaan käyttää samaan tapaan, kuin mitä tahansa perustietotyyppiä. Tietuetyyppiä käytetään tietueiden tilanvaraukseen. Itse tietue tyyppi määritellään varatulla sanalla struct seuraavaan tapaan.

struct TIETUETYYPPI{

// Tietueen kentät.} ;

Huomattavaa on se, että tietuetyyppi ei varaa tilaa muistista, vaan vasta kun tietuetyyppiä käytetään tietueen tilan varaamiseen, niin tapahtuu tietuetyypin mukainen tilanvaraus muistista. Kuvassa 5-8 on esitetty esimerkki tietuetyypin DATE määrittelystä. Tietuetyyppi sisältää kolme kenttää (Paiva, Kuukausi ja Vuosi).

Page 32: C++-KIELI - Oamkjjauhiai/opetus/olio/Olio-ohjelmointi-40.pdf · 2007. 1. 5. · C++-kieli Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved. 4 5.7.2 OSOITTIMET TIETUEESEEN.....33

C++-kieli

Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved.

31

struct DATE{

int Paiva ;int Kuukausi ;int Vuosi ;

} ;

Kuva 5-22. Esimerkki tietuetyypin määrittämisestä. Tietuetyypin avulla voidaan määrittää tietue. Tietue on tietuetyypin mukainen tilanvaraus muistista. Tietueelle annetaan tunnus sen määrittelyn yhteydessä.

DATE Paivays ;

Kuva 5-23. Esimerkki tietueen määrittelystä. Samassa struct-määrittelyssä voidaan määritellä tietuetyyppi ja tietuemuuttuja. Tietuemuuttujia voidaan märitellä useitakin samanaikaisesti kirjoittamalla muuttujien nimet pilkuilla erotettuina ennen tietuetyypin määrityksen lopettavaa puolipistettä.

struct DATE{

int Paiva ;int Kuukausi ;int Vuosi ;

} Paivays, Viimeinen_kayttopaiva ;

Kuva 5-24. Tietuetyypin ja kahden tietuemuuttujan samanaikainen määrittäminen. struct-määrittelyssä voidaan myös jättää tietuetyypin nimeäminen pois ja määritellä pelkästään tietuemuuttuja.

struct{

int Paiva ;int Kuukausi ;int Vuosi ;

} Date ;

Kuva 5-25. Tietuetyypin määrittäminen jättämällä tietyetyypin nimi pois.

DATE Paivays = { 13, 12, 2001 } ;

Kuva 5-26. Tietueen alustaminen sen määrittelyn yhteydessä. Ohjelmassa tietueen kenttiin voidaan viitata käyttämällä .-operaattoria seuraavasti.

Paivays.Vuosi = 2002 ;

#include <iostream>using namespace std ;

struct OPPILAS{

char Nimi [40] ;char Aine [30] ;int Arvosana ;

} ;

Page 33: C++-KIELI - Oamkjjauhiai/opetus/olio/Olio-ohjelmointi-40.pdf · 2007. 1. 5. · C++-kieli Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved. 4 5.7.2 OSOITTIMET TIETUEESEEN.....33

C++-kieli

Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved.

32

struct OPPILAS Luokka [ ] ={

{ "Tarja Halonen", "C++", 1 } ,{ "Martti Ahtisaari", "C++", 2 } ,{ "Mauno Koivisto", "C++", 3 }

} ;

int main (){

for ( int i=0; i<3; i++ ){

cout << Luokka[ i ].Nimi << " " ;cout << Luokka[ i ].Aine << " arvosana " ;cout << Luokka[ i ].Arvosana << "." << endl ;

}

return 0 ;}

Kuva 5-27. Esimerkki tietueen määrittämisestä ja käytöstä.

Kuva 5-28. Edellisen esimerkin tulostus.

5.7 Osoittimet Osoittimet ovat muuttujia, joilla voidaan viitata toisiin muuttujiin epäsuorasti. Osoitin voi sisältää keskusmuistiosoitteen. PC-ympäristössä kaikki muuttujat sijaitsevat keskusmuistissa, joten jokaisella muuttujalla on oma keskusmuistiosoitteensa. Osoittimen ja sen sisältämän keskusmuistiosoitteen avulla päästään siis käsiksi muistiin talletettuun tietoon. Osoittimia käytetään mm. dynaamisessa muistinhallinnassa ja aliohjelmien parametreissa. 5.7.1 Osoitinoperaattorit Osoittimien käsittelyyn käytetään seuraavia operaattoreita:

& osoiteoperaattori* sisältöoperaattori

Osoiteoperaattorilla ’&’ saadaan selville muuttujan osoite keskusmuistissa. Sisältöoperaattorilla ’*’ päästään viittaamaan epäsuorasti muuttujan sisältöön. Sisältöoperaattorista voidaan käyttää myös nimeä epäsuoran osoituksen operaattori. Tähti * muuttujan määrittelyn yhteydessä tarkoittaa sitä, että ko. muuttuja on osoitinmuuttuja.

Page 34: C++-KIELI - Oamkjjauhiai/opetus/olio/Olio-ohjelmointi-40.pdf · 2007. 1. 5. · C++-kieli Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved. 4 5.7.2 OSOITTIMET TIETUEESEEN.....33

C++-kieli

Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved.

33

int Luku ; // Muuttujan määrittelyint Numero ; // Muuttujan määrittely

int *Osoitin ; // Osoitinmuuttujan määrittäminen

Luku = 10 ; // Sijoitetaan muuttujaan ’Luku’ sisällöksi 10.

Osoitin = &Luku ; // Sijoitetaan muuttujan ’Luku’ osoite osoitinmuuttujan// ’Osoite’ arvoksi.

*Osoitin = 20 ; // Sijoitetaan muuttujan ’Luku’ arvoksi 20.

Numero = *Osoitin ; // Sijoitetaan muuttujan ’Numero’ arvoksi 20.

Kuva 5-29. Esimerkkejä osoiteoperaattoreiden käytöstä. 5.7.2 Osoittimet tietueeseen Tietueen kenttien käsittelyyn käytetään seuraavia operaattoreita:

. piste-operaattori -> nuoli-operaattori

Piste ’.’ -operaattoria käytetään, kun tietuemuuttujaan viitataan tietuemuuttujan nimellä. Nuoli ’->’ –operaattoria käytetään, kun tietuemuuttujaan viitataan osoitinmuuttujan kautta.

struct TIME // Tietueen määrittely.{ int Hour ;

int Minute ;int Second ;

} ;

TIME Time ; // Tietuemuuttujan määritys.TIME *pAika ; // Tietueosoittimen määritys.

Time.Hour = 11 ; // Asetetaan tuntikentän arvoksi 11.

// Sijoitetaan ’pAika’ osoittimen arvoksi ’Time’-tietueen keskusmuistiosoite.pAika->Hour = 10 ; // Muutetaan ’Time’-tietueen ’Hour’-kenttä arvoon 10.

Osoitinta käytettäessä tietueen kenttään viitattaessa voidaan käyttää myös ’*’-operaattoriaseuraavasti:

(*pAika).Hour = 9 ; // Muutetaan ’Time’-tietueen ’Hour’-kenttä arvoon 9.

Kuva 5-30. Esimerkkejä tietueen kenttien osoittamisesta.

Page 35: C++-KIELI - Oamkjjauhiai/opetus/olio/Olio-ohjelmointi-40.pdf · 2007. 1. 5. · C++-kieli Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved. 4 5.7.2 OSOITTIMET TIETUEESEEN.....33

C++-kieli

Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved.

34

5.10 Esimerkkejä 5.10.1 Stringit.cpp

//// Stringit.cpp//#include <iostream>using namespace std ;

#include <iomanip>#include <string>

void tulosta_stringi_monessa_muodossa ( char annettu_stringi[] ){

cout << "\n Tekstina: " << annettu_stringi ;

cout << "\n Heksana: " << hex ;

int stringi_indeksi = 0 ;

while ( annettu_stringi[ stringi_indeksi ] != 0 ){

cout << setw ( 4 ) << (int) annettu_stringi [ stringi_indeksi ] ;

stringi_indeksi ++ ;}

cout << "\n Desim.: " << dec ;

stringi_indeksi = 0 ;

while ( annettu_stringi [ stringi_indeksi ] != 0 ){

cout << setw ( 4 ) << (int) annettu_stringi[ stringi_indeksi ] ;

stringi_indeksi ++ ;}

cout << "\n" ;}

void main(){

char formula_autoilija [ 100 ] ;

strcpy ( formula_autoilija, "Mika Hakkinen" ) ;

cout << "\n Stringin \"" << formula_autoilija<< "\" pituus on " << strlen ( formula_autoilija ) << "\n" ;

tulosta_stringi_monessa_muodossa ( formula_autoilija ) ;

char toinen_autoilija [ ] = "Mika Salo" ;

strcpy ( formula_autoilija, toinen_autoilija ) ;

tulosta_stringi_monessa_muodossa ( formula_autoilija ) ;

formula_autoilija [ 5 ] = 'X' ;formula_autoilija [ 6 ] = 0 ;

tulosta_stringi_monessa_muodossa ( formula_autoilija ) ;}

Kuva 5-31. Esimerkki stringien ja merkkitiedon käsittelystä.

Page 36: C++-KIELI - Oamkjjauhiai/opetus/olio/Olio-ohjelmointi-40.pdf · 2007. 1. 5. · C++-kieli Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved. 4 5.7.2 OSOITTIMET TIETUEESEEN.....33

C++-kieli

Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved.

35

Kuva 5-32. Edellisen esimerkin tulostus.

Page 37: C++-KIELI - Oamkjjauhiai/opetus/olio/Olio-ohjelmointi-40.pdf · 2007. 1. 5. · C++-kieli Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved. 4 5.7.2 OSOITTIMET TIETUEESEEN.....33

C++-kieli

Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved.

36

6. TUNNUKSET JA MUUTTUJAT Tunnus (Identifier) on muuttujan, vakion, aliohjelman, makron tai ohjelmoijan määrittelemän tyypin nimi. Muuttuja (Variable) on keskusmuistista varattu paikka tiedon säilyttämiseksi ohjelman suorituksen aikana. Muuttujaan viitataan tunnuksella. Lähdetekstissä käytetyt tunnukset on esiteltävä ja määriteltävä. Esiteltyä tunnusta eli nimeä voidaan käyttää lähdetekstissä. Määrittelyn jälkeen tunnusta vastaa keskusmuistiin varattu muistialue, jonka sisältöön on mahdollista viitata tunnuksen avulla. Usein, esim. muuttujien yhteydessä esittely ja määrittely tapahtuvat samanaikaisesti. Esim. int luku; esittelee luku-nimisen muuttujan ja varaa tunnusta vastaavan kokonaislukutyypin int verran keskusmuistitilaa. Tunnusta käytetään siis keskusmuistista varattuun muuttujaan viittaamiseksi. Muuttujan olemassaolo määräytyy sen muistinvarausluokan perusteella ja tunnuksen käyttömahdollisuus vaihtelee tunnuksen määrittelypaikan mukaan. Muuttujien käyttöön liittyviä ominaisuuksia ovat:

• Elinikä – kuinka kauan muuttujan tilanvaraus säilyy keskusmuistissa. • Määrittelyalue ohjelmassa – kuinka laajalla alueella tunnus näkyy käännösyksikössä. • Linkitystapa – miten tunnus näkyy eri käännösyksiköissä.

6.1 Tunnusten määrittelyalue ja näkyvyysalue Muuttujan määrittelyalue (Scope) ohjelmassa määrittelee kuinka laajalla alueella käännösyksikössä tunnus on olemassa ja missä osissa tunnusta voidaan käyttää. Määrittelyalue kertoo siis näkyvyyden eli mahdollisen viittausalueen. Määrittelyalue vaikuttaa myös muuttujan elinikään. Näkyvyysalueita ovat: lohko, aliohjelma, aliohjelman esittely, tiedosto, luokka ja nimiavaruus. Määrittelyalueet voidaan ryhmitellä seuraavasti:

• Globaali määrittelyalue (Global scope) eli tiedosto (File scope). �Tunnus näkyy kaikkialla käännösyksikössä. �Tilanvaraus on olemassa koko ohjelman suorituksen ajan (Staattinen tilanvaraus).

• Paikallinen määrittelyalue (Local scope) eli aliohjelman (Function scope) tai lohko (Block scope). �Lisäksi erotetaan aliohjelman esittelyn määrittelyalue (Function prototype scope). �Tunnus näkyy vain paikallisesti lohkossa tai aliohjelmassa. �Tilanvaraus (Oletus) on olemassa lohkon tai aliohjelman suorituksen ajan

(Automaattinen tilanvaraus). • Luokan määrittelyalue (Class scope)

�Tunnus näkyy luokan määrittelyssä esiintyvien näkyvyyssääntöjen mukaisesti. �Tilanvaraus (Oletus) on olemassa yhtä kauan kuin olio.

• Nimiavaruus (Namespace scope) �Tunnus näkyy kaikkialla, missä nimiavaruus on otettu käyttöön. �Tilanvaraus on olemassa koko ohjelman suorituksen ajan.

Lohko (Block): Lohkossa esitellyn tunnuksen viittausalue alkaa esittelykohdasta ja päättyy lohkon lopussa. Lohkossa esitelty tunnus on paikallinen lohkossa.

for (int j=0; j<10; j++){

int Luku;…

}

Page 38: C++-KIELI - Oamkjjauhiai/opetus/olio/Olio-ohjelmointi-40.pdf · 2007. 1. 5. · C++-kieli Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved. 4 5.7.2 OSOITTIMET TIETUEESEEN.....33

C++-kieli

Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved.

37

Koska Luku on paikallinen for-lauseen lohkossa, se ei ole käytettävissä enää lohkon päättävän aaltosulun jälkeen.

Aliohjelma (Function): Aliohjelman määrittely tarkoittaa aliohjelman rungon toteutusta. Aliohjelman runko sisältää aliohjelman muuttujien esittelyn ja suoritettavat lauseet. Muuttujat ja lauseet yhdistetään lohkoksi. Aliohjelman lohkon sisällä esiteltyyn muuttujaan voidaan viitata vain aliohjelman lohkon sisällä. Aliohjelman lohkossa voidaan viitata myös aliohjelman parametriluettelossa esiteltyyn tunnukseen. Aliohjelman muuttujat ovat paikallisia (Local).

void Vaihda (int *PtrA, int PtrB) // PtrA ja PtrB ovat paikallisia{ // aliohjelmassa.

int Apu ;Apu = *PtrA ;*PtrA = *PtrB ;*PtrB = Apu ;

}

Muuttujat PtrA, PtrB ja Apu ovat paikallisia Vaihda-aliohjelmassa, joten ne eivät ole käytettävissä enää aliohjelman päättävän aaltosulun jälkeen. Aliohjelman esittely (Function prototype): Aliohjelman esittelyrivillä oleviin parametreihin ei voi muualla viitata.

void Vaihda (int *PtrA, int PtrB) ;

int main (){

// Main ei voi viitata PtrA- ja PtrB –muuttujiin.return 0 ;

}

Koska aliohjelman esittelyssä lueteltuihin tunnuksiin PtrA ja PtrB ei ole mahdollista viitata, niillä ei ole varsinaista merkitystä. Tällöin tunnusten nimet voidaan jättää pois parametriluettelosta. Parametrien tyypit on kuitenkin merkittävä luetteloon pilkuilla erotettuina. Ohjelmatiedosto (File): Globaalit (Global) tunnukset esitellään lohkojen ja luokkien ulkopuolella. Globaalien tunnusten viittausalue alkaa esittelykohdasta ja päättyy ohjelmatiedoston lopussa.

#include <iostream>using namespace std ;

int Globaali = 10 ;

int main ( ){

cout << Globaali ;

return 0 ;}

Main ohjelman yläpuolella esitelty Globaali-muuttuja on käytettävissä missä tahansa lähdetekstissä. Siihen voidaan viitata main-ohjelman sisällä ja myös kaikissa samassa lähdetekstissä (tiedostossa) sijaitsevissa aliohjelmissa.

Luokka (Class): Luokassa esiteltyjä tietoja on mahdollista käsitellä vain luokan aliohjelmilla (Oletusarvoisesti). Aliohjelmiin voidaan yleensä viitata luokan ulkopuolelta luokan olion kautta. Lisää luokan viittausalueista ja käytöstä kts. muut dokumentit.

Page 39: C++-KIELI - Oamkjjauhiai/opetus/olio/Olio-ohjelmointi-40.pdf · 2007. 1. 5. · C++-kieli Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved. 4 5.7.2 OSOITTIMET TIETUEESEEN.....33

C++-kieli

Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved.

38

Nimiavaruus (Namespace): Nimiavaruus on uusi tunnusten esittelyalue. Nimiavaruutta käyttämällä voidaan poistaa suurissa järjestelmissä nimikonflikteja. Sama tunnus voi esiintyä eri nimiavaruuksissa ja yksilöityy nimiavaruuden perusteella. Nimiavaruudesta lisää kts. dokumentti namespace. Tunnuksen näkyvyysalue eli viittausalue (Visibility) tarkoittaa sitä aluetta lähdetekstissä, jossa voidaan tehdä laillinen viittaus tunnukseen sidottuun muuttujaan tai olioon.Tunnukset ovat globaaleja tai paikallisia viittausalueellaan. Näkyvyys- eli viittausalue on yleensä sama kuin määrittelyalue. Näin ei ole, jos samanniminen tunnus on esitelty sisäkkäisissä lohkoissa.

#include <iostream>using namespace std ;

int main ( ){

int Luku = 10 ;

cout << Luku << “ “ ; // Tulostuu 10.

if (Luku > 2){

int Luku = 5;cout << Luku << “ “ ; // Tulostuu 5.

}

cout << Luku ; // Tulostuu 10.

return 0 ;}

Kuva 6-1. Samannimisen muuttujan määrittely sisäkkäisissä lohkoissa. 6.2 Globaaliin muuttujaan viittaus ::-operaattorilla Jos aliohjelmassa on esitelty samanniminen muuttuja kuin tiedoston viittausalueella oleva globaali muuttuja, voidaan aliohjelmassa viitata globaaliin muuttujaan ::-operaattorin avulla. Jos aliohjelmassa ei ole globaalin muuttujan kanssa samannimistä tunnistetta, ei ::-operaattoria tarvitse käyttää. Seuraavassa esimerkki globaalin muuttujan käsittelystä.

#include <iostream>using namespace std ;

int Luku = 10 ;

int main ( ){

int Luku = 5;

cout << Luku << ” ” ; // Tulostuu 5.cout << ::Luku ; // Tulostuu 10.

return 0 ;}

Kuva 6-2. Samannimisen muuttujan määrittely sisäkkäisissä lohkoissa. 6.3 Tunnuksen elinikä Tunnuksen elinikä (Duration) eli tilanvaraus määrittelee ajanjakson, jonka aikana esiteltyä tunnusta vastaa varattu alue keskusmuistissa. Elinikä määräytyy tunnuksen muistinvarausluokan (Storage class) perusteella. Elinikään vaikuttavia muistinvarausluokkia on kolmenlaisia: automaattinen, staattinen ja dynaaminen. Muistinvarausluokka vaikuttaa myös muuttujan näkyvyyteen.

Page 40: C++-KIELI - Oamkjjauhiai/opetus/olio/Olio-ohjelmointi-40.pdf · 2007. 1. 5. · C++-kieli Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved. 4 5.7.2 OSOITTIMET TIETUEESEEN.....33

C++-kieli

Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved.

39

Järjestelmä käyttää pääasiassa kolmea erilaista keskusmuistialuetta, jotka vastaavat muuttujien muistinvarausluokkia. Muuttujan elinikä voi olla:

• Automaattinen (Automatic) �Muuttujien tilanvaraus pinosta (Stack) tai joskus pyydettäessä rekisteristä (Register). Pino on

keskusmuistialue, jonne järjestelmä tallettaa ohjelman suorituksen ajaksi ohjelmassa määritellyt automaattiset muuttujat ja oliot. �Muuttujien tilanvaraus ja vapautus tapahtuu automaattisesti lohkoissa ja aliohjelmissa.

• Staattinen (Static) �Muuttujien tilanvaraus staattisesta muistista. �Muuttujien tilanvaraus tapahtuu ohjelman käynnistyessä ja on voimassa ohjelman päättymiseen

asti. • Dynaaminen (Dynamic)

�Muuttujien tilanvaraus dynaamisesta muistista eli keosta (Heap). Keko on tietokoneen vapaa muistialue (Free store), joka on käytettävissä mistä tahansa ohjelmasta. �Muuttujien tilanvaraus tapahtuu ohjelmoijan toimesta varatulla sanalla new ja tilanvapautus

varatulla sanalla delete tai ohjelman päättyessä (tai kunnes keskusmuistista katkaistaan virta). Automaattiset tunnukset Automaattinen (Automatic) tunnus on paikallinen lohkossa tai aliohjelmassa. Automaattinen tunnus on siten näkyvä vain kyseisessä lohkossa tai aliohjelmassa. Järjestelmä varaa tällaiselle tunnukselle muistitilan ajonaikaisesta pinosta (Stack) lohkoon tai aliohjelmaan tultaessa. Automaattisen tunnuksen tilanvaraus on olemassa niin kauan kuin sille on varattu tila pinosta. Tila vapautuu automaattisesti lohkosta tai aliohjelmasta poistuttaessa. Ohjelmoijan on alustettava automaattiset muuttujat, muuten niiden sisältö ei ole ennustettavissa. Tunnus voidaan määritellä automaattiseksi auto-määreellä. Lohkon ja aliohjelman sisäiset muuttujat ovat oletusarvoisesti automaattisia, joten niiden yhteydessä auto-määreen käyttö on turhaa. Stattiset tunnukset Staattisia (Static) tunnuksia ovat kaikki globaalit tunnukset, extern-määreellä esitellyt ulkoiset tunnukset ja static-määreellä esitellyt paikalliset tunnukset. Järjestelmä varaa staattisille tunnuksille tilan pääohjelman käynnistyessä. Muistitila pysyy varattuna koko suorituksen ajan, vaikka staattinen tunnus olisi esitelty paikalliseksi aliohjelmassa. Järjestelmä alustaa staattiset muuttujat nollalla, jos ohjelmoija ei ole alustanut muuttujia. Staattiset muuttujat alustuvat vain kerran, tilanvarauksen yhteydessä. Täten alustus ei tapahdu uudelleen aliohjelmaan tultaessa, vaikka staattinen muuttuja olisi paikallinen aliohjelmassa. Aliohjelmassa määritellyn staattisen muuttujan arvo säilyy aliohjelmasta poistumisen jälkeenkin. Kun aliohjelmaan seuraavan kerran tullaan, on muuttujassa sen arvo, joka siihen jäi edellisen kerran aliohjelmasta poistuttaessa. Dynaamiset tunnukset Dynaamiset (Dynamic) tunnukset ovat tunnuksia, joita vastaavien muuttujien ja olioiden tilanvaraushetken ja tilanvapautushetken ohjelmoija päättää. Ohjelmoijan on varattava dynaamisille muuttujille ja olioille tila ohjelmassa new-operaattorilla ja vastaavasti tila on vapautettava delete-operaattorilla. Järjestelmä varaa ajon aikana dynaamiselle muuttujalle tai oliolle muistitilan keosta (Heap). Dynaamisesti varattuun muuttujaan tai olioon viitataan ohjelmassa osoitinmuuttujan avulla. Samaan muuttujaan tai olioon saattaa viitata useita osoittimia samanaikaisesti. Osoittimille varataan tila erikseen sen oman muistinvarausluokan mukaisesti.

Page 41: C++-KIELI - Oamkjjauhiai/opetus/olio/Olio-ohjelmointi-40.pdf · 2007. 1. 5. · C++-kieli Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved. 4 5.7.2 OSOITTIMET TIETUEESEEN.....33

C++-kieli

Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved.

40

7. VARATUT SANAT Varattu sana (Reserved identifier) on ilmaisu, jolla on tietty merkitys ohjelmassa. Varattu sana on kääntäjän tuntema lause, määre tai operaattori. Varattu sana voi aloittaa esim. valinta- tai toistolauseen. Määreitä (specifiers) käytetään yleensä tietotyyppien, muuttujien, olioiden ja aliohjelmien esittelyn yhteydessä. Operaattori (Operator) on varattu sana tai merkintätapa, jota käytetään lausekkeen osana. Seuraavassa taulukossa on lueteltu C++-kielen varatut sanat. Lihavoidulla tekstityypillä esitetyt sanat ovat käytettävissä ainoastaan C++-kielisessä lähdetekstissä. Varattuja sanoja on yhteensä 62, joista 30 on ainoastaan C++-kielisissä lähdeteksteissä käytettäviä. Varatut sanat on kirjoitettava aina pienillä kirjaimilla. Varattuja sanoja käytettäessä on muistettava, että sama sana ei välttämättä tarkoita samaa asiaa C-kielessä ja C++-kielessä. Esimerkiksi sana struct tarkoittaa C-kielessä tietuetta ja C++-kielessä luokkaa. Samoin on muistettava, että saman varatun sanan esiintyminen eri yhteyksissä tarkoittaa eri asioita. Esimerkiksi varattuja sanoja private, protected ja public käytetään luokan jäsenten näkyvyyssääntöjen määräämisessä ja luokan perintätavan määräämisessä.

TAULUKKOC++-kielen varatut sanat

asm float staticauto for static_castbreak friend structbool goto switchcase if templatecatch inline thischar int throwclass long trueconst mutable tryConst_cast namespace typedefContinue new typeiddefault operator typenamedelete private uniondo protected unsignedDouble public usingdynamic_cast register virtualelse reinterpret_cast voidenum return volatileExplicit short wchar_textern signed whilefalse sizeof

Edellä olevassa taulukossa luetellut varatut sanat ryhmiteltyinä aiheluokittain:

• Muistimääreet (Storage-class specifiers) ilmoittavat kääntäjälle esiteltävän muuttujan, olion tai aliohjelman eliniän ja näkyvyyden. Muistimääreitä ovat auto, register, static ja extern.

• Aliohjelmien esittelyyn liittyviä määreitä (Function specifiers) ovat friend, inline ja virtual. • Tyyppimääreitä (Type specifiers) ovat bool, char, short, int, long, signed, unsigned, float, double, void,

wchar_t, enum, class, struct, union, const, mutable ja volatile. • Varatut sanat true ja false ovat bool-tyyppisen tiedon totuusarvoja. • Tunnusten näkyvyyteen voidaan vaikuttaa varatuilla sanoilla namespace ja using. • Aliohjelma- ja luokkamallien määrittelyssä käytetään määrettä template. • Tyypin uudelleennimeämisessä käytetään määrettä typedef. • Luokan olioihin liittyviä tyyppimuunnoksia voidaan rajoittaa varatulla sanalla explicit. • Luokan aliohjelmissa voidaan käyttää this-osoitinta, kun halutaan viitata käsiteltävän olion osoitteeseen. • Luokkien esittelyn yhteydessä käytettäviä saantimääreitä (Access specifiers) ovat private, protected ja

public. • Lauseita muodostetaan varatuilla sanoilla asm, break, case, catch, continue, default, do, else, for, goto,

if, return, switch, throw, try ja while. • Varattua sanaa asm käytetään assembler-käskyn suorittamiseen.

Page 42: C++-KIELI - Oamkjjauhiai/opetus/olio/Olio-ohjelmointi-40.pdf · 2007. 1. 5. · C++-kieli Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved. 4 5.7.2 OSOITTIMET TIETUEESEEN.....33

C++-kieli

Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved.

41

Varatut sanat const_cast, delete, dynamic_cast, new, reinterpret_cast, sizeof ja static_cast ovat operaattoreita. Operaattorimerkkien kuormituksen yhteydessä aliohjelmissa käytetään varattua sanaa operator.

Page 43: C++-KIELI - Oamkjjauhiai/opetus/olio/Olio-ohjelmointi-40.pdf · 2007. 1. 5. · C++-kieli Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved. 4 5.7.2 OSOITTIMET TIETUEESEEN.....33

C++-kieli

Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved.

42

8. OPERAATTORIT Operaattori (Operator) on merkintätapa, jota käytetään lausekkeen osana. Operaattori muodostaa arvon operandien arvojen perusteella. Operaattorit ovat:

• Yksioperandisia (Unary operator): käsittelevät yhtä operandia. • Kaksioperandisia (Binary operator): käsittelevät kahta operandia. • Kolmioperandisia (Ternary operator): Käsittelevät kolmea operandia.

Seuraavassa taulukossa on lueteltu merkit ja merkkiyhdistelmät, joita käytetään operaattoreina. Operaattorit on lueteltu taulukossa suoritusjärjestyksessä. Suoritusjärjestyksessä samanarvoiset operaattorit on esitetty ryhmänä ja eroteltu muista operaattoriryhmistä väliviivoilla ja ryhmänumeroinnilla. Jos samassa lausekkeessa esiintyy suoritusjärjestyksessä samanarvoisia operaattoreita, järjestelmä suorittaa operaattorit vasemmalta oikealle, paitsi operaattoriryhmissä 3, 15 ja 16, joissa suoritusjärjestys on oikealta vasemmalle.

TAULUKKO Operaattorit

Ryhmä Operaattori Nimi tai merkitys Syntaksiesimerkki 1 :: Viittaus luokan jäseneen. luokka::jäsen :: Viittaus globaaliin muuttujaan. ::muuttuja 2 . Viittaus olion jäseneen. olio.jäsen -> Viittaus jäseneen osoittimella. osoitin->jäsen [ ] Viittaus taulukon alkioon. osoitin [lauseke] ( ) Aliohjelmakutsu lauseke(lausekkeet) ( ) Arvon laskenta. tyyppi (lauseke) ++ Operandin käyttö ja kasvatus. operandi ++ - - Operandin käyttö ja vähennys. operandi - - typeid( ) Tyypin nimi. const_cast Tyyppimuunnos dynamic_cast Tyyppimuunnos reinterpret_cast Tyyppimuunnos static_cast Tyyppimuunnos 3 sizeof Olion tilanvarauksen koko tavuina. sizeof lauseke sizeof( ) Tyypin tilanvarauksen koko tavuina. sizeof (tyyppi)

++ Operandin kasvatus ja käyttö. ++ operandi - - Operandin vähennys ja käyttö. - - operandi ~ Komplementti (Bittioperaattori). ~lauseke ! Looginen ei. !lauseke

- Etumerkki -lauseke + Etumerkki +lauseke & Osoiteoperaattori &operandi * Sisältöoperaattori *lauseke new Tilan varaus. new tyyppi delete Tilan vapautus. delete osoitin delete [ ] Taulukon tilan vapautus. delete [ ] osoitin (tyyppi) Tyyppimuunnos (tyyppi) lauseke 4 .* Viittaus luokan jäseneen. olio.*osoitin jäseneen ->* Epäsuora viittaus jäseneen. osoitin->*osoitin jäs. 5 * Kertolasku lauseke * lauseke / Jakolasku lauseke / lauseke % Jakojäännös lauseke % lauseke 6 + Yhteenlasku lauseke + lauseke

Page 44: C++-KIELI - Oamkjjauhiai/opetus/olio/Olio-ohjelmointi-40.pdf · 2007. 1. 5. · C++-kieli Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved. 4 5.7.2 OSOITTIMET TIETUEESEEN.....33

C++-kieli

Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved.

43

- Vähennyslasku lauseke – lauseke 7 << Siirto vasemmalle. lauseke << lauseke >> Siirto oikealle. lauseke >> lauseke 8 < Pienempi kuin. lauseke < lauseke <= Pienempi tai yhtä suuri. lauseke <= lauseke > Suurempi kuin. lauseke > lauseke >= Suurempi tai yhtäsuuri. lauseke >= lauseke 9 == Yhtäsuuri kuin. lauseke == lauseke

!= Eri suuri kuin. lauseke != lauseke 10 & Ja (Bittioperaattori). lauseke & lauseke 11 ^ Poissulkeva tai (Bittioperaattori). lauseke ^ lauseke 12 | Tai (Bittioperaattori). lauseke | lauseke 13 && Ja (Looginen operaattori). lauseke&&lauseke 14 || Tai (Looginen operaattori). lauseke || lauseke 15 = Sijoitus operandi = lauseke *= Kertolasku ja sijoitus. operandi *= lauseke /= Jakolasku ja sijoitus. operandi /= lauseke %= Jakojäännös ja sijoitus. operandi%=lauseke += Yhteenlasku ja sijoitus. operandi+=lauseke -= Vähennyslasku ja sijoitus. operandi -= lauseke <<= Siirto vasemmalle ja sijoitus. operandi<<=lauseke >>= Siirto oikealle ja sijoitus. operandi>>=lauseke &= Ja ja sijoitus (Bittioperaattori). operandi&=lauseke |= Tai ja sijoitus (Bittioperaattori). operandi |= lauseke ^= Poissulkeva tai ja sijoitus

(Bittioperaattori). operandi^=lausek 16 ? : Ehtolauseke lauseke ? lauseke lauseke 17 throw Poikkeus throw lausek 18 , Pilkku

Edellisessä taulukossa sana operandi tarkoittaa lauseketta, joka viittaa muistialueeseen, jossa muuttuja, olio tai aliohjelma sijaitsee. Operandi on siis yleensä tunnus, jota voidaan käyttää sijoituksessa vasemmalla puolella. Tässä tarkoitettu operandi tunnetaan vieraskielisissä kirjoissa yleensä nimellä lvalue. Jos samassa lausekkeessa on useita suoritusjärjestyksessä samanarvoisia operaattoreita, lausekkeen arvo lasketaan yleensä vasemmalta oikealle. Poikkeuksia ovat yksioperandiset operaattorit (Ryhmä 3), arvonmuunto-operaattorit (Ryhmä 15) =, *=, /=, %=, +=, -= ja bittioperaattorit <<=, >>=, &=, <= ja ^= sekä ehto-operaattori ? :, joita käytettäessä lausekkeen arvon laskenta tapahtuu oikealta vasemmalle. Ohjelmoija voi vaikuttaa sulkeilla ( ) laskentajärjestykseen. Huom ! Käytä sulkeita ( ) epäselvyyksien välttämiseksi.

Page 45: C++-KIELI - Oamkjjauhiai/opetus/olio/Olio-ohjelmointi-40.pdf · 2007. 1. 5. · C++-kieli Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved. 4 5.7.2 OSOITTIMET TIETUEESEEN.....33

C++-kieli

Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved.

44

9. C++-STANDARDIKIRJASTO C++-standardikirjasto (C++ Standard Library) sisältää 49 otsikkotiedostoa. Standardikirjasto sisältää luokkia ja algoritmeja mm. merkkijonojen ja tietovirtojen käsittelyä varten sekä kirjaston erilaisten kokoelmien käsittelyä varten. Kokoelmien käsittelyyn liittyvä kirjasto on nimeltään STL (Standard Template Library). STL-kirjastoon liittyy 13-erillistä otsikkotiedostoa. Standardikirjasto sisältää 18 otsikkotiedostoa, jotka on muokattu suoraan C-kielen vastaavista otsikkotiedostoista uudelleennimeämällä ja mahdollisesti vähäisiä muutoksia tehden. Nämä otsikkotiedostot alkavat alla olevassa taulukossa kohdasta <cassert> ja päättyvät kohtaan <cwctype>. Esimerkiksi <cassert> sisältää merkinnän: namespace std { #include <assert.h> };. Merkintä lisää C-kielisen <assert.h> tiedoston sisällön C++:n std-nimiavaruuteen. Muut kuin c-alkuiset otsikkotiedostonimet tarkoittavat C++-kielen otsikkotiedostoja, joista suuri joukko on myös uudelleennimettyjä standardoinnin yhteydessä. Otsikkotiedostojen nimissä oli aiemmin tarkennin .h, joka on sittemmin poistettu käytöstä. Seuraavassa taulukossa on lueteltu standardikirjaston otsikkotiedostot.

TAULUKKOC++ Standardikirjaston otsikkotiedostot

Otsikkotiedosto Sisällön tarkoitus

<algorithm> STL: algoritmit<bitset> Malliluokan määrittely bittikäsittelyä varten.<cassert> Suoritusaikaisten poikkeustilanteiden käsittely.<cctype> Merkkitiedon luokittelu.<cerrno> Kirjastoaliohjelmien virhekoodien testaus.<cfloat> Liukulukujen käsittely.<ciso646> ISO 646 –merkistön käyttö ohjelmoinnissa.<limits> Kokonaislukutyyppien ominaisuuksien selvitys.<clocale> Sovitus eri kulttuureihin.<cmath> Matemaattisten aliohjelmien käyttö.<ccomplex> Kompleksilukujen käyttö.<csetjmp> Ei-paikalisten goto-lauseiden suoritus.<csignal> Erilaisten poikkeustilanteiden käsittely.<cstdarg> Parametrien käsittely.<cstddef> Tyyppien ja makrojen määrittely.<cstdio> Syöttö ja tulostus.<cstdlib> Erilaisia operaatioita (cmalloc, calloc, realoc, free, …).<cstring> Erilaisten merkkijonojen käsittely.<ctime> Aika- ja päivämääräkäsittely.<cwchar> Merkkijonojen käsittely (wide char).<cwctype> Merkkien (wide char) luokittelu.<deque> STL: jonon toteutus.<exception> Poikkeuskäsittely<fstream> Tiedostojen käsittely.<functional> STL: algoritmeissa käytettävien aliohjelmaolioiden

määrittely.<iomanip> Iostream-luokkien parametreinaan käyttämiä syöttö- ja

tulostus manipulaattoreita.<ios> <ios> Iostream-luokkien yliluokka.<iosfwd> Iostream-luokkien tarvitsemia luokkia.<iostream> Standardivirtoja käsittelevät iostream-oliot.<istream> Syöttövirtojen käsittely.<iterator> STL: iteraattoreiden käsittely.<limits> Numeeristen tyyppien tutkiminen.<list> STL: listan toteutus.<locale> Useita luokkia paikallisen tiedon käsittelyä varten.<map> STL: avainrakenteisen map-kokoelman määrittely.<memory> STL: kokoelmien muistinkäsittely.<numeric> STL: numeerisia aliohjelmia.<ostream> Tulostusvirtojen käsittely.<queue> STL:jonojen toteutus.<set> STL: yksilöivän avainrakenteisen kokoelman toteutus.<sstream> Merkkijonokokoelmien käsittely.<stack> STL: pinon toteutus.<stdexcept> Poikkeusten käsittelyyn käytettäviä luokkia.<streambuf> Iostream-käsittelyn puskurointi.<string> Merkkijonojen käittely.

Page 46: C++-KIELI - Oamkjjauhiai/opetus/olio/Olio-ohjelmointi-40.pdf · 2007. 1. 5. · C++-kieli Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved. 4 5.7.2 OSOITTIMET TIETUEESEEN.....33

C++-kieli

Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved.

45

<strstream> Merkkijonojen iostream-käsittely.<utility> STL: yleisiä apuluokkia.<valarray> Taulukoiden käyttö.<vector> STL: vektorin toteutus.

Standardikirjaston sisältämät otsikkotiedostot ovat jaettavissa neljään ryhmään: • Alkuperäiset C-kielen otsikkotiedostot.

- Päättyvät .h-tarkentimeen, esimerkiksi stdio.h. - Voidaan käyttää C- ja C++-kielisissä lähdeteksteissä.

• Uudistetut C-kielestä muokatut otsikkotiedostot. - c-etuliite, ei tarkenninta, esim. cstdio. - Voidaan käyttää C++-kielisissä lähdeteksteissä.

• Alkuperäiset C++-kielen otsikkotiedostot. - Päättyvät .h-tarkentimeen, esim. iostream.h. - Voidaan käyttää C++-kielisissä lähdeteksteissä.

• Uudistetut C++-kielen otsikkotiedostot. - Ei tarkenninta, esim. iostream. - Voidaan käyttää C++-kielisissä lähdeteksteissä std-nimiavaruuden kautta.

Ennen C++-kielen standardointia ohjelmoija on voinut sisällyttää C++-kielisiin lähdeteksteihin C- ja C++-kielen .h-tarkentimella varustettuja otsikkotiedostoja. Standardoinnin jälkeen lähdeteksteihin on voinut sisällyttää myös uudistettuja otsikkotiedostoja. Vanhemmissa ohjelmistokehitysympäristöissä ei siis ole mahdollista käyttää 1997 standardoituja otsikkotiedostojen nimiä. Uusimmissa marraskuun 1997 jälkeen julkaistuissa ohjelmistokehitysympäristöissä on mahdollisuus käyttää sekä uusia että vanhoja otsikkotiedostoja. Eri otsikkotiedostojen täydellisen ja tarkan sisällön voi tutkia ohjelmointiympäristön aputiedostoista, käsikirjoista ja help-toimintojen avulla.

Page 47: C++-KIELI - Oamkjjauhiai/opetus/olio/Olio-ohjelmointi-40.pdf · 2007. 1. 5. · C++-kieli Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved. 4 5.7.2 OSOITTIMET TIETUEESEEN.....33

C++-kieli

Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved.

46

10. ESIKÄSITTELIJÄ Esikäsittelijä eli esikääntäjä (Preprocessor, precompiler) käsittelee lähdetekstin ennen käännösvaihetta. Esikäsittelijän tehtävänä on tavallisesti tehdä erilaisia tekstin haku- ja korvaustoimintoja lähdetekstissä. Haku ja korvaus voivat olla myös ehdollisia. Esikäsittelijää ohjataan esikäsittelijän komennoilla (Directives), jotka alkavat merkillä #, jonka on oltava ensimmäinen merkitsevä merkki rivillä. Komennon kanssa samalla rivillä voi esiintyä kommenttimerkit // tai /* */. Komentoa voi myös jatkaa seuraavalle riville merkin \ jälkeen. Esikäsittelijän komentoja voi esiintyä missä tahansa lähdetekstissä. Esikäsittelijän komennoilla on oma syntaksinsa. Ohjelmoijan ei tarvitse aktivoida esikäsittelyprosessia vaan se käynnistyy automaattisesti ennen käännöstä.

TAULUKKOEsikäsittelijän komentoja

Komento Merkitys# Null-komento eli tyhjä, rivillä ei ole muita merkkejä.#define Makron ja symbolisen vakion määrittely#error Virheen raportointi käännösvaiheessa ja käännöksen keskeytys.#if, #elif, #else, #endif Ehdon vertailu.

#ifdef, #ifndefMakron ja symbolisen vakion määrittelyn olemassaolontutkiminen.

#import Tyyppikirjaston sisällyttäminen.#include Tiedostojen sisällyttäminen.#line Rivinumeron tuottaminen koodiin.#pragma Kääntäjäkohtaisia komentoja.#undef Makron ja symbolisen vakion määrittelyn purkaminen.

Esikäsittelijän komennoissa voidaan käyttää makroja. Esikäsittelijä tunnistaa joukon valmiiksi määriteltyjä makroja, jotka on lueteltu seuraavassa taulukossa. Eri ohjelmistokehitysympäristöissä on lisäksi ympäristöriippuvaisia makroja. Makrojen sisältö muuttuu esikäsittelijän komentojen tai ohjelmistokehitysympäristön asetusten mukaisesti. Makrojen nimien alussa ja lopussa on kaksi alaviivaa.

TAULUKKOEsikäsittelijän makroja

Makro Merkitys

__DATE__Käännöspäivämäärä (mmm dd yyyy). Kuukausi vastaa time.hkirjaston asctime-funktion palauttamaa kuukautta.

__FILE__ Lähdetekstitiedoston nimi lainausmerkeillä ympäröitynä.

__LINE__Lähdetekstin aktiivinen rivinumero. Rivinumeroa voidaan muuttaa#line-komennolla.

__STDC__Lähdeteksti vastaa ANSI C –standardia. Makron arvo on vakio 1,jos kääntäjän optiossa on merkintä C-kielisyydestä, muutenmakron arvo on määrittelemätön.

__TIME__ Edellisen käännöksen kellonaika (hh:mm:ss).

__TIMESTAMP__Lähdetekstin edellisen muokkauksen aikaleima. Aikaleimassa onpäivämäärä ja kellonaika.

Page 48: C++-KIELI - Oamkjjauhiai/opetus/olio/Olio-ohjelmointi-40.pdf · 2007. 1. 5. · C++-kieli Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved. 4 5.7.2 OSOITTIMET TIETUEESEEN.....33

C++-kieli

Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved.

47

11. OTSIKKOTIEDOSTOT 11.1 C++-otsikkotiedostojen käyttö (”uusi tapa”) Kun standardointikomitea tarvitsi nimiä vakiokirjastojen muutettuja versioita ja uusia toimintoja varten, syntyi ongelma. Vanhojen .h-nimien käyttäminen olisi aiheuttanut yhteensopivuusongelmia. Ratkaisu oli poistaa vakio-otsikkotiedostojen nimistä jälkiliite .h. Jälkiliite on joka tapauksessa tarpeeton, koska kulmasulkeet < > ilmaisevat, että kyseessä on vakio-otsikkotiedosto. Näiden tiedostojen esittely on sijoitettu nimiavaruuteen std. Vanhat esittelyt ovat yleisessä nimiavaruudessa ja sijaitsevat otsikkotiedostoissa, joiden jälkiliite on .h.

#include <iostream>using namespace std ;

C++-kielen standardoinnin yhteydessä C++:n otsikkotiedostoja on muokattu. Uudet otsikkotiedostot eivät sisällä .h-tarkenninta. Uudet otsikkotiedostot käyttävät nimiavaruutta std, joten se on otettava käyttöön otsikkotiedoston sisällyttämisen jälkeen. Jos std-nimiavaruutta ei oteta käyttöön, ei kääntäjä käytä iostream-kirjaston määrityksiä vaan globaalista nimiavaruudesta löytyviä määrityksiä. std-nimiavaruuden käyttöönotto tapahtuu ohjelmassa yhden kerran, vaikka sisällytettäviä C++-otsikkotiedostoja olisi useita. Tätä otsikkotiedostojen käyttötapaa ei välttämättä voi käyttää vanhemmissa (ennen standardointia julkaistuissa) ohjelmistonkehitysympäristöissä. Tuki uusimmille standardiin sisällytetyille piirteille tulee mukaan vähitellen ohjelmistokehitysympäristöihin. 11.2 Uudistettujen C-otsikkotiedostojen käyttö

#include <cctype>

c-kirjaimella alkavat otsikkotiedostot ovat uudelleennimettyjä tiedostoja, jotka sisältävät pääasiassa samat määrittelyt kuin aikaisemmat .h-tarkentimella varustetut C-kielestä peräisin olevat otsikkotiedostot. Otsikkotiedostoissa voi kuitenkin olla pieniä muutoksia C-kielisiin otsikkotiedostoihin verrattuna, joten niitä ei voi käyttää C-kielisissä ohjelmissa. Tätä otsikkotiedostojen käyttötapaa ei välttämättä voi käyttää vanhemmissa ohjelmistokehitysympäristöissä. 11.3 Vanhempien C- ja C++-otsikkotiedostojen käyttö Ennen C++-kielen standardointia otsikkotiedostot sisälsivät .h-tarkentimen. Tätä otsikkotiedostojen käyttöönottotapaa voidaan käyttää sekä vanhoissa että uusissa ohjelmistonkehitysympäristöissä.

Page 49: C++-KIELI - Oamkjjauhiai/opetus/olio/Olio-ohjelmointi-40.pdf · 2007. 1. 5. · C++-kieli Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved. 4 5.7.2 OSOITTIMET TIETUEESEEN.....33

C++-kieli

Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved.

48

13. FUNKTIOT Aliohjelmat eli funktiot voivat C++-kielessä olla joko itsenäisesti toimivia tai luokkaan liitettyjä aliohjelmia. Luokkaan liitettyjä aliohjelmia käsitellään osissa joissa käsitellään luokkia. Tässä osassa käsitellään itsenäisesti toimivia funktioita. 13.1 Määrittely Tavanomainen tapa suorittaa jokin tehtävä C++-kielisessä ohjelmassa on kutsua ko. tehtävän suorittavaa funktiota. Tehtävän suorittavalla funktiolla on selvästi määritetty rajapinta muuhun ohjelmistorakenteeseen nähden. Funktio huolehtii rajatun tehtäväkokonaisuuden suorittamisesta. Funktiolla voi olla omia funktiolohkon sisäisiä eli paikallisia muuttujia. Funktion rakenteesta ja käytöstä voidaan erottaa kolme eri osaa:

• Funktion esittely eli prototyyppi • Funktion kutsu • Funktion määrittely eli toteutus (Funktiolohkon toteutus)

13.1.1 Funktion esittely Funktion esittelyssä (Function declaration) ilmoitetaan funktion nimi, funktion palautusarvon tyyppi sekä funktion kutsuun sisällytettävien argumenttien (Eli aliohjelmalle välitettävien parametrien.) määrä ja tyypit. Funktion esittely tarvitaan, jotta kääntäjä pystyy tarkastamaan funktiokutsujen oikeellisuuden (Funktion nimi, parametrit ja paluuarvon tyyppi). Aliohjelman esittely on seuraavanlainen:

Tyyppi Aliohjelman_nimi ( Parametrit ) ;

• Aliohjelman Tyyppi: Aliohjelman return-lauseelle palauttaman tiedon tietotyyppi. return-lause suoritetaan aliohjelmassa viimeisenä, jos aliohjelma palauttaa jotain kutsuvalle ohjelmalle. • Aliohjelman_nimi: Ohjelman määrittelemä nimi aliohjelmalle. • Parametrit: Aliohjelman parametrien tyypit. Parametrien nimet voidaan myös esittää esittelyssä.

13.1.2 Funktion kutsu Aliohjelman kutsu (Function call) aiheuttaa ohjelman kontrollin siirtymisen aliohjelman lohkoon. Kun aliohjelman lohkossa olevat lauseet on suoritettu, niin kontrolli siirtyy takaisin kutsuvaan ohjelmaan. Aliohjelman kutsun on seuraavanlainen:

Aliohjelman_nimi ( Parametrit ) ;

Aliohjelmalle voidaan välittää parametreina muuttujia, vakioita ja lausekkeita. Parametrit kirjoitetaan sulkeiden sisälle pilkuilla toisistaan erotettuina. Parametrien on oltava samassa järjestyksessä, kuin ne ovat kirjoitettu aliohjelman esittelyyn. Kutsussa välitettävien parametrien nimien ei tarvitse olla samoja, mitä on käytetty aliohjelman esittelyssä. Aliohjelman kutsu, kun aliohjelma palauttaa jonkin paluuarvon:

Page 50: C++-KIELI - Oamkjjauhiai/opetus/olio/Olio-ohjelmointi-40.pdf · 2007. 1. 5. · C++-kieli Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved. 4 5.7.2 OSOITTIMET TIETUEESEEN.....33

C++-kieli

Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved.

49

tyyppi Muuttuja ;

Muuttuja = Aliohjelman_nimi ( Parametrit ) ;Aliohjelman_nimi ( Parametrit ) ;

Jos aliohjelman tyyppi on jokin muu kuin void, aliohjelma palauttaa tiedon return-lauseella, joka on aliohjelman viimeinen suoritettava lause. 13.1.3 Funktion määritys Jokainen ohjelmassa kutsuttava aliohjelma on määriteltävä jossakin yhden kerran. Aliohjelman määrittely (Function definition) on aliohjelman esittely, johon kuuluu aliohjelman runko. Aliohjelman määrittely on seuraavanlainen:

Tyyppi Aliohjelman_nimi ( Parametrit ){

MäärittelytLauseet

}

Aliohjelman tyypin, nimen ja parametrien tyyppien on vastattava aliohjelman esittelyä. Parametriluettelossa on oltava parametrien tyyppien lisäksi käytettävien parametrien nimet. Parametrien nimet ovat paikallisia aliohjelmassa, joten niiden ei tarvitse olla samoja joita käytetään aliohjelman kutsussa. Jos aliohjelman tyyppi on jokin muu kuin void, niin aliohjelman viimeisen lauseen on oltava return-lause. return-lauseen käyttö:

return Lauseke ;

13.1.4 Esimerkkejä SWAP

void swap ( int *, int * ) ; // Esittely

void swap ( int * p, int * q ) // Määrittely{

int t = *P ;

*p = *q ;*q = t ;

}

Kuva 13-1. Esimerkki swap-aliohjelma. TULOSTA Tulosta aliohjelmassa tulostetaan kutsussa välitetyn henkilön nimi ja ikä. Pääohjelma sijaitsee omassa lähdetekstitiedostossa Main.cpp. Tulosta-aliohjelma sijaitsee omassa lähdetekstitiedostossa Tulosta.cpp ja tulosta aliohjelman esittely sijaitsee otsikkotiedostossa (Header file) Tulosta.h.

Page 51: C++-KIELI - Oamkjjauhiai/opetus/olio/Olio-ohjelmointi-40.pdf · 2007. 1. 5. · C++-kieli Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved. 4 5.7.2 OSOITTIMET TIETUEESEEN.....33

C++-kieli

Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved.

50

//// Pääohjelma, Main.cpp//// (c) Markku Rahikainen 2001//#include <iostream>using namespace std ;#include "Tulosta.h" // Otsikkotiedoston mukaan ottaminen.

int main ( ){

char Nimi [20] ;int Ika ;

cout << "Syota nimi: " ;cin >> Nimi ;cout << "Syota ika: " ;cin >> Ika ;

Tulosta ( Nimi, Ika ) ;

return 0 ;}

Kuva 13-2. Pääohjelman lähdetekstitiedosto Main.cpp.

//// Tulostusohjelma, Tulosta.cpp//// (c) Markku Rahikainen 2001//#include <iostream>using namespace std ;

void Tulosta ( char HenkilonNimi [ ], int HenkilonIka ){

cout << "\nNimi on " << HenkilonNimi ;cout << " ja ika on " << HenkilonIka ;cout << " vuotta.\n" << endl ;

}

Kuva 13-3. Tulosta aliohjelman lähdetekstitiedosto Tulosta.cpp.

//// Tulosta.cpp tiedoston otsikkotiedosto.//// (c) Markku Rahikainen 2001//void Tulosta ( char HenkilonNimi [ ], int HenkilonIka ) ;

Kuva 13-4. Tulosta lähdetekstitiedoston otsikkotiedosto. 13.2 Parametrit Aliohjelmille voidaan välittää parametreina muuttujia, vakioita ja lausekkeita. Lisäksi on olemassa joitakin erikoistapauksia, kuten osoitinparametrit, tietuetyyppiset parametrit, taulukkoparametrit ja viittausparametrit (Viittausparametrien käsittely on esitetty osassa 14 VIITTAUS). 13.2.1 Perustyypit argumentteina Kun perustietotyyppejä käytetään aliohjelmalle välitettävinä parametreina, niin aliohjelman tekemät muutokset eivät näy kutsuvassa aliohjelmassa. Kutsuvassa aliohjelmassa muuttujien arvot säilyvät siis muuttumattomina

Page 52: C++-KIELI - Oamkjjauhiai/opetus/olio/Olio-ohjelmointi-40.pdf · 2007. 1. 5. · C++-kieli Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved. 4 5.7.2 OSOITTIMET TIETUEESEEN.....33

C++-kieli

Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved.

51

aliohjelmakutsun jälkeenkin. Parametrina välitetyt arvot kopioituvat aliohjelman paikallisiin muuttujiin. Aliohjelman paikallisille muuttujille varataan tilaa pinosta (Stack). Perustietotyyppiä olevien parametrien määritys aliohjelmassa:

void Aliohjelma ( Tyyppi Arvoparametri ){

. . .}

Arvoparametri on ohjelmoijan aliohjelmassa parametrille antama nimi. Tyyppi on jokin perustietotypistä (int, long, float, char…). 13.2.2 Osoitinparametri Kun osoitinparametreja käytetään aliohjelmalle välitettävinä parametreina, niin aliohjelman tekemät muutokset näkyvät myös kutsuvaan ohjelmaan. osoitinparametri on mahdollista toteuttaa joko osoittimen tai viittauksen avulla (Viittaus käsitellään osassa 14 VIITTAUS). Toteutuksessa käytetään osoiteoperaattoria ”&” ja sisältöoperaattoria (epäsuoran osoituksen operaattori) ”*”. Perus idea on se, että osoitinparametria käytettäessä kutsuvassa ohjelmassa määriteltyjen muuttujien osoitteet välitetään aliohjelmaan parametreina. Muuttujien osoitteet kopioituvat aliohjelman omiin osoitinparametreihin. Osoitinparametrityyppiä olevien parametrien määritys aliohjelmassa:

void Aliohjelma ( Tyyppi *Osoitinparametri ){

. . .}

Osoitinparametri on ohjelmoijan aliohjelmassa parametrille antama nimi. Osoitin sisältää parametrina välitetyn tiedon keskusmuistiosoitteen. Parametrin osoitteen välittäminen aliohjelmaan tapahtuu seuraavasti:

Aliohjelma ( &Parametri )

Aliohjelmalle välittyy parametrina muuttujan keskusmuistiosoite. Muuttujan osoitteeseen viitataan osoiteoperaattorin ”&” avulla. Esimerkiksi &Ika tarkoittaa Ika-nimisen muuttujan osoitetta keskusmuistissa. 13.2.3 Tietuetyyppinen parametri Tietuetyyppiä voidaan käyttää aliohjelmissa parametrien tyyppinä aivan samoin, kuin käytetään perustietotyyppejäkin. Seuraavassa on esimerkki tietuetyyppisen parametrin käytöstä. Esimerkissä on kaksi tiedostoa Para.cpp ja Para.h. Para.cpp tiedosto pitää sisällään pääohjelman ja aliohjelman. Para.h otsikkotiedosto (Header file) pitää sisällään aliohjelman prototyypin ja tietueen TIME.

/* Esimerkki ohjelmasta jossa aliohjelmalle välitettävä parametrion tietuetyyppinen, Para.cpp (c) Markku Rahikainen 2001 */

#include <iostream>using namespace std ;#include "Para.h"

int main ( ){

TIME Aika = { 11, 15, 30 } ;Tulosta ( Aika ) ;

Page 53: C++-KIELI - Oamkjjauhiai/opetus/olio/Olio-ohjelmointi-40.pdf · 2007. 1. 5. · C++-kieli Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved. 4 5.7.2 OSOITTIMET TIETUEESEEN.....33

C++-kieli

Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved.

52

return 0 ;}

void Tulosta ( TIME Kello ){

cout << "Kello on " ;cout << Kello.Hour << ":" ;cout << Kello.Minute << ":" ;cout << Kello.Second << endl ;

}

Kuva 13-5. Esimerkki tietuetyyppisestä parametrista. Tiedosto Para.cpp.

/*Para.cpp tiedoston otsikkotiedosto.(c) Markku Rahikainen 2001

*/

struct TIME{

int Hour ;int Minute ;int Second ;

} ;

void Tulosta ( TIME Kello ) ;

Kuva 13-6. Para.cpp tiedoston otsikkotiedosto.

Kuva 13-7. edellisen esimerkin tulostus.

Edellisessä esimerkissä on huomattavaa se, että main-ohjelmassa määritetty tietue Aika kopioituu aliohjelmassa määritettävän taulukon Kello sisällöksi, joten aliohjelmassa tehtävät muutokset eivät näy pääohjelmassa. Jos muutosten halutaan näkyvän pääohjelmassa, niin silloin aliohjelmalle on välitettävä vain tietueen osoite keskusmuistissa. 13.2.4 Taulukkotyyppinen parametri Jos aliohjelman kutsun argumenttina on taulukko, niin aliohjelmalle välitetään osoitin taulukon ensimmäiseen alkioon. Seuraavassa on esimerkki merkkitaulukon osoitteen välittämisestä aliohjelmalle.

/*Mjono.cpp

Esimerkki ohjelmasta jossa aliohjelmalle välitettävä parametrion merkkitaulukon osoite.

(c) Markku Rahikainen 2001*/#include <iostream>using namespace std ;

Page 54: C++-KIELI - Oamkjjauhiai/opetus/olio/Olio-ohjelmointi-40.pdf · 2007. 1. 5. · C++-kieli Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved. 4 5.7.2 OSOITTIMET TIETUEESEEN.....33

C++-kieli

Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved.

53

#include "Mjono.h"

int main ( ){

char Nimi [ ] = "Markku Rahikainen" ;

Tulosta ( Nimi ) ;

return 0 ;}

void Tulosta ( char TulostettavaNimi [ ] ){

int i = 0 ;

while ( TulostettavaNimi [ i ] != NULL ){

cout << TulostettavaNimi [ i++ ] ;}

cout << "\n\n" ;}

Kuva 13-8. Esimerkki taulukon osoitteen välittämisestä parametrina aliohjelmaan.

Kuva 13-9. Edellisen esimerkin tulostus.

13.3 Aliohjelmien kuormitus (Overloading) Aliohjelmien kuormitus eli ylimäärittely tarkoittaa samannimisen aliohjelman esittelyä ja määrittelyä useaan kertaan samassa lähdetekstissä tai luokassa. Kuormitusta käytetään, kun aliohjelman nimi halutaan standardoida tiettyyn tarkoitukseen riippumatta käsiteltävän tiedon tyypistä ja käsittelyn logiikasta. Aliohjelmien kuormitus on aliohjelmien monimuotoisuuttaa (Function polymorphism). Aliohjelmien kuormitus on mahdollista vain C++-kielisissä (Ei C-kielisissä) ohjelmissa. Alla on muutamia esimerkkejä:

int OmaFunktio (int, int) ;int OmaFunktio (int, long, double) ;void OmaFunktio (float) ;

Kuormitetut aliohjelmat poikkeavat toisistaan parametrien tyyppien ja/tai lukumäärien perusteella. Ylikuormitettujen funktioiden paluuarvot voivat olla samaa tai eri tyyppiä. Jos funktioiden ainoa ero on paluuarvon tyyppi, saadaan aikaiseksi käännös virhe. Kääntäjä tarkistaa käännösaikana, mikä aliohjelma sopii käytettyyn aliohjelmakutsuun parhaiten. Käännöksen aikana tapahtuvaa aliohjelman määrittelyn sitomista aliohjelmakutsuun sanotaan staattiseksi sidonnaksi (Static binding). Jos aliohjelmakutsussa käytettyä parametria vastaavaa tietotyyppiä varten ei ole toteutettu aliohjelmaa, kääntäjä etsii tietotyyppiin lähinnä sopivan aliohjelman. Tällöin järjestelmä yrittää tehdä parametrille automaattisen tyyppimuunnoksen.

Page 55: C++-KIELI - Oamkjjauhiai/opetus/olio/Olio-ohjelmointi-40.pdf · 2007. 1. 5. · C++-kieli Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved. 4 5.7.2 OSOITTIMET TIETUEESEEN.....33

C++-kieli

Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved.

54

Jos jotakin aliohjelmakutsua varten löytyy sopivia aliohjelmia enemmän kuin yksi, syntyy ristiriitatilanne ja kääntäjä antaa aliohjelmakutsusta virheilmoituksen. Tällöin ohjelmoijan on valittava käytettävä aliohjelma pakotettua eli eksplisiittistä tyyppimuunnosta käyttämällä. Tällaisia ristiriitatilanteita tapahtuu silloin, kun samojen aliohjelmien yhteydessä esiintyy sekä kuormitus että parametrien oletusarvot.

#include <iostream>using namespace std ;

void TulostaTyyppi (int) ;void TulostaTyyppi (int, int) ;void TulostaTyyppi (double) ;

int main (){

TulostaTyyppi (5) ;TulostaTyyppi (2, 4) ;TulostaTyyppi (2.5) ;

return 0 ;}

void TulostaTyyppi (int Luku){

cout << "\n Parametri on tyyppia int " << Luku ;}

void TulostaTyyppi (int Luku1, int Luku2){

cout << "\n\n 1. parametri on tyyppia int " << Luku1 ;cout << "\n 2. parametri on tyyppia int " << Luku2 ;

}

void TulostaTyyppi (double Luku){

cout << "\n\n Parametri on tyyppia double " << Luku << "\n\n" ;}

Kuva 13-10. Esimerkki aliohjelman nimen ylikuormittamisesta.

Kuva 13-11. Edellisen esimerkin tulostus.

13.3.1 Ongelmatilanteita Funktionimien ylikuormittamisen yhteydessä on joitakin ristiriitaisia tilanteita jotka on huomioitava. Kääntäjä tarkistaa aliohjelmakutsun löytäessään mikä on oikea kutsuttava aliohjelma. Toisinaan eri aliohjelmien kutsu voi näyttää samalta, esim. kutsu KerroKahdella(Luku); voisi tarkoittaa kumman tahansa seuraavan aliohjelman kutsua.

Page 56: C++-KIELI - Oamkjjauhiai/opetus/olio/Olio-ohjelmointi-40.pdf · 2007. 1. 5. · C++-kieli Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved. 4 5.7.2 OSOITTIMET TIETUEESEEN.....33

C++-kieli

Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved.

55

int KerroKahdella (int Luku) ;int KerroKahdella (int &Luku) ;

Ohjelmoijan on siis itse valittava kummalla tavalla haluaa aliohjelman määritellä, viittauksella vai ilman viittausta. Toinen ristiriitatilanne voi syntyä kun aliohjelmien välitystiedot poikkeavat toisistaan vain paluuarvojen perusteella, esim.

int TeeJako (int Jaettava, int Jakaja) ;short TeeJako (int Jaettava, int Jakaja) ;

Kuormitetuissa aliohjelmissa ei riitä paluutyppien erilaisuus, eroa on oltava myös parametreissa. Kolmas ristiriitatilanne syntyy helposti, kun kuormitus ja parametrien oletusarvot esiintyvät yhdessä. Aliohjelmakutsu Tuplaa(2); voi tarkoittaa kumman tahansa seuraavan aliohjelman kutsua.

int Tuplaa (int Luku) ;int Tuplaa (int Luku, int Tuplauskerroin = 1) ;

13.3.2 Luetellun tyypin (enum) kuormitus Lueteltu tyyppi enum on mahdollista kuormittaa samaan tapaan kuin mikä tahansa käyttäjän määrittelemä tyyppi. Tämä piirre luokitellaan C++-kielen uusiin piirteisiin. Se ei ole ollut mukana alkuperäisessä standardiehdotuksessa, vaan on lisätty standardiehdotukseen keväällä 1994. Kuormitettavat seuraava-aliohjelmat palauttavat joko seuraavan viikonpäivän järjestysnumeron tai seuraavan merkin käytettävässä merkistössä.

#include <iostream>using namespace std ;

enum Paiva {Maanantai = 1, Tiistai, Keskiviikko, Torstai, Perjantai, Lauantai, Sunnuntai } ;

char Seuraava (char Merkki) ;int Seuraava (Paiva paiva) ;

int main (){

Paiva Tanaan = Tiistai ;cout << "\n Huomenna on viikon " << Seuraava (Tanaan) << ".paiva \n" ;char Merkki = 'A';cout << "\n A:ta seuraava merkki on. " << Seuraava (Merkki) << "\n\n" ;return 0 ;

}

char Seuraava (char Merkki) {Merkki++ ;return Merkki ;

}

int Seuraava (Paiva paiva){

int Uusi = paiva ;Uusi = Uusi + 1 ;return Uusi ;

}

Kuva 13-12. Esimerkki luetellun tyypin käytöstä kuormituksessa.

Page 57: C++-KIELI - Oamkjjauhiai/opetus/olio/Olio-ohjelmointi-40.pdf · 2007. 1. 5. · C++-kieli Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved. 4 5.7.2 OSOITTIMET TIETUEESEEN.....33

C++-kieli

Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved.

56

Kuva 13-13. Edellisen esimerkin tulostus.

13.4 Esimerkkejä 13.4.1 Suuruus.cpp Yleensä ohjelmoinnissa on totuttu siihen, että jokaisella funktiolla tulee olla yksikäsitteinen nimi, jolla se voidaan erottaa toisista funktioista. Funktioitahan kutsutaan nimenomaan niiden nimien avulla. Koska C++ on ns. vahvasti tyypitetty ohjelmointikieli, on mahdollista että usealla funktiolla on sama nimi, kunhan funktiot eroavat argumenttien perusteella toisistaan. Jos kahdella funktiolla on sama nimi, voidaan sanoa että kyseinen funktio (nimi) on ylikuormitettu ja samannimisellä funktiolla on monta eri muotoa. Seuraavassa esimerkkiohjelmassa ”Suuruus.cpp” on funktiosta etsi_suurin_luku kolme erilaista versiota (muotoa). Kääntäjä voi tajuta nämä eri funktioiksi sen mukaan minkätyyppiset argumentit funktiota kutsuttaessa annetaan. Ohjelmassa ”Suuruus.cpp” on huomionarvoista myös se, että siinä käytetään referenssiargumentteja (Viittausta). Yksi funktion etsi_suurin_luku versioista käyttää yhtenä argumenttina referenssiargumenttia.

void etsi_suurin_luku (int kokonaislukutaulukko[], int lukujen_maara, int& suurin_luku)

Funktion kolmas argumentti (int& suurin_luku) on siis referenssiargumentti, joka voi siirtää tietoa kutsuvalle ohjelmalle. Kun jokin muuttuja on referenssiargumentti, niin se ei kopioidukaan kutsuttaessa kutsuttavalle ohjelmalle, vaan kutsussa siirtyy muuttujan osoite. Näin kutsuttava ohjelma voi kirjoittaa tietoa kutsuvassa ohjelmassa olevaan muuttujaan. Kutsuttava ohjelma siis ikään kuin käyttää kutsuvan ohjelman muuttujaa. Referenssiargumentti määritellään kirjoittamalla & argumentin tyyppinimen eteen.

//// Suuruus.cpp//#include <iostream>using namespace std ;#include <string>

int etsi_suurin_luku ( int kokonaislukutaulukko [ ], int lukujen_maara ){

int suurin_luku = kokonaislukutaulukko [ 0 ] ;int taulukkoindeksi = 1 ;

while ( taulukkoindeksi < lukujen_maara ){

if ( kokonaislukutaulukko [ taulukkoindeksi ] > suurin_luku ){

suurin_luku = kokonaislukutaulukko [ taulukkoindeksi ] ;}

taulukkoindeksi++ ;

Page 58: C++-KIELI - Oamkjjauhiai/opetus/olio/Olio-ohjelmointi-40.pdf · 2007. 1. 5. · C++-kieli Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved. 4 5.7.2 OSOITTIMET TIETUEESEEN.....33

C++-kieli

Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved.

57

}return suurin_luku ;

}

void etsi_suurin_luku ( int kokonaislukutaulukko [ ], int lukujen_maara,int& suurin_luku )

{suurin_luku = kokonaislukutaulukko [ 0 ] ;

int taulukkoindeksi = 1 ;

while ( taulukkoindeksi < lukujen_maara ){

if ( kokonaislukutaulukko [ taulukkoindeksi ] > suurin_luku ){

suurin_luku = kokonaislukutaulukko [ taulukkoindeksi ] ;}

taulukkoindeksi++ ;}

}

char etsi_suurin_luku ( char annettu_stringi [ ] ){

int merkkien_maara = strlen ( annettu_stringi ) ;char suurin_merkki = annettu_stringi [ 0 ] ;int stringi_indeksi = 1 ;

while ( stringi_indeksi < merkkien_maara ){

if ( annettu_stringi [ stringi_indeksi ] > suurin_merkki ){

suurin_merkki = annettu_stringi [ stringi_indeksi ] ;}

stringi_indeksi ++ ;}

return suurin_merkki ;}

void main ( ){

int esimerkkitaulukko [ ] = { 44, 2, 66, 33, 9 } ;int toinen_taulukko [ ] = { 888, 777, 66, 999, 998, 997 } ;int suurin_taulukon_luku = etsi_suurin_luku ( esimerkkitaulukko, 5 ) ;

cout << "\n Suurin esimerkkitaulukossa oleva luku on "<< suurin_taulukon_luku ;

etsi_suurin_luku ( toinen_taulukko, 6, suurin_taulukon_luku ) ;

cout << "\n\n Suurin toisen taulukon luku on "<< suurin_taulukon_luku ;

char esimerkkistringi [ ] = "abcde12345ABCDE;:.,-" ;

char suurin_stringin_merkki ;

suurin_stringin_merkki = etsi_suurin_luku ( esimerkkistringi ) ;

cout << "\n\n Suurin esimerkkistringin merkki on "<< suurin_stringin_merkki << " joka on "<< (int) suurin_stringin_merkki << "\n" ;

}

Kuva 13-14. Esimerkki funktionimien ylikuormittamisesta.

Page 59: C++-KIELI - Oamkjjauhiai/opetus/olio/Olio-ohjelmointi-40.pdf · 2007. 1. 5. · C++-kieli Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved. 4 5.7.2 OSOITTIMET TIETUEESEEN.....33

C++-kieli

Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved.

58

Kuva 13-15. Edellisen esimerkin tulostus.

Page 60: C++-KIELI - Oamkjjauhiai/opetus/olio/Olio-ohjelmointi-40.pdf · 2007. 1. 5. · C++-kieli Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved. 4 5.7.2 OSOITTIMET TIETUEESEEN.....33

C++-kieli

Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved.

59

14. VIITTAUS 14.1 Viittausmuuttuja (Referenssimuuttuja) Viittausmuuttuja eli lyhyemmin viittaus (Reference) on tunnuksen vaihtoehtoinen nimi eli alias. Viittauksia käytetään pääasiassa aliohjelmien muuttuja-parametreissa ja aliohjelmien palauttaman tiedon tyyppinä. Viittausten käytöllä voidaan helpottaa osoittimien käytöstä johtuvaa monimutkaisuutta. Viittauksia voi käyttää C++-kielisessä (Ei siis C-kielisessä) ohjelmassa. Viittausmuuttuja on alustettava määrittelyn yhteydessä. Viittausmuutuja viittaa aina samaan alustuksessa määrättyyn kohteeseen. Kohdetta ei voi vaihtaa. Jos kohdetta on pystyttävä vaihtamaan, on viittauksen sijasta käytettävä osoitinta. Viittausta käytettäessä ei tapahdu kuitenkaan yhtä helposti virheitä kuin osoittimia käytettäessä koska viittaus on alustettava määrittelynsä yhteydessä. Viittaus muistuttaakin enemmän vakio-osoitinta (const) kuin tavallista osoitinta. NULL-vertailua ei sitten tarvitse tehdä viittausmuuttujalle samaan tapaan kuin osoittimille.

tyyppi &Viittaus = Muuttuja ;

Kuva 14-1. Viittauksen määrittely. Viittaus voidaan määritellä vakiolle (Ei tavallista) tai aiemmin määritellylle muuttujalle. Viittaus määritellään &-operaattorilla.

#include <iostream>using namespace std ;

int main (){

int Luku = 9 ;int &Viittaus = Luku ;

Viittaus = Viittaus + 1 ;cout << "\n Viittaus: " << Viittaus ;cout << "\n\n Luku: " << Luku << "\n\n" ;

return 0 ;}

Kuva 14-2. Esimerkki viittausmuuttujan käytöstä.

Kuva 14-3. Edellisen esimerkin tulostus.

Viittauksilla on rajoituksia. Viittausta ei voi määritellä toiseen viittausmuuttujaan tai bittikenttään, viittausmuuttujista ei voi määritellä taulukkoa ja viittaukseen ei voi määritellä osoitinta. Edellä olevat rajoitukset johtuvat siitä, että viittausmuuttuja samaistetaan toiseen, viitattuun muuttujaan. Viittaus on siis aliasnimi. Jos

Page 61: C++-KIELI - Oamkjjauhiai/opetus/olio/Olio-ohjelmointi-40.pdf · 2007. 1. 5. · C++-kieli Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved. 4 5.7.2 OSOITTIMET TIETUEESEEN.....33

C++-kieli

Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved.

60

esim. tutkitaan “viittauksen osoitetta”, tutkitaankin oikeasti viitatun kohteen osoitetta. Samoin, jos määriteltäisiin “viittauksen viittaus”, on viittaus toinen aliasnimi alkuperäiselle muuttujalle, ei siis viittausmuuttujan aliasnimi.

#include <iostream>using namespace std ;

int main (){

int Luku = 10 ;int &Viite1 = Luku ;int &Viite2 = Viite1 ;int *Osoitin = &Viite1 ;

cout << "\n Viittauksen 1 kautta luku: " << Viite1 ;cout << "\n\n Viittauksen 2 kautta luku: " << Viite2 ;cout << "\n\n Osoittimen kautta luku: " << *Osoitin ;

int *&Viite3 = Osoitin;cout << "\n\n Viittaus osoittimeen: " << *Viite3 ;

int Taulukko [10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 0} ;int (&Viite4) [10] = Taulukko;// Huom ! Seuraava olisi väärin: "int &Viite4 [] = Taulukko;".cout << "\n\n Viittauksen taulukkoon kautta: \n\n" ;for (int i = 0; i<10; i++){

cout << " " << Viite4 [i] ;}

const int &Viite5 = 100 ;cout << "\n\n Viittaus vakioon: " << Viite5 << "\n\n" ;return 0 ;

}

Kuva 14-4. Erilaisia viittauksia.

Kuva 14-5. Edellisen esimerkin tulostus.

14.1.1 NULL-osoittimet ja NULL-viittaukset Kun osoitinta ei alusteta tai kun sen osoittaman muistialue on vapautettu delete-komennolla, osoittimen arvoksi kannattaa laittaa nolla eli NULL. Viittausten kohdalla tämä ei päde sillä viittaus ei voi olla arvoltaan nolla eli ei mitään. Viittaus voi kyllä kohdistua sellaiseen paikkaan muistia, jossa ei enää ole alkuperäistä viittauksen kohdetta. Ohjelma, jossa viitataan olemattomaan olioon tai käytetään NULL-osoitinta, on virheellinen. Virheellinen ohjelma saattaa toimia tekemättä vahinkoa tai se voi esim. sotkea tietokoneen ja poistaa kaikki tiedot kovalevyltä. Useimmat kääntäjät osaavat reagoida oikein jos ohjelmassa käytetään NULL-osoitinta. Yleensä ohjelma kaadetaan tai sen loputtua annetaan ilmoitus. Tästä huolimatta NULL-osoittimia kannattaa välttää (Kun käytetään viittauksia.). Kun ohjelma siirretään toiselle koneelle, sen toiminnassa saattaa ilmetä “mysteerisiä” häiriöitä.

Page 62: C++-KIELI - Oamkjjauhiai/opetus/olio/Olio-ohjelmointi-40.pdf · 2007. 1. 5. · C++-kieli Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved. 4 5.7.2 OSOITTIMET TIETUEESEEN.....33

C++-kieli

Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved.

61

14.1.2 Viittaus tietueeseen Viitattavan tiedon tyyppi voi olla perustietotyyppien lisäksi tietuetyyppi tai luokkatyyppi. Viittauksen käyttö tietueiden yhteydessä on osoittimien käyttöä helpompaa. Viittausta käytettäessä tietueen kenttiin voidaan viitata suoraan pistenotaation avulla.

#include <iostream>using namespace std ;

struct PVM{

int pp, kk, vv ;};

int main (){

PVM Tietue = {1, 1, 2001} ;PVM &Viittaus = Tietue ;

cout << "\nVuosi viittauksen kautta tulostettuna: " ;cout << Viittaus.vv << "\n\n" ;

return 0 ;}

Kuva 14-6. Viittaus tietueeseen.

Kuva 14-7. Viittaus tietueeseen ohjelman tulostus.

14.1.3 Viittaus osoittimeen Viittaus voidaan tarvittaessa määritellä myös osoittimeen. Osoitinta ei voi kuitenkaan määritellä viittaukseen. Viittausta käytettäessä merkintätavat yksinkertaistuvat huomattavasti osoitinmuuttujan käyttöön verrattuna.

#include <iostream>using namespace std ;

struct PVM{

int pp, kk, vv ;};

int main (){

PVM paiva = {1, 12, 99} ;PVM *osoitin1 = &paiva ;PVM *&osoitin2 = osoitin1 ;

cout << "\n Kuukausi: " << osoitin1->kk ;cout << "\n\n Kuukausi: " << osoitin2->kk << "\n\n" ;

Page 63: C++-KIELI - Oamkjjauhiai/opetus/olio/Olio-ohjelmointi-40.pdf · 2007. 1. 5. · C++-kieli Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved. 4 5.7.2 OSOITTIMET TIETUEESEEN.....33

C++-kieli

Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved.

62

return 0 ;}

Kuva 14-8. Viittaus osoittimeen.

Kuva 14-9. Ohjelman viittaus osoittimeen tulostus.

14.2 Perustietotyyppi muuttujaparametrina (Viittaus-parametri) Muuttujaparametrin toteuttaminen viittausparametrilla (Referenssiargumentti) on osoitinparametreihin verrattuna yksinkertaisempaa, koska erillisiä sisältö- ja osoitinoperaattoreita ei tarvita. Ainoastaan muuttujaparametrin määrittelyssä tarvitaan viittausmuuttujan määrittelyssä käytettävä &-merkki. Viittaus muuttuja voidaan ymmärtää viitattavan muuttujan aliasnimenä. Viittausta voidaan käyttää vain C++-kielessä.

void Aliohjelma (tyyppi &Muuttujaparametri){

...}

Muuttujaparametrin määrittely tapahtuu &-merkin avulla. Muuttujaparametri on siis viittausmuuttuja, joka on käytännössä aliohjelmalle parametrina välitetyn tiedon aliasnimi. Kun aliohjelmassa käytetään muuttujaparametrin nimeä, kohdistuu käsittely suoraan parametrina välitettyyn muuttujaan. Viittausmuuttujaa käytettäessä parametrin käsittely tapahtuu pelkän aliasnimen avulla ja kutsuva ohjelma lähettää parametrin aliohjelmalle arvoparametrin tapaan.

#include <iostream>using namespace std ;

void Tuplaa (int &Tuplattava) ;

int main (){

int Luku ;

cout << "\n Syota jokin kokonaisluku: " ;cin >> Luku;Tuplaa (Luku);cout << "\n Luku + Luku = " << Luku << "\n\n" ;

return 0;}

void Tuplaa (int &Tuplattava) {Tuplattava = Tuplattava + Tuplattava ;

}

Kuva 14-10. Aliohjelma, jossa muuttujaparametri on toteutettu viittausparametrina.

Page 64: C++-KIELI - Oamkjjauhiai/opetus/olio/Olio-ohjelmointi-40.pdf · 2007. 1. 5. · C++-kieli Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved. 4 5.7.2 OSOITTIMET TIETUEESEEN.....33

C++-kieli

Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved.

63

Kuva 14-11. Edellisen esimerkin tulostus.

14.2.1 Viittausparametrina väliaikainen muuttuja Viittausparametria käytettäessä on aliohjelmalle välitettävän parametrin tyypin vastattava tarkasti aliohjelmassa esitellyn viittausparametrin tyyppiä. Jos näin ei ole, järjestelmä tulkitsee tilanteen yleensä virheeksi ja antaa käännösvaiheessa virheilmoituksen. Edellisen esimerkin Tuplaa-aliohjelman esittely on void Tuplaa (int &Tuplattava);. Aliohjelma siis edellyttää int-parametria. Mitä tapahtuu jos kutsumme aliohjelmaa siten, että parametrina välitetään jonkin muun tyyppinen muuttuja ? Esim.

char Merkki = ‘A’ ;short Luku1 = 10 ;int Luku2 = 20 ;Tuplaa (Merkki) ; // VIRHE, muunnos ‘char’ -> ‘int &’ ei onnistu.Tuplaa (Luku1) ; // VIRHE, muunnos ‘short’ -> ‘int &’ ei onnistu.Tuplaa (Luku2 + 10) ; // VIRHE, muunnos ‘int’ -> ‘int &’ ei onnistu.

Kutsuparametreina esiintyvät eri tyyppiset tiedot eivät muunnu toisen tietotyypin viittauksiksi. Tämä on ymmärrettävää. Jos aliohjelman tulisi muuttaa parametrina annettavaa tietoa, on parametrina annettava juuri muutettava tieto eikä siitä tehty väliaikainen muunnettu versio. Edellisissä kutsutilanteissa jotkut kääntäjät tulkitsevat kutsut virheiksi, toiset kääntäjät antavat vain varoituksen. Muutetaan edellisen esimerkin aliohjelman esittelyä siten, että sen parametrina on const-viittaus ja että aliohjelma palauttaa yhteenlaskun tuloksen:

int Tuplaa (const int &Tuplattava){

return (Tuplattava + Tuplattava) ;}

Nyt kaikki edellä olleet kutsut ovat mahdollisia. Aliohjelmalle voi välittää tietoja, joiden tyyppi ei ole eksaktisti viittauksen tyyppinen. Aliohjelmalle voi välittää jopa laskulausekkeen. Kun viittausparametri määritellään vakioksi sanalla const, tuottaa järjestelmä välitettävistä parametreista aina aliohjelmalle väliaikaisen kopion silloin, kun välitetyn parametrin tyyppi ei täysin vastaa aliohjelman esittelyssä määriteltyä tyyppiä. Viittaus syntyy aliohjelman kutsussa tähän väliaikaiseen kopioon. Väliaikainen muunnos on olemassa aliohjelman suorituksen ajan, sitä käytetään aliohjelmassa ja järjestelmä tuhoaa sen automaattisesti aliohjelman päätyttyä.

Page 65: C++-KIELI - Oamkjjauhiai/opetus/olio/Olio-ohjelmointi-40.pdf · 2007. 1. 5. · C++-kieli Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved. 4 5.7.2 OSOITTIMET TIETUEESEEN.....33

C++-kieli

Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved.

64

#include <iostream>using namespace std ;

int Tuplaa (const int &Tuplattava) ;

int main (){

int Luku ;cout << "\n Syota jokin kokonaisluku: " ;cin >> Luku ;Tuplaa (Luku) ;cout << "\n Luku + Luku = " << Luku << "\n\n" ;

char Merkki = '#';short Luku1 = 10 ;int Luku2 = 20 ;Merkki = Tuplaa (Merkki) ;cout << "\n Merkki on " << Merkki ;Luku1 = Tuplaa (Luku1) ;cout << "\n\n Luku1 + Luku1 = " << Luku1 ;Luku2 = Tuplaa (Luku2 + 30) ;cout << " \n\n (Luku2 + 30) + (Luku2 + 30) = " << Luku2 << "\n\n" ;

return 0;}

int Tuplaa (const int &Tuplattava) {return (Tuplattava + Tuplattava) ;

}

Kuva 14-12. Parametrina on const-viittaus ja palautetaan tuplauksen tulos.

Kuva 14-13. Edellisen esimerkin tulostus.

Page 66: C++-KIELI - Oamkjjauhiai/opetus/olio/Olio-ohjelmointi-40.pdf · 2007. 1. 5. · C++-kieli Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved. 4 5.7.2 OSOITTIMET TIETUEESEEN.....33

C++-kieli

Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved.

65

15. DYNAAMINEN MUISTI Dynaamisella muistilla tarkoitetaan muistia jota varataan ja vapautetaan ohjelman suorituksen aikana eli muuttujien ja olioiden tarvitseman keskusmuistitilan varaamista ja vapauttamista. Olennaista dynaamisessa muistinhallinnassa on se, että etukäteen ei tarvitse olla tiedossa ohjelman käyttämän muistin määrä. 15.1 Muistinhallinnan operaattorit Ohjelman suorituksen aikana keskusmuistia voidaan varata käyttämällä new-operaattoria. Vastaavasti new-operaattorilla varattua muistia voidaan ohjelman suorituksen aikana vapauttaa käyttämällä delete-operaattoria. 15.1.1 new-operaattori Erityyppisille tiedoille kuten muuttujille ja olioille voidaan varata muistia käyttäen new-operaattoria. Kun keskusmuistia varataan new-operaattorilla, niin varatun keskusmuistitilan keskusmuistiosoite sijoitetaan osoitinmuuttujan arvoksi. Tämän osoitteen avulla voidaan dynaamisesti varatun muistialueen sisältöä käsitellä. new-operaattori varaa tilan vapaasta muistista eli keosta (Heap). new-operaattorilla keosta varatut muistialueet eivät vapaudu, kun kontrolli siirtyy pois viittausalueelta (Esimerkiksi pois aliohjelmasta takaisin kutsuneeseen ohjelmaan.).

int *Luku = NULL ;Luku = new int ;

Kuva 15-1. Dynaaminen tilanvaraus keskusmuistista (int-tyypin vaatima määrä). Kuvan 15-1 ensimmäisellä rivillä varataan int-tyyppinen osoitin joka alustetaan arvoon NULL (0). Tähän osoittimeen voidaan siis sijoittaa int-tyyppiä oleva tieto. Toisella rivillä int-tyyppiselle tiedolle varataan new-operaattorilla tilaa keskusmuistista. Varatun keskusmuistialueen osoite tallentuu osoittimen Luku arvoksi. Osoitinmuuttujan määrittäminen ja uuden muuttujan tilanvaraus voidaan kirjoittaa myös samalle riville (Kuva 15-2).

int *Luku = new int ;

Kuva 15-2. Osoittimen määrityksen ja dynaamisen tilanvaraus yhdistäminen. Tilanvarauksen onnistumisen tutkiminen voidaan suorittaa tutkimalla osoittimen arvoa new-operaattorin kutsumisen jälkeen. Jos muistinvaraus epäonnistuu, niin new-operaattori palauttaa arvon nolla.

if ( Luku != 0 )

if ( Luku != NULL )

Kuva 15-3. Tilanvarauksen onnistumisen tutkiminen. 15.1.2 delete-operaattori Dynaamisesti varattujen muuttujien ja olioiden tilanvapautus on suoritettava käyttäen delete-operaattoria. Dynaamisesti varatut muistialueet eivät vapaudu automaattisesti esimerkiksi ko. ohjelmalohkosta poistuttaessa.

delete Luku ;Luku = NULL ;

Kuva 15-4. Dynaamisen muistialueen vapautus.

Page 67: C++-KIELI - Oamkjjauhiai/opetus/olio/Olio-ohjelmointi-40.pdf · 2007. 1. 5. · C++-kieli Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved. 4 5.7.2 OSOITTIMET TIETUEESEEN.....33

C++-kieli

Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved.

66

Kuvassa 15-4 ’Luku’ on varattuun keskusmuistialueeseen viittaavan osoittimen nimi. delete-operaattorilla tapahtuvan tilan vapautuksen jälkeen on suositeltavaa, että laittaa osoittimen arvoksi sijoitetaan NULL (0). Kun osoittimen arvo on NULL eli 0, niin se tarkoittaa sitä, että se ei osoita mihinkään. 15.2 Taulukon dynaaminen käsittely Keskusmuistista voidaan varata yhdellä kertaa tilaa kokonaiselle taulukolle käyttämällä new [ ] – operaattoria. 15.2.1 Yksiulotteinen taulukko Varattaessa tilaa yksiulotteiselle taulukolle new [ ] –operaattorilla on varauksen yhteydessä ilmoitettava varattavien keskusmuistiyksiköiden määrä.

int *Taulukko = NULL ;Taulukko = new int [ 10 ] ;

Kuva 15-5. Esimerkki yksiulotteisen taulukon dynaamisesta tilanvaraamisesta. Tilanvarauksen yhteydessä on hakasulkeissa ilmoitettava varattavien keskusmuistiyksiköiden määrä. Kuvassa 15-5 varataan 10 kpl int-tyyppisiä yksiköitä. new-operaattori varaa yhtenäisen keskusmuistialueen eli kaikki varattavat alkiot sijoittuvat peräkkäin keskusmuistissa.

Taulukko 0 1 2 9

Kuva 15-6. Periaatteellinen kuva kuvan 15-5 tilanvarauksen jälkeisestä tilanteesta. Yksiulotteisen taulukon tilanvapautus tapahtuu delete-operaattorilla. Vapautuksen jälkeen osoitinmuuttujaan on suositeltavaa sijoittaa arvo NULL virheellisten osoitusten välttämiseksi.

delete [ ] Taulukko ;Taulukko = NULL ;

Kuva 15-7. Yksiulotteisen taulukon tilanvapautus.

Page 68: C++-KIELI - Oamkjjauhiai/opetus/olio/Olio-ohjelmointi-40.pdf · 2007. 1. 5. · C++-kieli Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved. 4 5.7.2 OSOITTIMET TIETUEESEEN.....33

C++-kieli

Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved.

67

16. LUOKKA JA OLIO Luokka on käyttäjän määrittelemä tyyppi. Olio on luokan mukainen tilanvaraus keskusmuistista. 16.1 Luokka Luokka (Class) on olioiden tyyppi. Toteutuksen kannalta luokka on ohjelmoijan määrittelemä tyyppi ja modularisointiyksikkö.

class Elain{ Attribuutitprivate:

char Lajin_nimi [10] ;char Lajin_Tyypillinen_Aantely [25] ;char Elaimen_Nimi [10] ;char Vari [10] ;int Vatsan_sisalto [100] ;

public:Elain (char Laji [ ], char Aantely [ ] ,char Nimi [ ]) ;~Elain ( ) ; Palvelutvoid Ruoki (char Ruokalaji [ ]) ;void Aantele ( ) ;

};

Kuva. Luokan eläin esittely. Palvelu (Service) on luokassa esitelty luokan olioiden vastuulla oleva tehtävä. Toteutuksen kannalta palvelu on luokkaan liitetyn aliohjelman esittely. Attribuutti (Attribute) eli luokan datajäsen on luokassa määriteltävä luokan olion ominaisuus. Toteutuksen kannalta attribuutti on luokassa määriteltävä tieto, olio tai palvelu.

Vatsan_sisalto

Kuva. Esim. eläin luokan datajäsen Vatsan_sisalto kertoo ko. olion tilasta. Metodi (Method) on palvelun toteutustapa. Toteutuksen kannalta metodi on luokkaan liitetty aliohjelma. Metodista voidaan käyttää nimitystä operaatio (Operation).

void Elain::Aantele ( ) Metodi{

cout << "\n" << Lajin_Tyypillinen_Aantely << " ! \n" ;}

Kuva. Eläin luokan jäsenfunktio. Jokainen olio kuuluu johonkin luokkaan. Luokka on oliotyyppi, joka sisältää attribuuttien, palveluiden ja metodien määrittelyn. Luokassa määritelty attribuutti on usein tieto, joka kuvailee luokan olion ominaisuutta. Esimerkiksi auto-oliolla on väri, kissa-oliolla on nimi jne. Jokaisella luokan oliolla on omat tiedot. Näitä tietoja on mahdollista käsitellä vain luokkaan määritellyillä metodeilla eli aliohjelmilla. Tieto on atribuutin yksi mahdollinen toteutustapa.

Page 69: C++-KIELI - Oamkjjauhiai/opetus/olio/Olio-ohjelmointi-40.pdf · 2007. 1. 5. · C++-kieli Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved. 4 5.7.2 OSOITTIMET TIETUEESEEN.....33

C++-kieli

Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved.

68

Kun attribuutin tyyppinä esiintyy luokka, on attribuuttikin olio. Tällainen tilanne syntyy, kun luokkia koostetaan muista luokista. Attribuutti voidaan toteuttaa palveluna, jos ominaisuutta tulee pystyä käsittelemään olion ulkopuolelta. Toteutustasolla palvelu-käsitettä vastaa lähinnä metodin eli aliohjelman esittely ja metodi-käsitettä vastaa tiettyyn palveluun liittyvä ohjelmakoodi. Oliolle lähetetty viesti käynnistää viestiä vastaavan metodin ohjelmakoodin.

Elain luokka

Kissa_Olio (Luokan instanssi)

Hiiri_Olio (Luokan instanssi)

Koira_Olio (Luokan instanssi)

Kuva. Jokainen olio kuuluu johonkin luokkaan. 16.2 Oliot ja niiden kommunikointi Olio (Object) on tietojen ja palvelujen kokonaisuus. Olio on ohjelman toteutuksen kannalta ajonaikainen keskusmuistista tehty tilanvaraus.

int main (){

Elain Katti (“Kissa”, “Miau”, “Katti”) ;...

return 0 ;} Kissa olio

Kuva. Kissa olion luonti Elain luokasta. Viesti eli palvelupyyntö (Message) on oliolle lähetetty pyyntö suorittaa jokin olin vastuulla oleva palvelu. Viesti on olioiden kommunikointitapa. Ohjelman toteutuksen kannalta viesti on olion kautta tapahtuva luokan aliohjelman kutsu.

Page 70: C++-KIELI - Oamkjjauhiai/opetus/olio/Olio-ohjelmointi-40.pdf · 2007. 1. 5. · C++-kieli Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved. 4 5.7.2 OSOITTIMET TIETUEESEEN.....33

C++-kieli

Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved.

69

int main (){

Elain Katti (“Kissa”, “Miau”, “Katti”);

Katti.Aantele() ;...return 0 ; Viesti

}

void Elain::Aantele(){

cout << "\n" << Lajin_Tyypillinen_Aantely << " ! \n" ;}

Kissa olio

Miau !

Kuva. Palvelupyyntö kissa oliolle. Palvelu (Service) on olion asiakasoliolleen tarjoama ja olion vastuulla oleva tehtävä. Toteutuksen kannalta palvelu on luokan aliohjelman esittely. Olio on käsitteenä hankala, sillä lähes mikä tahansa asia voi olla olio. Olio voi olla jokin tietty yritys, tuote, päivämäärä, käyttäjä, kokonaisluku jne. Oliot voivat olla siis eri abstraktiotasoilla. Yhteistä eri olioille on se, että kullakin oliolla on vastuullaan omat tietonsa ja niiden käsittelyyn tarvittavat palvelut. Oliot ovat siis kokonaisia tietojenkäsittely-yksiköitä. Oliolähestymistavassa eräs keskeinen periaate on tiedon piilotuksen (Information hiding) periaate. Tämä tarkoittaa sitä, että vain olio itse voi käsitellä omia tietojansa. Olio ei siis näe toisen olion tietoja eikä kykene niitä käsittelemään. Tiedon piilotus mahdollistaa olion käytön ohjelmistokomponenttina, joka on mahdollista liittää muihin ohjelmistokomponentteihin tietämättä sen sisältöä. Ainoastaan ohjelmistokomponentin käyttötarkoitus ja ulkoinen rajapinta on tiedettävä, jotta oliota voisi käyttää. Ulkoinen rajapinta sisältää olion palvelut.

Kuva. Olio-Tiedot-Palvelu-Viesti. Tehtävien toteuttamiseen tarvitaan yleensä useita yhteistyössä toimivia olioita. Oliot tuottavat siten yhdessä laajempaan tehtäväkokonaisuuteen liittyvän palvelun. Kullakin oliolla on oma vastuualueensa ja oliot kommunikoivat toistensa kanssa palvelupyyntöjä eli viestejä lähettämällä. Kun olio ei kykene tuottamaan palvelua yksin, se delegoi palvelupyynnön edelleen muille olioille. Toiselta oliolta palvelua pyytävä olio on

Page 71: C++-KIELI - Oamkjjauhiai/opetus/olio/Olio-ohjelmointi-40.pdf · 2007. 1. 5. · C++-kieli Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved. 4 5.7.2 OSOITTIMET TIETUEESEEN.....33

C++-kieli

Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved.

70

asiakasolio (Client) ja palvelun toteuttava olio on palvelinolio (Server). Sama olio voi toimia eri tilanteissa eri rooleissa. 16.3 Valmiiden luokkien käyttö Olioiden käyttö ohjelmoinnissa on yksinkertaisimmillaan silloin, kun ohjelmoija käyttää valmista luokkakirjastoa. Tällöin hänen on tunnettava luokkakirjaston sisältämien luokkien tarjoamat palvelut. Ohjelmoija voi käyttää luokkia seuraavilla tavoilla:

• Luoda ja alustaa olion. • Lähettää oliolle viestejä, joita vastaavat palvelut on määritelty olion luokassa.

Valmiin luokkakirjaston käyttäjän ei tarvitse tietää luokkien attribuuttien ja metodien toteutuksen teknisiä näkökohtia. Luokkien käyttö on samankaltaista kuin tietotyyppien käyttö. Erona on kuitenkin se, että olion tietoja ei voi käsitellä muuten kuin palveluja käyttäen.

Page 72: C++-KIELI - Oamkjjauhiai/opetus/olio/Olio-ohjelmointi-40.pdf · 2007. 1. 5. · C++-kieli Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved. 4 5.7.2 OSOITTIMET TIETUEESEEN.....33

C++-kieli

Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved.

71

17. LUOKKATYYPIT (Class types) Olio-ohjelmoinnissa keskitytään kahteen keskeiseen asiaan – luokkien käyttämiseen ja luokkien toteuttamiseen. Luokan toteuttaminen muistuttaa uuden tyypin toteuttamista. Uusi tietotyyppi tehdään määrittelemällä luokka (class). Luokka on yhteenliitetty joukko erilaisia muuttujia (Data member) ja luokan käsittelemään asiaan liittyviä funktioita (Function member). Luokan avulla erilaisia osia ja toimintoja voidaan kapseloida yhteen kokoelmaan eli olioon. Luokka voi sisältää minkälaisen yhdistelmän tahansa perustietotyyppejä ja muita luokkia. 17.1 Ylläpidettävyys ja uudelleenkäytettävyys Luokan ylläpidettävyys taataan luokan rajapinnan ja toteutuksen erottamisella. Rajapinta julkaistaan ulospäin näkyväksi niin, että luokan asiakkaat voivat pyytää palvelua luokan oliolta. Palvelujen ja tietojen toteutustapa piilotetaan luokan sisään niin, että ne eivät näy luokan käyttäjälle. Tämä tekniikka tunnetaan nimellä kapselointi (Encapsulation). Kapselointi on ohjelmointitekniikka, joka määrää sekä ohjelmien modularisoinnin että tietojen ja toteutustavan piilotuksen periaatteet. Sen tarkoituksena on uudelleenkäytettävyyden lisääminen ja ylläpidon paikallistaminen luokkaan. Ohjelmoija voi uudelleenkäyttää valmista luokkaa käyttämällä sen palveluja luokan olioiden avulla. Ohjelmoija voi myös määritellä kokonaan uusia luokkia olemassa olevista luokista koostamalla tai periyttämällä. Tietojen piilotuksella (Information hiding) tarkoitetaan sitä, että luokassa määriteltyjä tietoja voi käsitellä vain kyseisessä luokassa määritellyillä aliohjelmajäsenillä eli metodeilla. Toteutustavan piilottamisella tarkoitetaan sitä, että luokka piilottaa sisälleen palveluittensa toteutustavan metodeina – siis ohjelma-algoritmeina. Asiakasohjelmat näkevät ainoastaan palvelun nimitasolla ja tietävät näin mitä luokan oliot osaavat. Asiakkaat eivät siis näe miten luokan oliot palvelun toteuttavat. Luokka siis erottaa palveluista liittymän ja toteutustavan. Ohjelmien ylläpidettävyys paranee, kun tietojen ja metodeitten toteutukset ovat näkyviä vain ko. luokassa. Jos toteutustapaan tulee muutos, ei asiakasohjelmia tarvitse ylläpitää, ainoastaan toteutustavan sisältämää luokkaa muutetaan. 17.2 Luokan määrittelyssä käytettävät tyypit C++-kielessä luokan tyyppimääre voi olla class, struct tai union. Luokka (Class) on ohjelmoijan märittelemä tyyppi, jonka avulla kapselointi toteutetaan. Luokka liittää tyyppiin kuuluvat attribuutit ja attribuutteja käsittelevät metodit yhteen. C++-kielikohtainen vastine attribuutille on tietojäsen (Data member) ja metodille aliohjelmajäsen (Function member). Sekä tiedot että aliohjelmat ovat siis luokan jäseniä. Olio-ohjelmoinnissa aliohjelmajäsenestä käytetään yleisesti termiä metodi. 17.2.1 union-määre union-määreellä voidaan määritellä sekä tietuetyyppejä että luokkatyyppejä. Unioni on vaihtuvarakenteinen tietuetyyppi. Unioni (Yhdiste) on tietue, jossa kaikki jäsenet sijoitetaan samaan osoitteeseen niin, että se vie yhtä paljon tilaa kuin suurin jäsen (Suurimman jäsenen tilanvarauksen verran). Yhdiste voi sisältää tämän johdoista vain yhden jäsenen arvon kerrallaan. union-tietuetyypin kentät määrittelevät saman muistialueen eri tavoin. Samaan muistialueeseen viitataan vaihtoehtoisilla kentän nimillä, jolloin myös mustialueen tyyppi vaihtelee.

//// Union_1.cpp (c) 2001 Markku Rahikainen//

#include <iostream>using namespace std ; // Otetaan käyttöön nimiavaruus std.

Page 73: C++-KIELI - Oamkjjauhiai/opetus/olio/Olio-ohjelmointi-40.pdf · 2007. 1. 5. · C++-kieli Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved. 4 5.7.2 OSOITTIMET TIETUEESEEN.....33

C++-kieli

Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved.

72

union DATE{

char Month [20] ;char Weekday [12] ;

};

int main ( ){

DATE Paivays = { "Perjantai" } ;

cout << "\nViikonpaiva on: " << Paivays.Weekday ;cout << "\nKuukausi on: " << Paivays.Month ;

cout << endl << endl ;

return 0 ;

} // End of main().

Kuva 17-1. Esimerkki union-määreen käytöstä.

Kuva 17-2. Edellisen esimerkin tulostus.

//// Union_2.cpp (c) 2001 Markku Rahikainen//

#include <iostream>using namespace std ; // Otetaan käyttöön nimiavaruus std.

union DATE{

char Weekday [15] ;int DayNbr ;

};

int main ( ){

DATE Paivays ;

strcpy (Paivays.Weekday, "Perjantai");cout << "\nViikonpaiva on: " << Paivays.Weekday ;

Paivays.DayNbr = 10;cout << "\nKuukausi on: " << Paivays.DayNbr ;

cout << endl << endl ;

return 0 ;

} // End of main().

Kuva 17-3. Esimerkki union-määreen käytöstä.

Page 74: C++-KIELI - Oamkjjauhiai/opetus/olio/Olio-ohjelmointi-40.pdf · 2007. 1. 5. · C++-kieli Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved. 4 5.7.2 OSOITTIMET TIETUEESEEN.....33

C++-kieli

Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved.

73

Kuva 17-4. Edellisen esimerkin tulostus.

// Union_3.cpp (c) 2001 Markku Rahikainen#include <iostream>using namespace std ; // Otetaan käyttöön nimiavaruus std.

union DATE{

char Weekday [15] ;int DayNbr ;void Luku ( ) ;

};

void DATE::Luku( ){

cout << "Markku" ;}

int main ( ){

DATE Paivays ;Paivays.Luku();

strcpy (Paivays.Weekday, "Perjantai");cout << "\nViikonpaiva on: " << Paivays.Weekday ;

Paivays.DayNbr = 10 ;cout << "\nKuukausi on: " << Paivays.DayNbr ;

cout << endl << endl ;

return 0 ;} // End of main().

Kuva 17-5. Esimerkki union-määreen käytöstä luokan määrittelyssä.

Kuva 17-6. Edellisen esimerkin tulostus.

Page 75: C++-KIELI - Oamkjjauhiai/opetus/olio/Olio-ohjelmointi-40.pdf · 2007. 1. 5. · C++-kieli Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved. 4 5.7.2 OSOITTIMET TIETUEESEEN.....33

C++-kieli

Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved.

74

17.2.2 struct-määre C++ kielessä aliohjelmat voidaan liittää struct-määreellä määriteltyyn tyyppiin, koska struct määrittelee C++-kielessä luokkatyypin eikä tietuetyypin, kuten C-kielessä. Luokkatyypin mukaisesta tilanvarauksesta käytetään nimitystä olio (Object). Luokan aliohjelmat eli metodit eivät tarvitse parametrina käsiteltävää oliota, koska metodeita kutsutaan lähettämällä viesti eli palvelupyyntö (Message) tietylle oliolle. Luokan metodi käsittelee aina sen olion tietoja, joille viesti lähetetään.

#include <iostream>using namespace std ;

struct Luku{

int luku ;void Kysy () ;

};

void Luku::Kysy(){

cout << "\n Syota luku: " ;cin >> luku ;

}

int main (){

Luku Olio;Olio.Kysy();cout << " Syotetty luku on: " << Olio.luku << "\n\n" ;return 0 ;

}

Kuva 17-7. Luku-luokkatyypin määrittely struct-määreellä ja käyttö.

Kuva 18-8. Edellisen esimerkin tulostus.

17.2.3 class-määre C++-kielessä olio-ohjelmoinnin periaatteiden mukaisen luokan voi määritellä class-määreellä. Tällaisessa luokassa luokan jäsenet (Datajäsenet, Jäsenfunktiot) ovat oletusarvoisesti näkyviä vain luokan omissa aliohjelmajäsenissä (private). Jäsenet, joiden halutaan näkyvän luokan ulkopuolella esitellään public-määreen jäljessä. public-määreen jäljessä on siis luettelo luokan julkisista palveluista, se on luokan liittymä (Interface) luokan asiakkaisiin. Tämä menettely takaa tietojen piilotuksen (Information hiding) luokan sisään ja ohjelmien paremman ylläpidettävyyden. Luokan asiakkailla tarkoitetaan tässä yhteydessä mitä tahansa ohjelmaa, joka kutsuu luokan metodeita lähettämällä viestin luokan oliolle. Datajäsenet voivat olla mitä tahansa tyyppiä olevia tietoja tai olioita. Jäsenfunktiot ovat tietojäseniä käsittelevien aliohjelmajäsenien esittelyitä.

Page 76: C++-KIELI - Oamkjjauhiai/opetus/olio/Olio-ohjelmointi-40.pdf · 2007. 1. 5. · C++-kieli Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved. 4 5.7.2 OSOITTIMET TIETUEESEEN.....33

C++-kieli

Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved.

75

#include <iostream>using namespace std ;

class Luku{private:

int luku ;public:

void Kysy () ;void Nayta () ;

};

void Luku::Kysy(){

cout << "\n Syota luku: " ;cin >> luku ;

}

void Luku::Nayta(){

cout << "\n Syotetty luku on: " << luku << "\n\n" ;}

int main (){

Luku Olio ;

Olio.Kysy() ;Olio.Nayta() ;

return 0 ;}

Kuva 17-9. Luku-luokan määrittely class-määreellä olio-ohjelmoinnin periaatteen mukaisesti.

Kuva 17-10. Edellisen ohjelman tulostus.

Huom ! Ainoastaan class-määreen avulla muodostetut luokat mahdollistavat tietojen

käsittelyn oliolähestymistavan periaatteiden mukaisesti.

Page 77: C++-KIELI - Oamkjjauhiai/opetus/olio/Olio-ohjelmointi-40.pdf · 2007. 1. 5. · C++-kieli Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved. 4 5.7.2 OSOITTIMET TIETUEESEEN.....33

C++-kieli

Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved.

76

18. LUOKKAN MÄÄRITTELY Tässä käsitellään vain määrettä class eli C++kielen olio-ohjelmoinnin periaatteiden mukaista luokkaa. 18.1 Luokkatyyppi class Luokan määrittely tarkoittaa luokan datajäsenten (Attribuutit) ja jäsenfunktioiden (Metodit) esittelyä. Luokan määrittely kertoo, mitä tietoja sen luokan olioilla on ja mitä palveluita luokan oliot asiakasolioilleen tarjoavat. Luokan määrittely on itseasiassa tyyppimäärittely, jota tarvitaan myöhemmin oliota luotaessa ja olioille viestiä lähetettäessä. Luokkatyypin määrittely ei varaa muistia olion talletusta varten. Luokkamäärittelyn yleinen muoto on seuraava:

Luokan_tyyppi_määre Luokan_nimi{

Datajäsenten esittely.Jäsenfunktioiden esittely.

};

Luokan_tyyppi_määre voi olla class, struct tai unioni. Luokan_nimi on tunnus, jonka ohjelmoija määrää luokkatyypin nimeksi. Lohkosulkujen sisällä esitellään luokkatyyppiin liitettävät tietojäsenet (datajäsenet) ja aliohjelmajäsenet (jäsenfunktiot). Datajäsenet voivat olla mitä tahansa tyyppiä olevia tietoja tai olioita. Jäsenfunktiot ovat tietojäseniä käsittelevien jäsenfunktioiden eli metodien esittelyitä. Samalla viittausalueella voi esiintyä useita samannimisiä aliohjelmia. Siis myös luokassa voidaan kuormittaa metodeita. Lisäksi eri luokissa voi esiintyä samannimisiä aliohjelmia ja tietojäseniä. Luokka on siten itsenäinen viittausalue. C++-kielen termiä tietojäsen vastaa yleisesti olioterminologiassa lähinnä käsite attribuutti. Attribuutti voidaan mieltää myös yleisesti luokan olion ominaisuudeksi, jonka tekninen toteutustapa voi olla yhtä hyvin perustietotyyppiä vastaava tietojäsen, luokkatyyppiä vastaava olio kuin jäsenfunktiokin. Esim. henkilöolion ominaisuus ikä voidaan toteuttaa int-tyyppisenä tietona, Ika-tyyppisenä oliona tai int ika() –metodina. Toteutustapa valitaan tarpeen mukaan. Jos Ika sisältää omia attribuutteja ja palveluita ja sillä on uudelleenkäyttöarvoa sovelluksessa luokkatyyppinä, voidaan siitä toteuttaa olio ja luokka. Jos uudelleenkäyttöarvoa ei ole luokkatyyppinä, mutta ominaisuuden arvo voidaan laskea ja näyttää ulospäin, voidaan toteuttaa metodi. C++-kielen aliohjelmajäsenen esittely vastaa käsitettä palvelu. Palvelu kertoo mitä olio osaa. Aliohjelmajäsenen toteutus vastaa yleisessä olioterminologiassa käsitettä metodi. Metodi sisältää palvelun toteuttavan ohjelman algoritmin. Metodin ja palvelun käsitteiden erottaminen ei ole välttämätöntä, niiden erottaminen kuitenkin auttaa havaitsemaan erilliset mitä-miten-tasot luokan tarjoamassa toiminnallisuudessa. Luokan tyyppimääreet class, struct ja union vaikuttavat luokan jäsenten näkyvyyteen luokan olioiden asiakkaiden näkökulmasta. Näistä määreistä class on olio-ohjelmoinnin tiedon piilotuksen periaatteita noudattava määre, koska sen avulla määritellyn luokan jäsenet ovat käytettävissä vain luokan sisällä. Luokan jäsenten näkyvyyteen voidaan vaikuttaa luokkatyyppien struct ja class yhteydessä varatuilla sanoilla private, protected ja public. Nämä sanat ovat saantimääreitä (Access specifiers). private-määreen jäljessä esitellyt luokan jäsenet ovat yksityisiä eli ne ovat käytettävissä ainoastaan luokan sisällä. public-määreen jäljessä esitellyt luokan jäsenet ovat julkisia ja ne ovat käytettävissä missä kohtaa lähdekoodia tahansa, jossa luokkatyypin mukainen olio on viittausalueella (Eli alueilla missä ko. olio on käytettävissä.). protected-määre määrittelee tiedot suojatuiksi, määre liittyy periytymiseen (Kts. periytyminen). Yleensä luokan datajäsenet esitellään private-määreen jäljessä ja jäsenfunktiot public-määreen jäljessä. Myös aliohjelma voidaan esitellä private- tai protected-määreen jäljessä, jos aliohjelma on tarkoitettu vain luokan omaan käyttöön ja sen viittausalue halutaan säilyttää luokan sisällä.

Page 78: C++-KIELI - Oamkjjauhiai/opetus/olio/Olio-ohjelmointi-40.pdf · 2007. 1. 5. · C++-kieli Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved. 4 5.7.2 OSOITTIMET TIETUEESEEN.....33

C++-kieli

Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved.

77

TAULUKKOOletussaantimääreet luokkatyypeittäin

Luokkatyyppimääre Oletussaantimääre Muutettavuusclass private Voidaan muuttaa.struct public Voidaan muuttaa.union public Ei voida muuttaa.

Varatulla sanalla class määritellyissä luokkatyypeissä luokan jäsenet ovat luokan yksityisiä ellei ohjelmoija muuta määrää. Varatulla sanalla struct määritellyissä luokkatyypeissä luokan jäsenet ovat julkisia ellei ohjelmoija muuta määrää. Varatulla sanalla union määritellyissä luokkatyypeissä kuokan jäsenet ovat aina julkisia.

class Luokan_nimi{private:

// Datajäsenten (Attribuuttien) esittelyt eli luokan sisäiset ja// periytymättömät jäsenet.

protected:// Suojattavat tiedot (Liittyy periytymiseen) eli luokan sisäiset// ja periytyvät jäsenet.

public:// Aliohjelmajäsenten (Metodien) esittelyt eli luokan ulospäin// näkyvät jäsenfunktiot ja datajäsenet..

};

Kuva 18-1. Luokan määrittely varatulla sanalla class. Luokan määrittely alkaa class-määreellä. Luokan jäsenet esitellään lohkosulkeiden välissä. Luokan jäsenten esittely päättyy puolipisteeseen. Luokan tietojäsenet esitellään yleensä private-sanan jäljessä ja luokan julkinen palveluliittymä eli aliohjelmajäsenet public-sanan jäljessä. C++-kielen syntaksi ei kuitenkaan edellytä tätä, vaan aliohjelman voi tarvittaessa esitellä private-määreen jäljessä, jos aliohjelmaa on tarkoitus pystyä kutsumaan vain luokan omissa aliohjelmajäsenissä. Tietojäseniä ei ole kuitenkaan syytä määritellä julkisiksi missään tilanteessa (Rikkoo tiedon kätkemisen periaatetta.). class-määreen yhteydessä private-sana ei ole pakollinen, sillä jäsenten viittausalue on oletusarvoisesti luokka eikä niitä voida käyttää luokan ulkopuolelta. private-sanaa käytetään kuitenkin usein korostettaessa luokan jäsenten näkyvyyssääntöjä. Luokan määrittely tapahtuu tavallisesti luokan otsikkotiedostossa.

class Auto{private:

int Vuosimalli ;char Merkki [20] ;

public:void Kysy ( ) ;void Nayta ( ) ;

} ;

Kuva 18-2. Esimerkki yksinkertaisen ”Auto”-luokan määrittelystä. 18.1.1 Rekursio Luokan määrittelyn ensimmäisen rivin jälkeen luokka on esitelty, joten tämän jälkeen sitä voidaan käyttää uusien tunnusten esittelyyn. Tämä mahdollistaa luokkatyypin nimen käytön myös ko. luokan omien tyyppien määrittelyssä. Tällöin näiden ns. rekursiivisten tyyppien määrittely on mahdollista.

Page 79: C++-KIELI - Oamkjjauhiai/opetus/olio/Olio-ohjelmointi-40.pdf · 2007. 1. 5. · C++-kieli Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved. 4 5.7.2 OSOITTIMET TIETUEESEEN.....33

C++-kieli

Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved.

78

class Auto{private:

int Vuosimalli ;char Merkki [20] ;Auto *Osoitin ;

public:void Kysy ( ) ;void Nayta ( ) ;

};

Kuva 18-3. Esimerkki rekursiivisen luokan määrittelystä. 18.1.2 Tyhjä luokka Luokka voidaan määritellä keskeneräiseksi siten, että data- ja aliohjelmajäsenet jätetään esittelemättä. Tämä on käyttökelpoista silloin, kun esim. kaksi luokkaa sisältävät ristikkäisiä viittauksia toisiinsa.

class Auto ;

class Vakuutus{private:

Auto *AutoOlio ;char VakuutuksenOttaja ;

}

class Auto{private:

Vakuutus *VakuutusOlio;int Vuosimalli ;char Merkki [20] ;

public:void Kysy ( ) ;void Nayta ( ) ;

} ;

Kuva 18-4. Esimerkki ristikkäisesti viittaavista luokista. 18.2 Aliohjelmajäsenet Luokan määrittelyn sisällä esiteltyjä funktioita sanotaan luokan jäsenfunktioiksi eli aliohjelma-jäseniksi. Luokan aliohjelmien koodien toteutukset eli metodit on tehtävä erikseen (Poikkeuksena on inline-jäsenfunktiot). Jokaisella luokkaan kuuluvalla metodilla on oltava esittely luokan määrittelyn yhteydessä. Seuraavassa on esitetty metodin toteutuksen periaatteellinen rakenne:

Tyyppi Luokan_nimi::Metodin_nimi ( Parametrit ){

// Metodin toteuttava koodi.}

Tyyppi on metodin paluuarvon tyyppi. Luokan metodin määrittelyssä on oltava mukana sen luokan nimi, jossa metodi on esitelty. Eriluokat voivat sisältää samannimisiä metodeja. Parametrit ovat metodille välitettäviä parametreja samaan tapaan, kuin on laita tavallisten aliohjelmakutsujen yhteydessä. Metodin ohjelmakoodi saa käsitellä suoraan kaikkia luokassa esiteltyjä jäseniä riippumatta näiden saantimääreistä.

Page 80: C++-KIELI - Oamkjjauhiai/opetus/olio/Olio-ohjelmointi-40.pdf · 2007. 1. 5. · C++-kieli Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved. 4 5.7.2 OSOITTIMET TIETUEESEEN.....33

C++-kieli

Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved.

79

void Auto::Nayta( ){

cout << Merkki << Vuosimalli ;}

Kuva 18-5. Esimerkki metodin toteutuksesta. 18.3 Esimerkkejä 18.3.1 Auto.cpp

// Auto.cpp (c) 2001 Markku Rahikainen

#include <iostream>using namespace std ; // Otetaan käyttöön nimiavaruus std.

class Auto{private:

int Vuosimalli ;char Merkki [25] ;

public:void Kysy ( ) ;void Nayta ( ) ;

};

void Auto::Kysy( ){

cout << "Syota auton merkki ja vuosimalli \nvalilyonnilla" ;cout << "toisistaan erotettuna: " ;cin >> Merkki >> Vuosimalli ;

}

void Auto::Nayta( ){

cout << "\n\nAuto on " << Merkki << " merkkinen ja sen vuosimalli on " ;cout << Vuosimalli << ". \n\n" ;

}

int main ( ){

Auto OmaAuto ; // Luodaan olio jonka tunnus on OmaAuto.

OmaAuto.Kysy( ) ; // Viestin lähetys OmaAuto-oliolle.OmaAuto.Nayta( ) ; // Viestin lähetys OmaAuto-oliolle.

return 0 ;} // End of main().

Kuva 18-6. Esimerkki olio-ohjelmasta Auto.cpp.

Kuva 18-7. Edellisen esimerkin tulostus.

Page 81: C++-KIELI - Oamkjjauhiai/opetus/olio/Olio-ohjelmointi-40.pdf · 2007. 1. 5. · C++-kieli Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved. 4 5.7.2 OSOITTIMET TIETUEESEEN.....33

C++-kieli

Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved.

80

18.3.2 Elaimet.cpp

//// Elaimet.cpp//

#include <iostream>using namespace std ;#include <cstring>

class Elain{protected:

char lajin_nimi [ 40 ] ;char vatsan_sisalto [ 80 ] ;

public:Elain ( char annettu_lajin_nimi[ ] ) ;

void ruoki ( char annettu_ruoka[ ] ) ;void anna_puhua ( ) ;

} ;

Elain::Elain( char annettu_lajin_nimi[ ] ){

strcpy ( lajin_nimi, annettu_lajin_nimi ) ;strcpy ( vatsan_sisalto, "" ) ;

}

void Elain::ruoki( char annettu_ruoka[ ] ){

strcat ( vatsan_sisalto, annettu_ruoka ) ;strcat ( vatsan_sisalto, ", " ) ;

}

void Elain::anna_puhua( ){

cout << "\n Hei, mina olen " << lajin_nimi << "."<< "\n Olen syonyt: " << vatsan_sisalto << "\n" ;

}

void main ( ){

Elain kissaolio( "kissa" ) ;Elain koiraolio( "vegaani koira" ) ;

kissaolio.anna_puhua( ) ;koiraolio.anna_puhua( ) ;

kissaolio.ruoki( "kalaa" ) ;kissaolio.ruoki( "kalkkunaa" ) ;

koiraolio.ruoki( "salaattia" ) ;koiraolio.ruoki( "perunoita" ) ;

kissaolio.anna_puhua( ) ;koiraolio.anna_puhua( ) ;

}

Kuva 18-8. Esimerkki olio-ohjelmasta Auto.cpp.

Page 82: C++-KIELI - Oamkjjauhiai/opetus/olio/Olio-ohjelmointi-40.pdf · 2007. 1. 5. · C++-kieli Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved. 4 5.7.2 OSOITTIMET TIETUEESEEN.....33

C++-kieli

Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved.

81

Kuva 18-9. Edellisen esimerkin tulostus.

Page 83: C++-KIELI - Oamkjjauhiai/opetus/olio/Olio-ohjelmointi-40.pdf · 2007. 1. 5. · C++-kieli Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved. 4 5.7.2 OSOITTIMET TIETUEESEEN.....33

C++-kieli

Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved.

82

19. OLIOIDEN MUISTINVARAUSLUOKAT Ennen viestin lähettämistä on olion oltava olemassa. Oliolle on siis varattava tila. Ohjelmointikielen kannalta olio on keskusmuistiin varattu alue. Olion muistinvarausluokka voi olla: Automaattinen

• Olio on paikallinen lohkossa. • Järjestelmä varaa oliolle keskusmuistitilan olion määrittelyn yhteydessä pinosta. • Järjestelmä vapauttaa oliolle varatun keskusmuistitilan automaattisesti lohkon loppuessa.

Dynaaminen

• Ohjelmoija varaa oliolle keskusmuistitilan new-operaattorilla, tilanvaraus tapahtuu vapaasta muistista eli keosta. • Ohjelmoija vapauttaa tilan delete-operaattorilla. • Olioon voidaan viitata monen eri tunnuksen avulla, tunnukset ovat yleensä paikallisia lohkoissa/aliohjelmissa.

Staattinen

• Olio voi olla globaali tai static-määreellä esitelty paikallinen olio. • Järjestelmä varaa oliolle keskusmuistitilan pääohjelman käynnistyksen yhteydessä. • Järjestelmä vapauttaa oliolle varatun keskusmuistitilan pääohjelman loppuessa.

Automaattiset oliot ovat lyhytikäisiä. Ne ovat olemassa tietyn palveluketjun tai metodin suorituksen ajan. Niiden palveluja ei tarvita, kun palveluketju on loppuun suoritettu. Automaattisia olioita käytetään väliaikaisina työolioina, kun käsiteltävien olioiden lukumäärä on tiedossa ohjelman kirjoitusvaiheessa ja kun olion ei tarvitse olla olemassa sen luoneen ohjelmalohkon loputtua. Dynaamiset oliot voivat olla automaattisia olioita pitkäikäisempiä. Dynaamiset oliot voivat olla osallisina useissa eri palveluketjuissa. Dynaamisen olion luomisesta ja tuhoamisesta on vastuussa aina jokin toinen olio. Dynaamisia olioita käytetään, kun ajonaikaisten olioiden lukumäärästä ei ole tarkkaa tietoa ohjelman kirjoitusvaiheessa tai kun olion on oltava olemassa vielä palveluketjun päätyttyäkin. Dynaamisten olioiden käsittelyssä tarvitaan osoittimia ja dynaamista muistinhallintaa. Staattiset oliot ovat olemassa koko sovelluksen käyttöajan. Staattisia olioita voidaan käyttää useissa eri palveluketjuissa. Staattiset oliot sisältävät usein sovellukseen, palveluketjuun tai luokkaan liittyvää kirjanpito- tms. Tietoa, jonka tulee olla käytettävissä aina.

Page 84: C++-KIELI - Oamkjjauhiai/opetus/olio/Olio-ohjelmointi-40.pdf · 2007. 1. 5. · C++-kieli Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved. 4 5.7.2 OSOITTIMET TIETUEESEEN.....33

C++-kieli

Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved.

83

20. OLION LUONTI eli TILANVARAUS Olion tilanvaraukseen liittyy olion tunnuksen esittely ja olion määrittely. Olion esittely liittää tunnuksen nimen olion tyyppiin eli luokkaan. Olion määrittely luo olion eli määrittely varaa keskusmuistitilan olion tiedoille. Olio saa luotaessa luokkansa mukaisen kehyksen eli luokka määrää sille varattavat tietojäsenet (Datajäsenet, Attribuutit). Aliohjelmajäsenet eivät kopioidu jokaiselle, vaan kaikki luokan oliot käyttävät kertaalleen talletettua ohjelmakoodia. Olion tilanvarauksen koko määräytyy siis tietojäsenten tilanvarauksien summasta. Kuitenkin tyhjän olion tilanvaraus on yksi tavu. 20.1 Automaattisen olion esittely ja määrittely Automaattisen olion tunnuksen esittely on samalla sen määrittely. Järjestelmä varaa automaattisen olion tarvitseman keskusmuistitilan olion tunnuksen esittelyn yhteydessä.

Luokan_nimi Olion_tunnus ;Luokan_nimi Olion_tunnus = Luokan_nimi( );

Kuva 20-1. Automaattisen olion esittely ja määrittely. Luokan_nimi on sen luokan tunnus, jonka perusteella järjestelmä varaa keskusmuistitilan olion tiedoille. Olion_tunnus on olion nimi, jota käytetään ohjelmakoodissa olioon viitattaessa ja sille viestiä lähetettäessä. Automaattisen olion tunnus viittaa ohjelman koko suorituksen ajan samaan olioon. Olion luonnin yhteydessä järjestelmä kutsuu olion alustamista varten luokan muodostinta (Constructor). Yllä olevat olion luontilauseet aiheuttavat ns. oletusmuodostimen käynnistymisen. Oletusmuodostin on järjestelmän generoima tai ohjelmoijan generoima olion alustusmetodi, jota kutsutaan ilman alustuksessa käytettäviä parametreja. Ensimmäisellä rivillä järjestelmä varaa tilan oliolle ja kutsuu automaattisesti (Implisiittisesti) oletusmuodostinta. Toisella rivillä käytetyssä kirjoitusmuodossa ohjelmoija kutsuu oletusmuodostinta pakotetusti (Eksplisiittisesti). Lopputulos on sama riippumatta valitusta olion luontilauseen kirjoitustavasta. Molemmat esitetyt olion luontilauseet toimivat ilman ohjelmoijan itsensä toteuttamaa muodostinta. Olion luonti varaa oliolle luokan perusteella keskusmuistitilan, johon voidaan viitata olion tunnuksella. Huom ! Automaattista oliota luotaessa sulkeiden käyttö liittyy vain pakotettuun oletusmuodostimen kutsuun eli

siis olion luontiin sijoitusmerkin jälkeen. Sulkeita ei voi käyttää silloin, kun järjestelmä kutsuu automaattisesti oletusmuodostinta, koska tällöin merkintätapa sekoittuu aliohjelmaesittelyyn.

Kissa Olio ; // Automaattinen oletusmuodostimen kutsu.Kissa Olio() ; // Aliohjelman esittely, ei olionmuodostus !Kissa Olio = Kissa() ; // Pakotettu oletusmuodostimen kutsu.

Kuva 20-2. Esimerkkejä automaattisen olion luomisesta Kissa-luokkaan. 20.2 Dynaamisen olion esittely ja määrittely Dynaamisen olion tunnuksen esittely ja olion määrittely voivat tapahtua samanaikaisesti tai eri aikaan. Dynaamisen olion tunnuksen esittely on osoitinmuuttujan esittely. Sama osoitinmuuttuja voi osoittaa eri hetkinä eri olioihin ja samaan olioon voi olla useita osoittimia yhtä aikaa.

Page 85: C++-KIELI - Oamkjjauhiai/opetus/olio/Olio-ohjelmointi-40.pdf · 2007. 1. 5. · C++-kieli Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved. 4 5.7.2 OSOITTIMET TIETUEESEEN.....33

C++-kieli

Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved.

84

20.2.1 Olion esittely ja määrittely erikseen

Luokan_nimi *Olion_tunnus ;Olion_tunnus = new Luokan_nimi ;Olion_tunnus = new Luokan_nimi() ;

Kuva 20-3. Automaattisen olion esittely ja määrittely erikseen. Ensimmäisellä rivillä on osoitinmuuttujan esittely. Osoitinmuuttuja voi sisältää myöhemmin varattavan olion keskusmuistiosoitteen. Varsinainen olion tilanvaraus tapahtuu vasta toisella rivillä new-operaattorilla. Olion luonnin eli tilanvarauksen jälkeen olion tunnusta käytetään mm. välitettäessä viestiä oliolle. Vasta tilanvarauksen jälkeen oliolle voidaan lähettää viestejä. Kolmannella rivillä oleva olion luontilause on vaihtoehto toisella rivillä esitetylle luontilauseelle. Toisen rivin luontilause aiheuttaa automaattisesti oletusmuodostimen kutsun, kun taas kolmannen rivin luontilauseessa ohjelmoija määrää eksplisiittisesti oletusmuodostimen kutsun.

Kissa *Katti_olio ; // Katti_olio voi osoittaa Kissa tyyppiseen olioon.Katti_olio = new Kissa ; // new-operaattorilla varattu tila Kissa-oliolle.

Kuva 20-4. Esimerkki dynaamisen olion esittelystä ja määrittelystä Kissa-luokkaan. 20.2.2 Olion esittely ja määrittely yhtäaikaisesti

Luokan_nimi *Olion_tunnus = new Luokan_nimi ;Luokan_nimi *Olion_tunnus = new Luokan_nimi() ;

Kuva 20-5. Automaattisen olion esittely ja määrittely samanaikaisesti.

Kissa *Katti_olio = new Kissa ;

Riippumatta siitä, tapahtuuko dynaamisen olion esittely ja määrittely yhtä aikaa vai eri aikaan, tulee keskusmuisti varatuksi seuraavaan tapaan: Jos luokka on seuraavanlainen,

class Kissa {private:

int Ika ;int Paino ;char Nimi [8];

public:void Naukaise() ;void AsetaIka() ;

};

niin edellisen esimerkin osoitinmuuttuja Katti_olio sisältää osoitteen oliolle varatun keskusmuistialueen alkuun.

Katti_Olio: 12F4002A Ikä: Paino: Nimi: Luku 12F4002A edustaa varatun olion keskusmuistiosoitetta.

Page 86: C++-KIELI - Oamkjjauhiai/opetus/olio/Olio-ohjelmointi-40.pdf · 2007. 1. 5. · C++-kieli Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved. 4 5.7.2 OSOITTIMET TIETUEESEEN.....33

C++-kieli

Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved.

85

20.3 Staattisen olion esittely ja määrittely Staattisen olion määrittely alkaa varatulla sanalla static. Globaalit oliot ovat staattisia ilman static-määrettäkin. Määrettä tarvitaan aliohjelmissa tai luokkien sisällä, jos määritellyn olion tilanvaraus halutaan staattiseksi. Paikallisen staattisen olion tilanvaraus ja vapautus tapahtuu täsmälleen kerran koko ohjelman suorituksen aikana. Sekä automaattinen olio että dynaamiseen olioon viittaava osoitinmuuttuja voidaan määritellä static-määreellä staattiseksi. Tällöin tilanvaraus ja arvo säilyvät, vaikka tunnuksen viittausalue olisi paikallinen.

static Luokan_nimi Olion_tunnus ;static Luokan_nimi *Olion_tunnus = new Luokan_nimi ;

Kuva 20-6. Staattisen olion esittely ja määrittely.

1 {2 static Kissa Misse_olio ;3 static Kissa *Katti_olio ;4 Katti_olio = new Kissa ;5 }

Kuva 20-7. Esimerkki staattisten olioiden esittelystä ja määrittelystä Kissa-luokkaan. Rivillä 2 on automaattisen olion tilanvaraus vaihdettu staattiseksi. Ilman static-määrettä olion tilanvaraus vapautuisi rivillä 5. Rivillä 3 on määritelty muistinvarausluokaltaan staattinen osoitinmuuttuja. Ilman static-määrettä osoitinmuuttujan tilanvaraus vapautuisi rivillä 5 ja osoitin rivillä 4 luotuun dynaamiseen olioon katoaisi. Rivillä 4 luodun olion keskusmuistitila ei sen sijaan vapaudu ennen kuin ohjelmoija ohjelmakoodissa vapauttaa tilan delete-operaatiolla.

Page 87: C++-KIELI - Oamkjjauhiai/opetus/olio/Olio-ohjelmointi-40.pdf · 2007. 1. 5. · C++-kieli Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved. 4 5.7.2 OSOITTIMET TIETUEESEEN.....33

C++-kieli

Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved.

86

21. OLION TILANVAPAUTUS Automaattiset oliot ovat paikallisia lohkossa ja tuhoutuvat automaattisesti lohkon loppuessa. Staattiset oliot vapautuvat, kun pääohjelman suoritus päättyy. Dynaamisten olioiden tilanvaraus ei häviä automaattisesti, vaan ohjelmoija on vapautettava tila delete-operaattoria käyttäen.

delete Olion_tunnus ;

Kuva 21-1. Dynaamisen olion tilanvapautus. Tuhoutuneen olion keskusmuistitila vapautuu muuhun käyttöön. Dynaamisiin olioihin on muistettava säilyttää viittaukset aina niiden olemassaoloaikana. Dynaamiset oliot jäävät keskusmuistiin, vaikka ohjelman kontrolli siirtyy pois olion luoneen lohkon viittausalueelta. Jos olion keskusmuistiosoite katoaa, häviää viittausmahdollisuus ko. olioon, vaikka olio olisikin olemassa. Tällaiset oliot kuormittavat keskusmuistia turhaan. Ohjelmoijan on siis muistettava aina poistaa delete-operaattorilla new-operaattorilla luodut oliot.

1 void Aliohjelma( )2 {3 Kissa Misse_olio ;4 Kissa *Katti_olio = new Kissa ;5 static Kissa Rontti_olio ;6 …7 delete Katti_olio ;8 }

Kuva 21-2. Kissa-luokan olioiden tilanvapautus. Rivillä 3 varatun olion tila vapautuu automaattisesti rivillä 8. Rivillä 4 varatun olion tila ei häviä rivillä 8, mutta siihen osoittavan osoitinmuuttujan tila häviää. Olion varaama tila on ohjelmoijan itse vapautettava delete-operaattorilla, kuten rivillä 7 on tehty. Rivillä 5 määritelty staattisen olion tilanvaraus häviää vasta, kun pääohjelman suoritus loppuu.

Page 88: C++-KIELI - Oamkjjauhiai/opetus/olio/Olio-ohjelmointi-40.pdf · 2007. 1. 5. · C++-kieli Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved. 4 5.7.2 OSOITTIMET TIETUEESEEN.....33

C++-kieli

Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved.

87

22. KONSTRUKTORI (Constructor) Olioihin kohdistuvia automaattisia toimintoja ovat luonti, alustus, kopiointi, sijoitus, tyhjennys ja tuhoaminen. Automaattiset toiminnot voivat aktivoitua järjestelmän käynnistämänä tai ohjelmoijan käynnistämänä. Muut tapauskohtaisesti määriteltävät ohjelmoijan käynnistämät toiminnot liittyvät usein olion tilan eli tietojäsenten arvojen tutkimiseen tai muuttamiseen. Kutakin oliokohtaista toimintoa varten on luokkaan esiteltävä ja määriteltävä omat metodinsa (Jäsenfunktiot). 22.1 Olion luonti ja tuhoaminen Olion luontiin ja tuhoamiseen liittyy kumpaankin kaksi eri vaihetta. Olion luontiin liittyvät vaiheet ovat:

• Olion tilanvaraus • Olion alustus

Olion tuhoamiseen liittyvät vaiheet ovat:

• Olion tyhjennys • Olion tilanvapautus

Olion tilanvaraus- ja tilanvapautushetki määräytyy olion muistinvarausluokan perusteella. Olion alustus tapahtuu tilanvarauksen yhteydessä. Olion tietojäsenten alustustoimenpiteet sisältyvät erityiseen alustusta varten kirjoitettuun metodiin, jota kutsutaan muodostimeksi (Constructor). Yhdessä luokassa voi olla useita kuormitettuja muodostimia erilaisia käyttötilanteita varten Jaamme muodostimet kolmeen ryhmään:

• Oletusmuodostin (Default constructor) �Olion tietojäsenten alustus oletusarvoilla.

• Kopiointimuodostin (Copy constructor) �Olion tietojäsenten alustus toisesta oliosta kopioimalla.

• Ohjelmoijan määrittelemät parametrilliset muodostimet �Olion tietojäsenten alustus ohjelmoijan tapauskohtaisesti määräämillä alkuarvoilla.

Luokkaan määritellään muodostimia, jotta voitaisiin varmistaa, että olion tietojäsenet ovat alustettuja ja että ohjelma ei keskeydy ajonaikaiseen virheeseen tietojäsenen sisältöön viitattaessa. Muodostin kutsutaan kerran yhtä oliota kohti. Jos olion luonnin jälkeen halutaan olion tietojäsenet alustaa uudelleen, on käytettävä sijoitusta tai jotakin muuta metodia. Järjestelmä kutsuu muodostinta automaattisesti olion tilanvarauksen yhteydessä. Olion tietojäsenten tyhjennys tapahtuu olion tilanvapautuksen yhteydessä. Tyhjennykseen liittyvät toimenpiteet sisältyvät metodiin josta käytämme nimitystä hajotin (Destructor). Luokassa voi olla yksi hajotin. Hajotinta voidaan kutsua tilanvapautushetken lisäksi myös muulloin, kun olio halutaan tyhjentää. Tämä ei ole kuitenkaan tavallista tai suositeltavaa. 22.2 Olion tietojäsenten alustus oletusarvoilla ja oletusmuodostin Oletusmuodostin (Default constructor) alustaa olion tietojäsenet oletusarvoilla. Oletusmuodostin voi olla kääntäjän generoima tai ohjelmoijan kirjoittama. Kääntäjä generoi luokalle oletusmuodostimen vain jos ohjelmoija ei ole toteuttanut luokkaan muodostimia. Järjestelmä kutsuu oletusmuodostinta automaattisesti olion tilanvarauksen yhteydessä, kun olio määritellään alla olevan syntaksin mukaisesti.

Page 89: C++-KIELI - Oamkjjauhiai/opetus/olio/Olio-ohjelmointi-40.pdf · 2007. 1. 5. · C++-kieli Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved. 4 5.7.2 OSOITTIMET TIETUEESEEN.....33

C++-kieli

Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved.

88

Olion tilanvaraus aiheuttaa oletusmuodostimen kutsun:

Luokka Olio ;Luokka Olio = Luokka() ;Luokka *Olio = new Luokka ;Luokka *Olio = new Luokka() ;

Ensimmäisellä rivillä on automaattisen olion tunnuksen esittely, joka on samalla olion määrittely. Määrittely varaa oliolle keskusmuistitilan ja aiheuttaa automaattisesti oletusmuodostimen kutsun. Toisella rivillä on olion tunnuksen esittely erotettu olion määrittelystä. Ohjelmoija voi kirjoittaa muodostimen kutsun halutessaan sijoitusmerkin oikealle puolelle. Kolmannella rivillä olevassa mallissa new-operaattorin käyttö aiheuttaa dynaamisen olion tilanvarauksen ja oletusmuodostimen kutsun. Neljännellä rivillä ohjelmoija on kirjoittanut itse muodostimen kutsun. Järjestelmän tekemä automaattinen kutsu on implisiittinen (Implicit call) ja ohjelmoijan kirjoittama kutsu on pakotettu eli eksplisiittinen (Explicit call). Automaattisessa kutsussa ei esiinny sulkeita, kun taas pakotetussa kutsussa esiintyy. Pakotettu ohjelmoijan kirjoittama muodostimen kutsu ei välttämättä ole mahdollista vanhemmissa kääntäjäympäristöissä. Jokaista luotavaa oliota kohti muodostinta kutsutaan yhden kerran. Kääntäjän generoima oletusmuodostin ei tee varsinaisesti mitään. Jos ohjelmoija haluaa olioiden tietojäsenet alustettavaksi tietyillä oletusalkuarvoilla, hänen on määriteltävä itse oletusmuodostin.

class Luokka{

…public:

Luokka ( );};

Kuva 22-1. Oletusmuodostimen esittely. Oletusmuodostimen esittelyssä ja määrittelyssä on seuraavat säännöt:

• Oletusmuodostimen nimi on luokan nimi. • Oletusmuodostin ei saa parametreja. • Oletusmuodostimella ei ole tyyppiä (Ei edes void), oletusmuodostin ei siis palauta return-lauseella mitään. • Oletusmuodostinta koskevat samat näkyvyyssäännöt kuin muitakin luokan metodeita ja muodostimesta voidaan tarvittaessa kutsua muita aliohjelmia tavallisen luokan metodin tapaan. • Muodostimen esittelyssä ei saa käyttää varattuja sanoja const, volatile, virtual tai static. • Muodostimen esittelyssä voi esiintyä varattu sana explicit, tällöin muodostinta ei voi käyttää tyyppimuunnoksiin.

Uudemmissa C++-kääntäjäympäristöissä oletusmuodostimeksi tulkitaan kaikki muodostimet, joita voi kutsua ilman parametreja. Tästä syystä oletusmuodostin voi olla myös parametrillinen muodostin, jonka kaikilla parametreilla on oletusarvo. Luokassa voi olla ainoastaan yksi oletusmuodostin. Tietojäsenten alustus muodostimessa voidaan kirjoittaa kahteen eri kohtaan.

Luokka::Luokka() : Tietojäsenten alustukset{

Tietojäsenten alustukset.Muodostimen runko.

}

Kuva 22-2. Oletusmuodostimen määrittely eli toteutus.

Page 90: C++-KIELI - Oamkjjauhiai/opetus/olio/Olio-ohjelmointi-40.pdf · 2007. 1. 5. · C++-kieli Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved. 4 5.7.2 OSOITTIMET TIETUEESEEN.....33

C++-kieli

Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved.

89

Tietojäsenten alustus voidaan kirjoittaa muodostimen ensimmäiselle riville kaksoispisteen jälkeen tai oletusmuodostimen runkoon.

Luokka::Luokka() : Tieto(lauseke) , Tieto(lauseke), …{}

Kuva 22-3. Tietojäsenten alustus muodostimen ensimmäisellä rivillä. Tieto on alustettava tietojäsen. lauseke on muuttuja, vakio tai jokin muu lauseke, jonka arvolla tietojäsen alustuu. Edellistä alustustapaa voidaan käyttää, jos alustuslauseke on yksinkertainen. Alustustapaa on käytettävä, jos 1) alustettava tietojäsen on esitelty vakioksi const-määreellä tai 2) alustettava tietojäsen on viittausmuuttuja tai 3) tietojäsen on jonkin luokan automaattinen olio.

Luokka::Luokka(){

Tieto = lauseke ;…

}

Kuva 22-4. Tietojäsenten alustus muodostimen rungossa. Jos tietojäsenten alustukseen liittyy monimutkaista logiikkaa, eikä alustettava tietojäsen ole vakio tai viittaus, voidaan alustuslauseet kirjoittaa muodostimen runkoon. Tämä alustustapa on mahdollinen myös tietojäsenille, joiden tyyppi on luokka ja jos ko. luokassa on määritelty sijoitusoperaattori. Tällaisessa tapauksessa alustus on kuitenkin tehokkaampaa, kun se tehdään muodostimen ensimmäisellä rivillä. Seuraavassa esimerkissä on toteutettu Pvm-luokkaan oletusmuodostin, joka alustaa päivämäärän vakioarvoilla.

1 #include <iostream>2 using namespace std ;

3 class Pvm4 {5 private:6 int pp, kk, vv ;7 public:8 Pvm() ;9 void Nayta() const ;10 };

11 Pvm::Pvm() : pp(1), kk(2), vv(99)12 {13 }

14 void Pvm::Nayta() const15 {16 cout<<pp<<'/'<<kk<<'/'<<vv ;17 }

18 int main()19 {20 Pvm Paiva ;21 Paiva.Nayta() ;22 return 0 ;23 }

Kuva 22-5. Pvm-olion alustus oletusarvoilla.

Page 91: C++-KIELI - Oamkjjauhiai/opetus/olio/Olio-ohjelmointi-40.pdf · 2007. 1. 5. · C++-kieli Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved. 4 5.7.2 OSOITTIMET TIETUEESEEN.....33

C++-kieli

Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved.

90

1 / 2 / 99

Kuva 22-6. Edellisen esimerkin tulostus. Rivillä 8 on esitelty Pvm-luokan oletusmuodostin. Oletusmuodostin on esitelty public-sanan jäljessä. Jos oletusmuodostin olisi määritelty private-sanan jäljessä, ei rivillä 20 oleva olion tilanvaraus onnistuisi. Riveillä 11-13 on oletusmuodostimen toteutus. Oletusmuodostimen ensimmäisellä rivillä näkyy tietojäsenten alustus vakioarvoilla. Oletusmuodostimen runko on tyhjä. Tällaisissa tapauksissa voidaan oletusmuodostin helposti kirjoittaa suoraan esittelyn yhteyteen inline-metodiksi. Rivillä 20 oleva Paiva-olion määrittely varaa oliolle keskusmuistitilan ja kutsuu oletusmuodostinta. Kun Paiva-olion sisältö on tulostettu Nayta-metodilla, näkyy sisältönä oletusarvot. Edellisessä esimerkissä päivämäärä alustettiin vakioarvolla. Alustus olisi kuitenkin mielekkäämpää esimerkiksi kuluvalla päivämäärällä. Tällöin alustuksessa voidaan käyttää ctime-kirjaston (Aiemmin time.h) aliohjelmia time ja localtime. Alustus sisältää logiikkaa, joka on kirjoitettava muodostimen runkoon.

0 #include <iostream>1 using namespace std ;2 #include <ctime>

3 class Pvm4 {5 private:6 int pp, kk, vv ;7 public:8 Pvm();9 void Nayta() const ;10 };

11 Pvm::Pvm()12 {13 time_t sek ;14 tm *paiva ;15 time(&sek) ;16 paiva = localtime(&sek) ;17 pp = paiva->tm_mday ;18 kk = paiva->tm_mon + 1 ;19 vv = paiva->tm_year ;20 }

21 void Pvm::Nayta() const22 {23 cout<<pp<<'/'<<kk<<'/'<<vv ;24 }

25 int main()26 {27 Pvm Paiva ;28 Paiva.Nayta() ;2929 return 0 ;30 }

Kuva 22-7. Pvm-olion alustus kuluvalla päivämäärällä. Ohjelman tulos riippuu luonnollisesti suorituspäivämäärästä. Rivillä 2 on sisällytetty lähdetekstiin ctime-otsikkotiedosto, jotta ohjelmassa voitaisiin viitata tyyppitunnuksiin time_t ja tm sekä aliohjelmiin localtime ja time. Pvm-olion datajäsenet on alustettu tm-tyyppisestä tietueesta paiva. Tämä tietue sisältää kuluvan päivämäärän ja kellonajan. Tiedot paiva-tietueeseen saadaan selvittämällä ensin sekunnit time-aliohjelmalla rivillä 15 ja muuttamalla sekunnit sitten localtime-aliohjelmalla tm-tietuetyypille sopivaan muotoon. Valmiista paiva-tietueesta on pp-kenttään sijoitettu kuluvan päivän numero rivillä 17, kuluvan kuukauden numero rivillä 18 ja kuluvan vuoden numero rivillä 19. Jos time-kirjaston tietotyypit ja aliohjelmat eivät ole tuttuja, ne voi tutkia kääntäjäympäristön ohjeista.

Page 92: C++-KIELI - Oamkjjauhiai/opetus/olio/Olio-ohjelmointi-40.pdf · 2007. 1. 5. · C++-kieli Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved. 4 5.7.2 OSOITTIMET TIETUEESEEN.....33

C++-kieli

Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved.

91

22.3 Olion tietojäsenten alustus määrätyillä arvoilla ja parametrillinen muodostin Jos ohjelmoija haluaa alustaa olion tilanvarauksen yhteydessä tapauskohtaisilla alustusarvoilla, ohjelmoija voi määritellä luokkaan parametrillisen muodostimen. Muodostin voidaan kuormittaa. Luokassa voi olla monta parametrillista muodostinta erilaisia alustustilanteita varten. Parametrillinen muodostin on aina ohjelmoijan kirjoittama. Tässä kopiointimuodostin erotetaan parametrillisesta muodostimesta. Parametrillisen muodostimen esittelyssä ja määrittelyssä noudatetaan samoja sääntöjä kuin oletusmuodostimen yhteydessä. Poikkeuksena on kuitenkin seuraavat säännöt:

• Parametrillisen muodostimen parametreihin voidaan määritellä tarvittaessa myös oletusarvot. • Luokka voi sisältää useita erilaisilla parametreilla varustettuja muodostimia. • Parametrillinen muodostin, jonka kaikilla parametreilla on oletusarvo, toimii oletusmuodostimena. • Kääntäjä ei generoi oletusmuodostinta, jos ohjelmoija on määritellyt luokkaan parametrillisen

muodostimen. Seuraavassa esimerkissä Pvm-luokkaan on esitelty ja määritelty parametrillinen muodostin, joka saa parametreina vakioarvot kunkin tietojäsenen alustamista varten. Tietojäsenten alustus on tehty muodostimen ensimmäisellä rivillä. Alustus olisi ollut mahdollista kirjoittaa myös muodostimen runkoon.

0 #include <iostream>1 using namespace std ;2 #include <ctime>

3 class Pvm4 {5 private:6 int pp, kk, vv ;7 public:8 Pvm(int, int, int) ;9 void Nayta() const ;10 };

11 Pvm::Pvm (int p_pp, int p_kk, int p_vv) :12 pp(p_pp), kk(p_kk), vv(p_vv)13 {14 }

15 void Pvm::Nayta() const16 {17 cout<<pp<<'/'<<kk<<'/'<<vv ;18 }

19 int main()20 {21 Pvm Paiva(13, 12, 99) ;22 Paiva.Nayta() ;2323 return 0 ;24 }

Kuva 22-8. Parametrillinen muodostin Pvm-luokassa.

13 / 12 / 99

Kuva 22-9. Edellisen esimerkin tulostus. Rivillä 12 näkyy tietojäsenten alustus parametrien arvoilla. Rivillä 21 näkyy Paiva-olion luonti ja alustus parametrillista muodostinta käyttäen. Huomaa, että Pvm-luokkaan ei ole mahdollista luoda oliota ilman parametreja, koska esimerkissä ei ole toteutettu oletusmuodostinta. Nyt siis jokaiselle Paiva-oliolle on määrättävä alkuarvot luonnin yhteydessä.

Page 93: C++-KIELI - Oamkjjauhiai/opetus/olio/Olio-ohjelmointi-40.pdf · 2007. 1. 5. · C++-kieli Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved. 4 5.7.2 OSOITTIMET TIETUEESEEN.....33

C++-kieli

Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved.

92

Muodostimen parametrit voivat sisältää tarvittaessa oletusarvoja. Seuraavassa esimerkissä parametrillinen muodostin alustaa vuosiluvun vakioarvolla 99, jos luonnin yhteydessä ei vuosilukua ole välitetty parametrina.

0 #include <iostream>1 using namespace std ;23 class Pvm4 {5 private:6 int pp, kk, vv ;7 public:8 Pvm (int, int, int = 99) ;9 void Nayta() const ;10 };

11 Pvm::Pvm (int p_pp, int p_kk, int p_vv)13 {14 pp = p_pp ;15 kk = p_kk ;16 vv = p_vv ;14 }

15 void Pvm::Nayta() const16 {17 cout<<pp<<'/'<<kk<<'/'<<vv ;18 }

19 int main()20 {21 Pvm Paiva1 (13, 12) ;22 Pvm Paiva2 (16, 10, 98) ;23 cout << “Päivä1: “ ;24 Paiva1.Nayta();25 cout << “Paiva2: “ ;26 Paiva2.Nayta() ;2728 return 0 ;

}

Kuva 22-10. Parametrillinen muodostin Pvm-luokassa.

Paiva1: 13 / 12 / 99Paiva1: 16 / 10 / 98

Kuva 22-11. Edellisen esimerkin tulostus. 22.4 Kopiointimuodostin Kopiointimuodostin (Copy constructor) alustaa olion tietojäsenet saman luokan jo olemassa olevalla olion tiedoilla. Kääntäjä generoi kopiointimuodostimen, joka kopioi uudelle oliolle parametrina välitetyn saman luokan olion tietojäsenten sisällön. Ohjelmoija voi määritellä kopiointimuodostimen myös itse, jos kääntäjän generoiman muodostimen toiminta ei ole täysin sopiva ko. tilanteessa.

Kun vanha olio on automaattinen:Luokka Olio ( Vanha_olio ) ;Luokka Olio = Vanha_olio ;

Kun vanha olio on dynaaminen:Luokka Olio ( *Vanha_olio ) ;Luokka Olio = *Vanha_olio ;

Kuva 22-12. Automaattisen olion tilanvaraus ja kopiointimuodostimen kutsu.

Page 94: C++-KIELI - Oamkjjauhiai/opetus/olio/Olio-ohjelmointi-40.pdf · 2007. 1. 5. · C++-kieli Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved. 4 5.7.2 OSOITTIMET TIETUEESEEN.....33

C++-kieli

Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved.

93

Osoitinmuuttujan esittely:Luokka *Olio ;

Kun vanha olio on automaattinen:Luokka Olio = new Luokka ( Vanha_olio ) ;

Kun vanha olio on dynaaminen:Luokka Olio = new Luokka ( *Vanha_olio ) ;

Kuva 22-13. Dynaamisen olion tilanvaraus ja kopiointimuodostimen kutsu. Ohjelmoija voi myös itse määritellä kopiointimuodostimen. Tällöin kopiointimuodostimen esittelyssä ja määrittelyssä noudatetaan samoja sääntöjä kuin oletusmuodostimen yhteydessä. Lisäksi on seuraavat säännöt:

• Kopiointimuodostimen ensimmäinen parametri on viittaus saman luokan olioon. Viittaus voi olla määritelty myös vakioksi const-määreellä. • Kopiointimuodostimen muilla mahdollisilla parametreilla tulee olla oletusarvo. • Jos ohjelmoija määrittelee kopiointimuodostimen, ei kääntäjä generoi oletusmuodostinta.

Luokka ( const Luokka ) ;

Luokka ( const Luokka &, Parametri = Alustusarvo, … ) ;

Kuva 22-14. Kopiointimuodostimen esittelytavat. Kopiointimuodostimen ensimmäisen parametrin on aina oltava viittaus saman luokan olioon. Yleensä viittaus määritellään vakioksi varatulla sanalla const. Kääntäjän generoima kopiointimuodostin on ensimmäisellä rivillä olevan mallin mukainen. const-määreellä osoitetaan se, että muodostin ei voi muuttaa parametrina saamansa olion tietoja. Tarvittaessa kopiointimuodostimelle voidaan esitellä useita parametreja. Kopiointimuodostinta on kuitenkin pystyttävä aina kutsumaan vain yhdellä olioparametrilla. Siksi kaikilla muilla parametreilla on oltava oletusarvot. Kopiointimuodostimella on tämä vaatimus siitä syystä, että järjestelmä kutsuu joissakin tilanteissa itse automaattisesti kopiointimuodostinta väliaikaisen olion luontia varten ja tällöin parametrina välittyy ainoastaan yksi olioparametri. 22.5 Esimerkkejä 22.5.1 Stack.cpp Ohjelmassa Stack.cpp määritellään yksinkertainen pinoluokka ’Stack’ sekä käytetään kyseistä luokkaa. Luokan määrittely alkaa varatulla sanalla class ja päättyy puolipisteeseen ’;’. Funktioita joiden nimi alkaa Stack:: ovat luokan Stack jäsenfunktioita. public-alueella määritellyt jäsenet ovat näkyvissä luokkamäärittelyn ulkopuolella. public-alueella määritellään yleensä jäsenfunktioita (ulospäin näkyvät). protected-alueella olevat jäsenet eivät näy luokan ulkopuolisille funktioille. protected-alueella määritellään yleensä datajäsenet. Pinoluokan pino-oliolle voidaan suorittaa kaksi perusoperaatiota:

• push operaatio panee argumenttina tulleen arvon pinon päällimmäiseksi. • pop operaatio lukee päällimmäisimmän arvon pois pinosta.

Konstruktori Jäsenfunktio jolla on sama nimi kuin luokalla itsellään (Tässä tapauksessa Stack), on kyseisen luokan konstruktorifunktio. Konstruktoreita kutsutaan myös muodostimiksi, jotka muodostavat luokan oliot.

Page 95: C++-KIELI - Oamkjjauhiai/opetus/olio/Olio-ohjelmointi-40.pdf · 2007. 1. 5. · C++-kieli Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved. 4 5.7.2 OSOITTIMET TIETUEESEEN.....33

C++-kieli

Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved.

94

Konstruktorifunktion erityispiirteitä:

• Konstruktori on aina luokan jäsenfunktio. • Sama nimi kuin itse luokalla. • Muodostimia kutsutaan automaattisesti, kun luokasta luodaan instanssi. Konstruktori siis luo, konstruoi, instanssin eli kyseisen luokan olion.

�Esimerkiksi, kun ohjelmassa main kirjoitetaan: Stack OmaPino ;

�Luodaan yksi instanssi (olio) luokasta Stack. Tällöin kääntäjä generoi automaattisesti ohjelmakoodin, joka kutsuu luokan konstruktorifunktiota. �Voidaan sanoa, että konstruktorifunktion kutsuminen tapahtuu implisiittisesti, ts.

konstruktorifunktiota ei tarvitse koskaan erikseen kutsua. �Voidaan myös sanoa, että olion luomiseen on piilotettuna kutsu luokan

konstruktorifunktioon. • Konstruktorin ohjelmakoodissa ei esitetä mitään paluuarvon tyyppiä:

Luokan_nimi::Luokan_nimi ( Parametrit ){

// Konstruktorin ohjelmakoodi.}

Jäsenfunktio Yleisesti jäsenfunktioiden ohjelmakoodi pitää kirjoittaa muotoon:

Tyyppi Luokan_nimi::Jäsenfunktion_nimi ( Parametrit ){

// Jäsenfunktion ohjelmakoodi.}

:: on ns. scope-operaattori, jolla luokan nimi ja jäsenfunktion nimi yhdistetään. Olioon liittyvään luokan jäsenfunktioon viitataan pisteoperaattorilla seuraavasti: Olion_nimi.Jäsenfunktion_nimi ( Parametrit ) ;

/*Stack.h

Otsikkotiedosto joka sisältää 'Stack'-luokan määrityksen.(c) Markku Rahikainen, 2003

*/

#define PINON_KOKO 50

class Stack{protected:

int PinossaOlevienNumeroidenLkm ;int Pino [PINON_KOKO] ;

public:Stack () ;~Stack () ;

void Push (int Numero) ;void Pop (int& Numero) ;

int OnkoPinoTyhja () ;int NumeroidenLkm () ;

} ;

Page 96: C++-KIELI - Oamkjjauhiai/opetus/olio/Olio-ohjelmointi-40.pdf · 2007. 1. 5. · C++-kieli Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved. 4 5.7.2 OSOITTIMET TIETUEESEEN.....33

C++-kieli

Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved.

95

// Luokan Pino konstruktori (Muodostin).Stack::Stack(){

PinossaOlevienNumeroidenLkm = 0 ;}

// Luokan Pino destruktori (Hajotin).Stack::~Stack(){

;}

void Stack::Push(int Numero){

if (PinossaOlevienNumeroidenLkm >= PINON_KOKO){

cout << endl << "Virhe: Pino on jo täysi !" << endl ;}else{

Pino [PinossaOlevienNumeroidenLkm] = Numero ;PinossaOlevienNumeroidenLkm++ ;

}}

// Huomaa, että tässä metodissa tehdään viittaus// parametrina välitettävään muuttujaan.void Stack::Pop(int& Numero){

if (PinossaOlevienNumeroidenLkm == 0){

cout << endl << "Virhe: Pino on tyhja !" << endl ;}else{

PinossaOlevienNumeroidenLkm-- ;Numero = Pino [PinossaOlevienNumeroidenLkm] ;

}}

int Stack::OnkoPinoTyhja(){

// Jos pinossa olevien numeroiden lkm. on// nolla, niin paluuarvona on 1 eli pino// on tyhjä. Muutoin paluuarvona on 0 eli// pinossa on numeroita.return (PinossaOlevienNumeroidenLkm == 0) ;

}

int Stack::NumeroidenLkm(){

return PinossaOlevienNumeroidenLkm ;}

Kuva 22-15. Stack.h.

/*Stack.c

Ohjelma joka käyttää Stack.h tiedostossa olevaa 'Stack'-luokkaa.(c) Markku Rahikainen, 2003

*/#include <iostream>using namespace std ;#include "Stack.h"

Page 97: C++-KIELI - Oamkjjauhiai/opetus/olio/Olio-ohjelmointi-40.pdf · 2007. 1. 5. · C++-kieli Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved. 4 5.7.2 OSOITTIMET TIETUEESEEN.....33

C++-kieli

Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved.

96

int main (){

int Luku ;

// Luodaan pino-olio.Stack OmaPino ;

// Syotetään lukija ja viedään ne pinoon. Kun syötetään// luku 0, niin lukujen syöttäminen loppuu.do{

cout << "Syota luku: " ;cin >> Luku ;OmaPino.Push(Luku) ;

} while (Luku > 0) ;

// Tarkistetaan onko pino tyhjä.if (OmaPino.OnkoPinoTyhja()){

cout << endl << "Pino on tyhja !" << endl ;}else{

cout << endl << "Pinossa on " << OmaPino.NumeroidenLkm() ;cout << " numeroa." << endl ;

}

// Lutaan numerot pinosta.while (!OmaPino.OnkoPinoTyhja()){

OmaPino.Pop(Luku) ;cout << Luku << endl ;

}

return 0 ;}

Kuva 22-16. Stack.cpp.

Kuva 22-17. Ohjelman Stack.cpp esimerkkitulostus.

Page 98: C++-KIELI - Oamkjjauhiai/opetus/olio/Olio-ohjelmointi-40.pdf · 2007. 1. 5. · C++-kieli Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved. 4 5.7.2 OSOITTIMET TIETUEESEEN.....33

C++-kieli

Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved.

97

23. HAJOTIN (Destructor) Hajotin on luokan metodi, jonka toiminta on käänteinen muodostimen toimintaan nähden. Hajottimen tarkoituksena on tyhjentää olion tietojäsenet ja vapauttaa olion sisäiset rakenteet. Järjestelmä kutsuu hajotinta olion tilanvapautuksen yhteydessä automaattisesti. Hajotinta voidaan kutsua ohjelmallisesti myös ennen olion tilanvapautusta, kun olio halutaan väliaikaisesti tyhjentää. Tämä ei kuitenkaan ole tavallista. Kääntäjä generoi luokalle hajottimen, jos ohjelmoija ei sitä itse kirjoita. Kääntäjän generoima hajotin ei varsinaisesti tee mitään. Hajottimella on erityistä merkitystä, jos luokassa on esitelty dynaamisia tietojäseniä. Ohjelmoija voi esitellä ja määritellä hajottimen tarvittaessa. Hajottimen esittelyssä ja määrittelyssä on seuraavat säännöt:

• Hajottimen nimi on luokan nimi ja sen edessä on merkki ~. • Hajotin ei saa parametreja. • Hajottimella ei ole tyyppiä (Ei edes void), hajotin ei siis palauta mitään arvoa return-lauseella. • Hajottimen esittelyssä ei saa esiintyä varattuja sanoja const, explicit, volatile tai static. • Hajotin voi olla virtuaalinen, jolloin esittelyn yhteydessä on sana virtual. Virtuaalinen hajotin liittyy periytymiseen.

Hajottimen kutsu tapahtuu automaattisesti olion tilanvapautuksen yhteydessä. Automaattisen olion yhteydessä tämä tapahtuu olion luoneen lohkon päättyessä. Dynaamisten olioiden yhteydessä delete-operaattorin käyttö aiheuttaa hajottimen kutsun. Hajotinta voidaan kutsua ennen tilanvapautusta olion väliaikaista tyhjentämistä varten seuraavalla tavalla.

Olio.Luokka::~Luokka() ;Olio->Luokka::~Luokka() ;

Kuva 23-1. Hajottimen kutsu olion väliaikaista tyhjentämistä varten. Ensimmäisellä rivillä olevaa kutsumuotoa on käytettävä, jos Olio on automaattinen. Toisella rivillä oleva kutsumuoto on tarkoitettu dynaamisen Olion tyhjentämistä varten. Yleensä ohjelmoijan ei tarvitse kutsua hajotinta, vaan järjestelmä kutsuu sitä automaattisesti olion tilanvapautuksen yhteydessä.

class Luokka{

…public:

~Luokka ( ) ;};

Kuva 23-2. Hajottimen esittely.

Luokka::~Luokka(){

Tietojäsenten tyhjennys.}

Kuva 23-3. Hajottimen määrittely eli toteutus.

Page 99: C++-KIELI - Oamkjjauhiai/opetus/olio/Olio-ohjelmointi-40.pdf · 2007. 1. 5. · C++-kieli Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved. 4 5.7.2 OSOITTIMET TIETUEESEEN.....33

C++-kieli

Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved.

98

Esimerkki

1 #include <iostream>2 using namespace std ;3 #include <ctime>

4 class Pvm5 {6 private:6 int pp, kk, vv;7 public:8 Pvm (int, int);9 ~Pvm ();10 void Nayta () const;11 };

12 Pvm::Pvm(int p_pp, int p_kk)13 : pp(p_pp), kk(p_kk)14 {15 time_t sek;16 tm *paiva;17 time (&sek);18 paiva = localtime (&sek);19 vv = paiva->tm_year;20 }

21 Pvm::~Pvm()22 {23 pp = 0;24 kk = 0;25 vv = 0;26 }

27 void Pvm::Nayta() const28 {29 cout<<pp<<'/'<<kk<<'/'<<vv;30 }

31 int main()32 {33 cout << "Päivä1: ";34 Pvm Paiva1 (1, 2);35 Paiva1.Pvm::~Pvm(); // Kutsutaan hajotinta.36 Paiva1.Nayta ();

37 cout << "\nPäivä2: ";38 Pvm *Paiva2 = new Pvm (2, 2);39 Paiva2->Pvm::~Pvm (); // Kutsutaan hajotinta.40 Paiva2->Nayta ();41 delete Paiva2; // Kutsutaan hajotinta.

42 return 0;43 } // Kutsutaan hajotinta.

Kuva 23-4. Pvm-luokan hajotin.

0 / 0 / 00 / 0 / 0

Kuva 23-5. Edellisen esimerkin tulostus. Rivillä 9 on esitelty hajotin, joka on toteutettu riveillä 21-26. Hajotin alustaa datajäsenet nolliksi. Riveillä 34 ja 38 näkyy olioiden luonti parametrillista muodostinta käyttäen. Kumpikin olio saa eri alkuarvot. Ohjelman tuloste sisältää kuitenkin pelkkiä nollia, koska oliot on tyhjennetty hajotinta kutsumalla riveillä 35 ja 39 ennen Nayta-viestin lähettämistä. Hajotin tulee tulee kutsutuksi vielä rivillä 41, kun dynaaminen olio vapautetaan ja rivillä 43, kun automaattinen olio vapautetaan. Ohjelma kutsuu hajotinta siis yhteensä neljä kertaa.

Page 100: C++-KIELI - Oamkjjauhiai/opetus/olio/Olio-ohjelmointi-40.pdf · 2007. 1. 5. · C++-kieli Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved. 4 5.7.2 OSOITTIMET TIETUEESEEN.....33

C++-kieli

Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved.

99

Esimerkki

#include <iostream>using namespace std ;

class Kissa{private:

char Nimi [10] ;

public:Kissa(char KissanNimi[]) ;~Kissa( );

void Naukaise () ;};

Kissa::Kissa(char KissanNimi[]){

strcpy (Nimi, KissanNimi);cout << "\n Syntyi kissa jonka nimi on " << Nimi << "." << endl ;

}

Kissa::~Kissa(){

cout << "\n Kissa jonka nimi oli " << Nimi << " kuoli !" << endl ;}

void Kissa::Naukaise(){

cout << "\n Miau ! " << Nimi << " naukas." << endl ;}

int main (){

Kissa Katti("Katti");Kissa Misse("Misse");

cout << endl;

Katti.Naukaise();Misse.Naukaise();

cout << endl ;

return 0;}

Kuva 23-6. Hajottimen kutsuminen.

Kuva 23-7. Edellisen esimerkin tulostus.

Page 101: C++-KIELI - Oamkjjauhiai/opetus/olio/Olio-ohjelmointi-40.pdf · 2007. 1. 5. · C++-kieli Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved. 4 5.7.2 OSOITTIMET TIETUEESEEN.....33

C++-kieli

Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved.

100

23.1 Dynamisia tietojäseniä sisältävän olion tyhjennys ja hajotin Dynaamisia tietojäseniä sisältävän olion tietojäsenten tilanvaraukset eivät häviä automaattisesti samalla kertaa, kun olion tila vapautuu. Tästä syystä ohjelmoijan on toteutettava hajotin.

#include <iostream>using namespace std ;#include <cstring>

class Kissa{private:

char *DynaaminenNimi ;

public:Kissa(char KissanNimi[]) ;~Kissa() ;

void Naukaise() ;};

Kissa::Kissa(char KissanNimi[]){

19 DynaaminenNimi = new char [strlen(KissanNimi) + 1] ;strcpy (DynaaminenNimi, KissanNimi) ;cout << "\n Syntyi kissa jonka nimi on " << DynaaminenNimi << "." << endl ;

}

Kissa::~Kissa(){

cout << "\n Kissa jonka nimi oli " << DynaaminenNimi << " kuoli !" << endl ;cout << " Vapautetaan kuolleen kissan nimen varaama muisti. " << endl ;

if (DynaaminenNimi){

31 delete [] DynaaminenNimi ;DynaaminenNimi = NULL ;

}}

void Kissa::Naukaise(){

cout << "\n Miau ! " << DynaaminenNimi << " naukas." << endl ;}

int main (){

Kissa Katti("Katti") ;Kissa Misse("Misse") ;

cout << endl ;Katti.Naukaise() ;Misse.Naukaise() ;cout << endl ;

return 0 ;}

Kuva 23-8. Dynaamisen datajäsenen sisältävä olio.

Page 102: C++-KIELI - Oamkjjauhiai/opetus/olio/Olio-ohjelmointi-40.pdf · 2007. 1. 5. · C++-kieli Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved. 4 5.7.2 OSOITTIMET TIETUEESEEN.....33

C++-kieli

Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved.

101

Kuva 23-9. Edellisen esimerkin tulostus.

Rivillä 31 hajoitin vapauttaa muistitilan delete-operaattoria kutsumalla. NULL-arvo on sijoitettu DynaaminenNimi-muuttujaan siksi, että hajotinta on mahdollista kutsua olion tyhjennystarkoituksessa milloin tahansa. Tällöin NULL-arvoa vertaamalla voidaan estää suorituksenaikaisten virhetilanteiden syntyminen. Koska strlen-aliohjelma ei laske pituuteen mukaan merkkijonon lopetusmerkkiä, on varattavan tilan pituuteen lisättävä luku 1(Kts. Rivillä 19). 23.2 Esimerkkejä 23.2.1 Stackd.cpp Ohjelmassa Stackd.cpp esitellään luokka Dynamic_stack joka käyttää muistia dynaamisesti. Kyseisen luokan mukaiset pino-oliot kasvavat automaattisesti, kun pinolle varattu muistitila käy liian pieneksi. Stackd.cpp ohjelmassa pino kasvaa vakion STACK_INCREMENT_SIZE verran automaattisesti em. tapauksissa. Perustoiminnoiltaan Stackd.cpp on samanlainen kuin aiemmin esitelty stacks.cpp. Hajotin Jäsenfunktio, jonka nimi on ~Luokan_nimi, on ns. destruktorifunktio, jota kutsutaan automaattisesti silloin kun ko. luokan olio tuhoutuu. Destruktoria kutsutaan aina automaattisesti. Destruktorifunktion erityispiirteitä:

• Nimen täytyy olla ~Luokan_nimi. • Destruktoria eli hajotinta kutsutaan automaattisesti, kun luokasta luotu olio tuhotaan. • Oliohan on olemassa (Automaattinen olio) vain sen aaltosulkuparin sisällä missä se on määritelty. Kun ohjelman suoritus menee ko. aaltosulkujen ulkopuolelle, destruktorifunktiota kutsutaan automaattisesti. • Hajottimen ohjelmakoodissa ei esitetä mitään paluuarvon tyyppiä:

Luokan_nimi::~Luokan_nimi ( Parametrit ){

// Hajottimen ohjelmakoodi.}

Dynaamisen muistin käsittelystä C++-kielessä • Olio-ohjelmoinissa on oleellista että olioita voidaan luoda ja tuhota dynaamisesti ohjelman ajon aikana. Tätä varten C++ ohjelmiin linkataan mukaan dynaamista muistia. • C++-kielen operaattorilla new voidaan dynaamista muistia allokoida ohjelman käyttöön. Vastaavasti operaattorilla delete voidaan aiemmin allokoitu muisti palauttaa takaisin muistialtaaseen eli vapaaseen muistitilaan eli kekoon (Free store, Heap). • Muistin varaaminen new-operaattorilla:

Osoite = new tyyppi [ Koko ] ;

Page 103: C++-KIELI - Oamkjjauhiai/opetus/olio/Olio-ohjelmointi-40.pdf · 2007. 1. 5. · C++-kieli Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved. 4 5.7.2 OSOITTIMET TIETUEESEEN.....33

C++-kieli

Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved.

102

�Osoite: new-opwraattori palauttaa muistiosoitteen, joka talletetaan osoittimen arvoksi. �new: new, samoin kuin delete, on C++:n varattu sana. �Tyyppi: Tässä kerrotaan minkä tyyppiselle tietoelementille muistia varataan. Tässä voi luke esim. int,

float, long, tietue, tai olion nimi. �Koko: Hakasuluissa kerrotaan, paljonko muistia halutaan varata. Muistin määrä voidaan ilmaista

numeroin tai lausekkeella. �Jos muistinvaraus epäonnistuu osoittimen arvoksi palautuu 0.

• Muistin vapauttaminen delete-operaattorilla:

delete [ ] Osoite ;

Jos muisti on alun perin varattu taulukkomuodossa, niin vapautuksessa tarvitaan tyhjät hakasulut.

// Stackd.cpp//// A program that contains the definition of class Dynamic_stack and function// main that uses that stack. A dynamic stack is able to grow automatically// when the stack is found to be full. A larger memory space from free store// is allocated in these situations.//#include <iostream.h>#include <stdlib.h>#include <string.h>

#define STACK_INCREMENT_SIZE 5

// The following is the definition of class Dynamic_stack.class Dynamic_stack{public:

Dynamic_stack ( int requested_stack_size = STACK_INCREMENT_SIZE ) ;~Dynamic_stack ( ) ;void push ( int value_to_the_stack ) ;void pop ( int& value_from_the_stack ) ;int stack_is_not_empty ( ) ;

protected:int number_of_elements_in_stack ;int current_stack_size ;int* stack_memory_space ;

} ;

// The following is the constructor function of class Dynamic_stack.Dynamic_stack::Dynamic_stack( int requested_stack_size ){

stack_memory_space = new int [ requested_stack_size ] ;

if ( stack_memory_space == 0 ) {cout << "\n\nERROR: Failure in free store allocation.\n" ;current_stack_size = 0 ;

}else {

current_stack_size = requested_stack_size ;}

number_of_elements_in_stack = 0 ;}

// The following is the destructor function of class Dynamic_stack.Dynamic_stack::~Dynamic_stack(){

delete [ ] stack_memory_space ;}

// The following is the push function of class Dynamic_stack.void Dynamic_stack::push( int value_to_the_stack ){

if ( number_of_elements_in_stack >= current_stack_size ){

Page 104: C++-KIELI - Oamkjjauhiai/opetus/olio/Olio-ohjelmointi-40.pdf · 2007. 1. 5. · C++-kieli Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved. 4 5.7.2 OSOITTIMET TIETUEESEEN.....33

C++-kieli

Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved.

103

// We must increase the size of this stack instance.

int* new_stack_memory_space ;

new_stack_memory_space = new int [current_stack_size + STACK_INCREMENT_SIZE] ;

if ( new_stack_memory_space == 0 ){

cout << "\nERROR: Failure to allocate more space.\n" ;}else{

current_stack_size = current_stack_size + STACK_INCREMENT_SIZE ;

// We must first copy the old stack contents to the// new stack memory space and then we can delete the old// stack memory space.

for ( int stack_index = 0 ;stack_index < number_of_elements_in_stack ;stack_index ++ )

{new_stack_memory_space [ stack_index ] =

stack_memory_space [ stack_index ] ;}

delete [ ] stack_memory_space ;

stack_memory_space = new_stack_memory_space ;

// And finally we put the new value to the grown stack.stack_memory_space [ number_of_elements_in_stack ] = value_to_the_stack ;number_of_elements_in_stack ++ ;cout << "\nSTACK HAS BEEN GROWN.\n" ;

}}else{

// Here we push the new value to the stack which did not have to be enlarged.

stack_memory_space [ number_of_elements_in_stack ] = value_to_the_stack ;number_of_elements_in_stack ++ ;

}}

// The following is the pop function of class Dynamic_stack.void Dynamic_stack::pop( int& value_from_the_stack ){

if ( number_of_elements_in_stack == 0 ){

cout << "\nERROR: Attempt to pop on empty stack !!\n" ;}else{

number_of_elements_in_stack -- ;value_from_the_stack = stack_memory_space [ number_of_elements_in_stack ] ;

}}

// The following is the stack_is_not_empty function of class Dynamic_stack.int Dynamic_stack::stack_is_not_empty( ){

return ( number_of_elements_in_stack > 0 ) ;}

// The following is the main function that use class Dynamic_stack.void main ( ){

int value_to_the_stack ;int value_popped_from_the_stack ;

Dynamic_stack test_stack ;

Page 105: C++-KIELI - Oamkjjauhiai/opetus/olio/Olio-ohjelmointi-40.pdf · 2007. 1. 5. · C++-kieli Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved. 4 5.7.2 OSOITTIMET TIETUEESEEN.....33

C++-kieli

Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved.

104

cout << "\nLet us test a stack. Please, type in integer"<< "\nnumbers. I will put those numbers into a stack and"<< "\nlater read them away from the stack. I will stop"<< "\nreading the numbers when you enter a zero."<< "\nPlease, hit Enter after each number. \n\n" ;

do{

cout << "Give a number: " ;cin >> value_to_the_stack ;

test_stack.push( value_to_the_stack ) ;}while ( value_to_the_stack != 0 ) ;

cout << "\nThe numbers popped from the stack are: \n\n" ;

while ( test_stack.stack_is_not_empty( ) ){

test_stack.pop( value_popped_from_the_stack ) ;cout << value_popped_from_the_stack << " " ;

}

cout << "\n\nLet us then put the characters of a string into"<< "\nanother stack and reverse the string by popping the"<< "\ncharacters away from the stack." ;

Dynamic_stack another_stack ;

char string_from_keyboard [ 80 ] ;

cout << "\n\nPlease, give me a string: " ;cin >> string_from_keyboard ;

int string_length = strlen ( string_from_keyboard ) ;

for (int string_index = 0; string_index < string_length ; string_index++){

another_stack.push( string_from_keyboard [ string_index ] ) ;}

cout << "\nThe string in reverse order: " ;

int integer_from_stack ;char character_from_stack ;

while ( another_stack.stack_is_not_empty( ) ){

another_stack.pop( integer_from_stack ) ;character_from_stack = integer_from_stack ;cout << character_from_stack ;

}

} // End of main.

Kuva 23-10. Ohjelma Stackd.cpp.

Page 106: C++-KIELI - Oamkjjauhiai/opetus/olio/Olio-ohjelmointi-40.pdf · 2007. 1. 5. · C++-kieli Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved. 4 5.7.2 OSOITTIMET TIETUEESEEN.....33

C++-kieli

Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved.

105

Kuva 23-11. Ohjelman Stackd.cpp esimerkkitulostus.

Page 107: C++-KIELI - Oamkjjauhiai/opetus/olio/Olio-ohjelmointi-40.pdf · 2007. 1. 5. · C++-kieli Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved. 4 5.7.2 OSOITTIMET TIETUEESEEN.....33

C++-kieli

Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved.

106

24. this-OSOITIN (this-pointer, this-pointteri) Viestin lähettäminen luokkaan luodulle oliolle on luokan metodin kutsu. Metodi käsittelee sen olion tietojäseniä, jolle viesti on saapunut. Eri kutsukerroilla sama metodi siis käsittelee eri olioiden tietojäseniä. Mistä metodi tietää, minkä olion tietoja se käsittelee, kun metodissa viitataan tietojäseniin ilman erityistä olion tunnusta ? C++-kielessä this-pointteri sisältää viestin saaneen olion keskusmuistiosoitteen. this-osoitinta voidaan käyttää luokkaan kuuluvissa aliohjelmissa. Osoittimeen ei voi viitata main-ohjelmassa tai missään luokan ulkopuolisessa luokkaan kuulumattomassa aliohjelmassa.

Luokan_nimi *const this ;

Kuva 24-1. this-pointteri on C++-kielessä valmiiksi esitelty. Osoittimen esittelyssä varattu sana const tekee osoittimesta vakion. Osoittimen arvoa ei voi muuttaa, mutta osoitetun olion tietoja voi muuttaa. Ohjelmoija ei itse esittele this-osoitinta, vaan se on oletusarvoisesti aina olemassa luokan metodissa. Aina kun luokan metodissa esiintyy viittaus luokan jäseniin, järjestelmä käyttää this-osoitinta.

1. cout << “\n Sosiaaliturvatunnus: “ << sotu ;2. cout << “\n Sosiaaliturvatunnus: “ << this->sotu ;

Kuva 24-2. Kuvan merkinnät ovat identtiset. Edellä olevat rivit sijaitsevat luokan metodissa. C++ löytää oikean olion tiedon this-pointterin avulla. C++ tulkitsee rivin 1 koodirivin rivin 2 mukaiseksi. Kumpaakin kirjoitustapaa voidaan käyttää myös käytännössä, vaikka rivin 1 kirjoitustapa on normaali kirjoituskäytäntö. this-osoitinta käytetään luokan metodeissa yleensä parametrinvälityksessä. Koska oliot tarvitsevat viestin välittämisessä toistensa osoitteita, metodissa käsiteltävän olion keskusmuistiosoite voidaan välittää parametrina jollekin toiselle aliohjelmalle. this-osoitinta voidaan käyttää apuna myös testausvaiheessa, kun halutaan selvittää eri olioiden olemassaoloaikaa ja siirtymistä näkyvyysalueelta toiselle.

#include <iostream>using namespace std ;

class Pvm{private:

int pp, kk, vv ;public:

Pvm() ;~Pvm() ;

};

Pvm::Pvm(){

cout << "\n Luotu olio: " << this << endl ;}

Pvm::~Pvm(){

cout << "\n Tuhottu olio: " << this << endl ;}

int main (){

Pvm Paiva1 ;Pvm *Paiva2 = new Pvm ;delete Paiva2 ;

Page 108: C++-KIELI - Oamkjjauhiai/opetus/olio/Olio-ohjelmointi-40.pdf · 2007. 1. 5. · C++-kieli Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved. 4 5.7.2 OSOITTIMET TIETUEESEEN.....33

C++-kieli

Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved.

107

return 0 ;}

Kuva 24-3. Pvm-luokan muodostimen ja hajottimen kutsuhetki havainnollistettu this-pointterin avulla.

Kuva 24-4. Edellisen esimerkin tulostus.

#include <iostream>using namespace std ;#include <cstring>

class Auto{private:

char Automerkki [20] ;char Autotyyppi [20] ;

public:Auto (char Merkki [ ], char Tyypi [ ]) ;void KutsuAutoa (const Auto &KutsuttuAuto) ;

};

// Muodostin (Constructor).Auto::Auto (char Merkki [ ], char Tyyppi [ ]){

strcpy (Automerkki, Merkki) ;strcpy (Autotyyppi, Tyyppi) ;

}

void Auto::KutsuAutoa (const Auto &KutsuttuAuto){

if (this == &KutsuttuAuto){

cout << "\n Virhe! Auto-olio kutsui itseaan ! \n" ;}else{

cout << "\n Hinausauto on tulossa ! \n" ;}

}

int main ( ){

// Luodaan autoluokasta olioita.Auto Hinuri ("Sisu", "Hinausauto") ;Auto Kaahariauto ("Audi", "Henkiloauto") ;

// Kutsutaan toista autoa.Kaahariauto.KutsuAutoa(Hinuri) ;Hinuri.KutsuAutoa(Hinuri) ;

cout << "\n" ;

return 0 ;}

Kuva 24-5. Esimerkki this-osoittimen käytöstä.

Page 109: C++-KIELI - Oamkjjauhiai/opetus/olio/Olio-ohjelmointi-40.pdf · 2007. 1. 5. · C++-kieli Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved. 4 5.7.2 OSOITTIMET TIETUEESEEN.....33

C++-kieli

Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved.

108

Kuva 24-6. Edellisen esimerkin tulostus.

24.1 Parametrilla ja datajäsenellä sama nimi Luokan metodin parametrin nimi voi olla sama kuin luokassa esitellyn tietojäsenen nimi. Tällöin parametrin nimi piilottaa datajäsenen nimen metodissa. Jos metodissa halutaan viitata datajäseneen, on tietojäsenen nimen yhteydessä käytettävä luokan nimeä tai this-osoitinta.

Luokka::Tietojäsenthis->Tietojäsen

Kuva 24-7. Viittaus tietojäseneen. Seuraavassa esimerkissä Kissa-luokkaan on toteutettu metodi, jossa parametrin nimi on sama kuin datajäsenen nimi.

#include <iostream>using namespace std ;#include <cstring>

class Kissa{private:

char Nimi [10] ;public:

Kissa(char KissanNimi[ ]) ;void VaihdaNimi (char Nimi [ ]) ;

};

Kissa::Kissa(char KissanNimi[ ]){

strcpy (Nimi, KissanNimi);cout << "\n Syntyi kissa jonka nimi on: " << Nimi << endl ;

}

void Kissa::VaihdaNimi(char Nimi[ ]){

strcpy (Kissa::Nimi, Nimi);cout << "\n Kissan nimi on nyt: " << this->Nimi << "\n\n" ;

}

int main (){

Kissa Katti(“Katti”) ;

Katti.VaihdaNimi("Rontti") ;

return 0 ;}

Kuva 24-8. Sama nimi parametrilla ja tietojäsenellä.

Page 110: C++-KIELI - Oamkjjauhiai/opetus/olio/Olio-ohjelmointi-40.pdf · 2007. 1. 5. · C++-kieli Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved. 4 5.7.2 OSOITTIMET TIETUEESEEN.....33

C++-kieli

Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved.

109

Kuva 24-9. Edellisen esimerkin tulostus.

Page 111: C++-KIELI - Oamkjjauhiai/opetus/olio/Olio-ohjelmointi-40.pdf · 2007. 1. 5. · C++-kieli Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved. 4 5.7.2 OSOITTIMET TIETUEESEEN.....33

C++-kieli

Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved.

110

25. 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 tyyppiin sidottua ohjelmakoodia. Malleja käytetään, kun samanlainen logiikka toistuu eri tietotyyppejä käytettäessä. Mallin avulla voidaan samasta lähdekoodista luoda uusia instansseja (Olioita) eri tyyppien käsittelyä varten kirjoittamatta lähdekoodia uudelleen. Malleja käytetään tyypillisesti tietorakenneluokkien toteuttamisessa. Mallien avulla voidaan rakentaa myös kokonaisia sovellusrunkoja. Malleilla ohjelmointi on ns. geneeristä ohjelmointia (Generic programming). Usein on ohjelmoitaessa tarve soveltaa samaa ohjelmalogiikkaa eri tilanteissa. Tämä on mahdollista malleja käyttämällä. Tällöin mallin lähdekoodissa ei viitata mihinkään tiettyyn tyyppiin tai luokkaan, vaan viittaukset korvataan viittauksilla generiseen tyyppiin, joka edustaa mitä tahansa tyyppiä. Geneerinen lähdekoodi ei ole kuitenkaan suoraan käännettävissä ja ajettavissa. Ajettava ohjelmakoodi saadaan aikaan instantioimalla mallista määrättyyn tyyppiin sidottu ohjelmakoodi. Kun malli otetaan käyttöön, korvautuu geneerinen tyyppi mallille parametrina välitetyllä tyypillä. Mallista voidaan käyttää myös nimitystä parametrisoitu tyyppi (Parametrized type). Mallit ovat aliohjelmamalleja (Function templates) tai luokkamalleja (Class templates). Aliohjelmamalli mahdollistaa yhden aliohjelman logiikan käyttämisen eri tyyppien yhteydessä. Luokkamallit mahdollistavat kokonaisen luokan ohjelmakoodin uudelleenkäytön uusille tyypeille. 25.1 Aliohjelmamallit Aina samanlaisena toistuva aliohjelmalogiikka voidaan kirjoittaa aliohjelmamalliksi (Function template), jota voidaan käyttää sopiville tietotyypeille. Ohjelmakoodia ei tarvitse kirjoittaa kuin kerran. Kääntäjä generoi aliohjelman kutsun yhteydessä käytettyyn tyyppiin sopivan aliohjelman. Ilman aliohjelmamalleja on usein kirjoitettava useita eri aliohjelmia, joissa logiikka on sama, mutta käsiteltävän tiedon tyyppi vaihtelee.

template <Geneerinen_tyyppi>Aliohjelman_toteutus

Kuva 25-1. Aliohjelmamallin esittely ja määrittely. Mallin esittely ja määrittely alkaa varatulla sanalla template. Sen jälkeen < > -merkkien väliin kirjoitetaan ohjelmakoodissa käytettävien geneeristen tyyppien tunnukset. Tyypin nimenä käytetään tavallisesti yhtä suurta kirjainta, esim. T. < > -merkkien välissä voi olla useita eri geneerisiä tyyppitunnuksia pilkuilla erotettuina. Kunkin tunnuksen eteen kirjoitetaan varattu sana class tai typename. typename on uusi lisäys C++-standardiin. Se ilmaisee class-sanaa paremmin, että tyyppiparametri voi olla muukin kuin luokka. typename ei välttämättä ole käytettävissä vanhemmissa ympäristöissä. Kun aliohjelmamallia on käytetty jossakin kohtaa ohjelmakoodia, kääntäjä instantioi aliohjelmasta tyyppikohtaisen aliohjelmainstanssin. Kääntäjä korvaa geneerisen tyypin T kutsussa käytetyn tiedon tyypillä.

#include <iostream>using namespace std ;

template <typename T>T Summa (T Luku1, T Luku2) ;

int main (){

int SummaInt = Summa (2, 5) ;cout << " Luku1 + Luku2 = " << SummaInt << endl ;

Page 112: C++-KIELI - Oamkjjauhiai/opetus/olio/Olio-ohjelmointi-40.pdf · 2007. 1. 5. · C++-kieli Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved. 4 5.7.2 OSOITTIMET TIETUEESEEN.....33

C++-kieli

Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved.

111

double SummaDouble = Summa (2.5, 10.2) ;cout << " Luku1 + Luku2 = " << SummaDouble << endl ;

char SummaChar = Summa ('A', '!' ); // Huom! A + ! = b (65 + 33 = 98).cout << " Merkki + Merkki = " << SummaChar << endl ;

return 0 ;}

template <typename T>T Summa (T Luku1, T Luku2){

return (Luku1 + Luku2) ;}

Kuva 25-2. Aliohjelmamallin määrittely ja käyttö. 25.2 Luokkamallit (Class template) Luokkamalli sisältää tarvittavat tietojäsenet ja geneeristä tietotyyppiä käsittelevät metodimallit. Luokkamallin avulla voidaan uudelleenkäyttää kaikkia luokan metodeita kirjoittamatta niitä uudelleen. Luokkamallin tyypillisiä käyttökohteita ovat mm. tietorakenneluokat. Luokkamallin määrittely ja luokkamallin metodien toteutus kirjoitetaan samaan tiedostoon. Luokkamalli metodeineen sijoitetaan otsikkotiedostoon (hpp). Metodeita ei sijoiteta erilliseen cpp-tiedostoon, koska ne eivät ole sellaisenaan käännettäviä. Metodit voidaan kääntää vasta, kun kääntäjä on korvannut geneerisen tyypin käytetyllä tyypillä tai luokalla. Malli on siis ohje kääntäjälle generoida uusi luokka. Vasta generoitu luokka on käännettävää ohjelmakoodia.

template <Geneerinen_tyyppi>class Malliluokka{};

Kuva 25-3. Luokkamallin määrittely. Luokkamallin määrittely aloitetaan varatulla sanalla template. Sen jälkeen < > -merkkien väliin kirjoitetaan ohjelmakoodissa käytettävien geneeristen tyyppien tunnukset samoin kuin aliohjelmamallien yhteydessä neuvottiin. Metodien esittelyn yhteydessä ei tarvitse käyttää merkintää template <typename T> tai template <class T>. Metodien toteutuksen yhteydessä ko. merkintä tarvitaan myös. Luokkamallin metodit toteutetaan metodimalleina. Kukin metodi määritellään kuten aliohjelmamallin yhteydessä oli esillä. Luokkamallin metodit toteutetaan luokan määrittelyn kanssa samaan tiedostoon. Kaikissa aliohjelmissa, joissa viitataan luokkamallista instantioitavaan luokkaan, merkitään luokan nimen yhteyteen geneerinen tyyppi.

Malliluokka <Geneerinen_tyyppi>

Kuva 25-4. Viittaus instantioitavaan luokkaan.

Luokkamallien ja metodimallien määrittely alkaa aina tekstillä template <class T>. Aina kun ohjelmakoodissa halutaan viitata talletettavan olion tyyppiin, käytetään tyyppinä geneeristä tyyppiä T. Aina kun ohjelmakoodissa halutaan viitata parametrisoidun tyypin perusteella instantioitavaan luokkaan, käytetään tyyppinä tyyppiä Luokan_nimi<T>. Luokkamalli sellaisenaan ei ole käännettävää ja suoritettavaa ohjelmakoodia. Luokkamalli saadaan käyttöön instantioimalla siitä uusi luokka parametreina välitetyn tyypin perusteella.

Page 113: C++-KIELI - Oamkjjauhiai/opetus/olio/Olio-ohjelmointi-40.pdf · 2007. 1. 5. · C++-kieli Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved. 4 5.7.2 OSOITTIMET TIETUEESEEN.....33

C++-kieli

Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved.

112

Malliluokka <Parametri> Olio ;

Kuva 25-5. Luokkamallin instantiointi ja käyttöönotto. Parametri on sen tyypin tai luokan nimi, jonka perusteella luokkamalli halutaan instantioida uudeksi luokaksi. Uudeksi instantioidun luokan tunnus on siis Malliluokka<Parametri>. Uuden luokan instantioinnin yhteydessä voidaan luoda olio uuteen luokkaan. Samaa luokkamallia voidaan käyttää nyt eri tilanteissa eri tyyppisten parametrien yhteydessä.

#include <iostream>using namespace std ;

template <class T>class Malli_Kissa{private:

char Nimi [20] ;T Paino ;

public:Malli_Kissa(char KissanNimi[]) ;~Malli_Kissa() ;

void AsetaPaino(T KissanPaino) ;void NaytaPaino() ;

};

template <class T>Malli_Kissa<T>::Malli_Kissa(char KissanNimi[]){

strcpy (Nimi, KissanNimi) ;}

template <class T>Malli_Kissa<T>::~Malli_Kissa(){}

template <class T>void Malli_Kissa<T>::AsetaPaino(T KissanPaino){

Paino = KissanPaino ;}

template <class T>void Malli_Kissa<T>::NaytaPaino(){

cout << "\n" << Nimi << " painaa " << Paino << " kiloa. \n" ;}

int main (){

Malli_Kissa<int> SuurpiirteinenKatti("SuurpiirteinenKatti") ;Malli_Kissa<double> TarkkaKatti("TarkkaKatti") ;

SuurpiirteinenKatti.AsetaPaino(3) ;TarkkaKatti.AsetaPaino(3.245) ;SuurpiirteinenKatti.NaytaPaino() ;TarkkaKatti.NaytaPaino() ;cout << endl ;

return 0 ;}

Kuva 25-6. Esimerkki luokkamallin käytöstä.

Page 114: C++-KIELI - Oamkjjauhiai/opetus/olio/Olio-ohjelmointi-40.pdf · 2007. 1. 5. · C++-kieli Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved. 4 5.7.2 OSOITTIMET TIETUEESEEN.....33

C++-kieli

Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved.

113

Kuva 25-7. Edellisen esimerkin tulostus.

25.3 Esimerkkejä 25.3.1 Stackt.cpp Ohjelmassa Stackt.cpp on aiemmin esitelty dynaaminen pinoluokka (Stackd.cpp ohjelmassa) muutettu templaattiluokaksi. template-luokkamäärittely • C++-kieli tarjoaa mahdollisuuden määritellä ns. templaattiluokkia (template classes), jotka eivät itse asiassa ole täydellisiä luokkia vaan niistä voidaan olioita luotaessa konfiguroida ”oikeita” luokkia. • Templaattiluokissa voidaan jättää esim. jokin tietotyyppi myöhemmin määriteltäväksi. • Templaattiluokat määritellään alkavaksi seuraavasti:

template <class Type>class Luokan_nimi{

�template on varattu sana templaattien määrittelyä varten. �class on varattu sana. �Type on ohjelmoijan itsensä valitsema tunnus. �Kulmasulkujen sisällä kerrotaan minkä suhteen luokkamäärittely on templaattinen.

• Varattu sana class on luettava myös jäsenfunktioiden alussa. Lisäksi templaattinen nimi tulee mainita luokan nimen perässä kulmasulkeissa.

template <class Type>void Luokan_nimi::<Type>::Jäsenfunktion_nimi (Parametrit ){

• Templaattiluokkaa käytettäessä luokka konfiguroidaan halutunlaiseksi kirjoittamalla todellinen tietotyyppi luokan nimen perään hakasulkeisiin.

Luokan_nimi<int> Olion_tunnus ;

Page 115: C++-KIELI - Oamkjjauhiai/opetus/olio/Olio-ohjelmointi-40.pdf · 2007. 1. 5. · C++-kieli Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved. 4 5.7.2 OSOITTIMET TIETUEESEEN.....33

C++-kieli

Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved.

114

//// stackt.cpp//// A program that contains the definition of class template// Template_stack and function main that uses that stack// template to build stacks that can contain different// types of stack elements.#include <iostream.h>#include <stdlib.h>#include <string.h>

#define STACK_INCREMENT_SIZE 5

template <class Type>class Template_stack{public:

Template_stack ( int requested_stack_size = STACK_INCREMENT_SIZE ) ;~Template_stack ( ) ;

void push ( Type value_to_the_stack ) ;void pop ( Type& value_from_the_stack ) ;int stack_is_not_empty ( ) ;

protected:int number_of_elements_in_stack ;int current_stack_size ;Type* stack_memory_space ;

} ;

template <class Type>Template_stack<Type>::Template_stack( int requested_stack_size ){

stack_memory_space = new Type [ requested_stack_size ] ;

if ( stack_memory_space == 0 ){

cout << "\n\nERROR: Failure in free store allocation.\n" ;current_stack_size = 0 ;

}else{

current_stack_size = requested_stack_size ;}

number_of_elements_in_stack = 0 ;}

template <class Type>Template_stack<Type>::~Template_stack(){

delete [ ] stack_memory_space ;}

template <class Type>void Template_stack<Type>::push( Type value_to_the_stack ){

if ( number_of_elements_in_stack >= current_stack_size ){

// We must increase the size of this stack instance.

Type* new_stack_memory_space ;

new_stack_memory_space = new Type [ current_stack_size +STACK_INCREMENT_SIZE ] ;

if ( new_stack_memory_space == 0 ){

cout << "\nERROR: Failure to allocate more space.\n" ;}else

Page 116: C++-KIELI - Oamkjjauhiai/opetus/olio/Olio-ohjelmointi-40.pdf · 2007. 1. 5. · C++-kieli Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved. 4 5.7.2 OSOITTIMET TIETUEESEEN.....33

C++-kieli

Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved.

115

{current_stack_size = current_stack_size + STACK_INCREMENT_SIZE ;

// We must first copy the old stack contents to the// new stack memory space and then we can delete the old// stack memory space.

for ( int stack_index = 0 ;stack_index < number_of_elements_in_stack ;stack_index ++ )

{new_stack_memory_space [ stack_index ] =

stack_memory_space [ stack_index ] ;}

delete [ ] stack_memory_space ;

stack_memory_space = new_stack_memory_space ;

// And finally we put the new value to the grown stack.

stack_memory_space [ number_of_elements_in_stack ] = value_to_the_stack ;number_of_elements_in_stack ++ ;cout << "\nSTACK HAS BEEN GROWN.\n" ;

}}else{

// Here we push the new value to the stack which did not// have to be enlarged.

stack_memory_space [ number_of_elements_in_stack ] = value_to_the_stack ;number_of_elements_in_stack ++ ;

}}

template <class Type>void Template_stack<Type>::pop( Type& value_from_the_stack ){

if ( number_of_elements_in_stack == 0 ){

cout << "\nERROR: Attempt to pop on empty stack !!\n" ;}else{

number_of_elements_in_stack -- ;value_from_the_stack =

stack_memory_space [ number_of_elements_in_stack ] ;}

}

template <class Type>int Template_stack<Type>::stack_is_not_empty(){

return ( number_of_elements_in_stack > 0 ) ;}

void main (){

int value_to_the_stack ;int value_popped_from_the_stack ;

Template_stack<int> integer_stack ;

cout << "\nLet us test a stack. Please, type in integer"<< "\nnumbers. I will put those numbers into a stack and"<< "\nlater read them away from the stack. I will stop"<< "\nreading the numbers when you enter a zero."<< "\nPlease, hit Enter after each number. \n\n" ;

do{

Page 117: C++-KIELI - Oamkjjauhiai/opetus/olio/Olio-ohjelmointi-40.pdf · 2007. 1. 5. · C++-kieli Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved. 4 5.7.2 OSOITTIMET TIETUEESEEN.....33

C++-kieli

Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved.

116

cout << "Give a number: " ;cin >> value_to_the_stack ;

integer_stack.push( value_to_the_stack ) ;}while ( value_to_the_stack != 0 ) ;

cout << "\nThe numbers popped from the stack are: \n\n" ;

while ( integer_stack.stack_is_not_empty( ) ){

integer_stack.pop( value_popped_from_the_stack ) ;

cout << value_popped_from_the_stack << " " ;}

cout << "\n\nLet us then put the characters of a string into"<< "\nthe stack and reverse the string by popping the"<< "\ncharacters away from the stack." ;

char string_from_keyboard [ 80 ] ;

cout << "\n\nPlease, give me a string: " ;cin >> string_from_keyboard ;

int string_length = strlen ( string_from_keyboard ) ;

Template_stack<char> character_stack ;

for ( int string_index = 0 ;string_index < string_length ;string_index ++ )

{character_stack.push( string_from_keyboard [ string_index ] ) ;

}

cout << "\nThe string in reverse order: " ;

char character_from_stack ;

while ( character_stack.stack_is_not_empty () ){

character_stack.pop( character_from_stack ) ;cout << character_from_stack ;

}

} // End of main.

Kuva 25-8. Ohjelma Stackt.cpp.

Kuva 25-9. Ohjelman Stackt.cpp esimerkkitulostus.

Page 118: C++-KIELI - Oamkjjauhiai/opetus/olio/Olio-ohjelmointi-40.pdf · 2007. 1. 5. · C++-kieli Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved. 4 5.7.2 OSOITTIMET TIETUEESEEN.....33

C++-kieli

Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved.

117

26. OPERAATTOREIDEN KUORMITUS (Operator overloading) Operaattoreiden kuormitus eli ylimäärittely tarkoittaa aliohjelman toteuttamista siten, että aliohjelman nimi on jokin operaattorimerkki. Aliohjelma voi kantaa nimenään mm. aritmeettista operaattoria tai vertailuoperaattoria. Kuormitetut operaattorit mahdollistavat vaikkapa merkkijono-olioiden yhteenliittämisen +-operaattorilla. Käytettäessä kuormitettuja operaattoreita muistuttaa ohjelmoijan määrittelemien luokkatyyppien käsittelytapa järjestelmässä määriteltyjen tyyppien käsittelyä. Kukin operaattori kuormitetaan omassa aliohjelmassaan. Operaattorin kuormitusaliohjelman nimi on operatorop, missä op on operaattorimerkki. Esimerkiksi operator+ voisi olla merkkijono-oliot yhdistävä aliohjelma.

+ - * / % ^ & | ~ != < > += -= *= /= %= ^= &=|= << >> >>= <<= == != <= >= &&|| ++ - - ->* , -> [ ] ( )

new delete

Kuva 26-1. C++-kielessä on mahdollista kuormittaa seuraavia operaattoreita. Operaattoreiden kuormituksessa on seuraavat säännöt:

• Kuormitettavien merkkien suoritusjärjestystä ei ole mahdollista muuttaa. • Alkuperäistä syntaksia ei voi muuttaa. • Yksioperandista operaatiota (Unaarioperaatiota) % ja kaksioperandista operaatiota (Binäärioperaatiota) ! ei ole mahdollista määritellä. • Uusia merkkejä ei voi määritellä. • Kuormitetulla operaattorilla täytyy olla ainakin yksi operandi, joka on käyttäjän omaa tyyppiä (Estää perustietotyypien kuormituksen). • Seuraavia operaattoreita ei voi kuormittaa:

�sizeof . .* :: ?: typeid const_cast dynamic_cast �reinterpret_cast static_cast

• Seuraavia operaattoreita voidaan kuormittaa ainoastaan luokkien aliohjelmajäsenillä: �= ( ) [ ] ->

• Operaattoreita ei voi kuormittaa static-aliohjelmissa. Jos yliluokkaan on määritelty jokin kuormitettu operaattori, se periytyy aliluokille tavallisten metodien tapaan. Poikkeuksena on kuitenkin sijoitusoperaattori, joka on toteutettava erikseen yli- ja aliluokille.

#include <iostream>using namespace std ;

class Plussa_eiku_Miinus{private:

int Taulukko [10] ;

public:Plussa_eiku_Miinus (int Alustusarvo) ;

void TulostaTaulukonSisalto () ;Plussa_eiku_Miinus operator+ (Plussa_eiku_Miinus &ToinenOlio) ;

};

Page 119: C++-KIELI - Oamkjjauhiai/opetus/olio/Olio-ohjelmointi-40.pdf · 2007. 1. 5. · C++-kieli Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved. 4 5.7.2 OSOITTIMET TIETUEESEEN.....33

C++-kieli

Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved.

118

Plussa_eiku_Miinus::Plussa_eiku_Miinus (int Alustusarvo){

for (int i=0; i<10; i++){

Taulukko [i] = Alustusarvo}

}

void Plussa_eiku_Miinus::TulostaTaulukonSisalto ( ){

cout << endl ;

for (int i=0; i<10; i++){

cout.width (3);cout << Taulukko [i] ;

}

cout << endl ;}

Plussa_eiku_Miinus Plussa_eiku_Miinus::operator+ (Plussa_eiku_Miinus &ToinenOlio){

// Luodaan uusi taulukko(olio) johon kahden// muun olion(taulukon) erotus sijoitetaan.Plussa_eiku_Miinus ErotusTaulukko(0) ;

for (int i=0; i<10; i++){

ErotusTaulukko.Taulukko[i] = Taulukko [i] - ToinenOlio.Taulukko[i] ;}

return ErotusTaulukko ;}

int main ( ){

// Luodaan Plussa_eiku_Miinus luokasta kaksi oliota.Plussa_eiku_Miinus EkaOlio (12) ;Plussa_eiku_Miinus TokaOlio (2) ;

EkaOlio.TulostaTaulukonSisalto () ;TokaOlio.TulostaTaulukonSisalto () ;

// Luodaan Erotus olio.Plussa_eiku_Miinus ErotusOlio (0) ;

// Operaattoria '+' on nyt ylikuormitetu niin, että// tuloksena onkin vähennyslasku. Eli tästä seuraa// jäsenfunktion Plussa_eiku_Miinus::operator+ kutsu.ErotusOlio = EkaOlio + TokaOlio ;

ErotusOlio.TulostaTaulukonSisalto() ;

cout << "\n" ;

return 0 ;}

Kuva 26-2. Esimerkki ‘+’ –operaattorin ylikuormittamisesta.

Page 120: C++-KIELI - Oamkjjauhiai/opetus/olio/Olio-ohjelmointi-40.pdf · 2007. 1. 5. · C++-kieli Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved. 4 5.7.2 OSOITTIMET TIETUEESEEN.....33

C++-kieli

Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved.

119

Kuva 26-3. Edellisen esimerkin tulostus.

26.1 Syöttö- ja tulostusoperaattorit >> ja << Perustietotyyppien syöttöön ja tulostukseen tarkoitetut operaattorit << ja >> on kuormitettu iostream-kirjaston (Aiemmin iostream.h) luokkiin. Ne ovat valmiita luokkia, joihin ohjelmoija ei voi lisätä uusia metodeita. Jos <<- ja >>-operaattoreita halutaan käyttää omien luokkien olioiden syöttöön ja tulostukseen, ne on määriteltävä kullekin ohjelmoijan määrittelemälle tyypille.

cout << Olio1 << Olio2 … ;

Kuva 26-4. Tulostusoperaattorin käyttö. Järjestelmä voi tulkita tulostusoperaattorin käytön kahdella eri tavalla. Se on joko viesti cout-oliolle tai globaalin luokkaan kuulumattoman aliohjelman kutsu. Tulostusoperaattoria voidaan käyttää myös tiedostoon tulostettaessa. Tällöin cout-olion tilalle kirjoitetaan käytettävän tiedosto-olion nimi.

cout.operator<<(Tulostettava_tieto) ;operator<<(cout, Tulostettava_tieto) ;

Kuva 26-5. Tulostusoperaattorin kutsun tulkintatavat. cout-olion tilalla voi olla myös tiedosto-olion nimi. Ensimmäinen tulkintatapa edellyttää, että tulostusoperaattori on toteutettu cout-olion luokkaan ostream. Tämä tulkintatapa koskee siis järjestelmässä määriteltyjä perustietotyyppejä. Koska ohjelmoija ei voi itse määritellä metodia ostream-luokkaan, on tulkintatapa alemman mallin mukainen silloin, kun tulostettava tieto on kokonainen olio. Alempi tulkintatapa tarkoittaa siis globaalia luokkaan kuulumatonta aliohjelmaa, joka käsittelee parametreina välitettyjä olioita. Operaattorialiohjelma on esiteltävä sen luokan ystäväksi, jonka olioita se käsittelee. Ilman ystäväksi määrittelemistä ei aliohjelma voi käsitellä olion tietojäseniä. Syöttö- ja tulostusoperaattoriohjelmien tulee palauttaa viittaus syöttö- tai tulostusvirtaan, jotta parametrien ketjutus olisi mahdollista. Syöttö ja tulostusvirta on iostream-luokan olio. Syöttö- ja tulostusoperaattorit eivät siten ole luokan metodeita vaan glopaaleja aliohjelmia.

ostream &operator << (ostream &, Luokka &) ;istream &operator >> (istream &, Luokka &) ;

Kuva 26-6. Syöttö- ja tulostusoperaattoreiden esittelyt. Ylempi malli on tulostusoperaattorin esittely. Aliohjelma palauttaa viittauksen tulostusvirtaan. Aliohjelma saa parametrina viittauksen tulostusvirtaolioon ja tulostettavan luokan olioon. Alempi malli on syöttöoperaattorin esittely, jonka parametrit ovat vastaavat.

Page 121: C++-KIELI - Oamkjjauhiai/opetus/olio/Olio-ohjelmointi-40.pdf · 2007. 1. 5. · C++-kieli Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved. 4 5.7.2 OSOITTIMET TIETUEESEEN.....33

C++-kieli

Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved.

120

#include <iostream.h>

class Plussa_eiku_Miinus{private:

int Taulukko [10] ;

public:Plussa_eiku_Miinus (int Alustusarvo) ;Plussa_eiku_Miinus operator+ (Plussa_eiku_Miinus &ToinenOlio) ;friend ostream& operator<< (ostream &Tulostus_virta, Plussa_eiku_Miinus &Tulostettava) ;

};

Plussa_eiku_Miinus::Plussa_eiku_Miinus(int Alustusarvo){

for (int i=0; i<10; i++){

Taulukko [i] = Alustusarvo ;}

}

Plussa_eiku_Miinus Plussa_eiku_Miinus::operator+ (Plussa_eiku_Miinus &ToinenOlio){

// Luodaan uusi taulukko(olio) johon kahden// muun olion(taulukon) erotus sijoitetaan.Plussa_eiku_Miinus ErotusTaulukko(0) ;

for (int i=0; i<10; i++){

ErotusTaulukko.Taulukko[i] = Taulukko [i] - ToinenOlio.Taulukko[i] ;}

return ErotusTaulukko ;}

ostream& operator<< (ostream &Tulostus_virta, Plussa_eiku_Miinus &Tulostettava){

Tulostus_virta << endl ;

for (int i=0; i<10; i++){

Tulostus_virta.width(3) ;Tulostus_virta << Tulostettava.Taulukko[i] ;

}

Tulostus_virta << endl ;

return Tulostus_virta;}

int main (void){

// Luodaan Plussa_eiku_Miinus luokasta kaksi oliota.Plussa_eiku_Miinus EkaOlio(12) ;Plussa_eiku_Miinus TokaOlio(2) ;

// Operattoria "<<" on nyt ylikuormitettu, joten// tästä generoituu funktion "operator<<" kutsu.cout << EkaOlio ;cout << TokaOlio ;

// Luodaan Erotus olio.Plussa_eiku_Miinus ErotusOlio(0) ;

// Operaattoria '+' on nyt ylikuormitetu niin, että// tuloksena onkin vähennyslasku. Eli tästä seuraa// jäsenfunktion Plussa_eiku_Miinus::operator+ kutsu.ErotusOlio = EkaOlio + TokaOlio ;

// Operattoria "<<" on nyt ylikuormitettu, joten// tästä generoituu funktion "operator<<" kutsu.cout << ErotusOlio ;

Page 122: C++-KIELI - Oamkjjauhiai/opetus/olio/Olio-ohjelmointi-40.pdf · 2007. 1. 5. · C++-kieli Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved. 4 5.7.2 OSOITTIMET TIETUEESEEN.....33

C++-kieli

Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved.

121

// Tässä "<<"-operaattoria käytetään normaalisti.cout << "\n" ;

return 0 ;}

Kuva 26-7. Esimerkki <<-operaattorin ylikuormittamisesta.

Kuva 26-8. Edellisen esimerkin tulostus.

26.2 Esimerkkejä 26.2.1 Darray.cpp Ohjelmassa Darray.cpp (Darray.h) tarkastellaan monimutkaisempia funktioiden ylikuormitustapauksia:

• Luokan konstruktoreiden (Muodostimien) ylikuormitus. • Normaalien operaattoreiden kuten << = [ ] ylikuormitus.

Ohjelmassa määritellään dynaamisen yksiuloitteisen taulukon (Dynamic array) toteuttava luokkan. Kyseistä taulukkoluokkaa voidaan käyttää mm. siten, että kysytään ohjelman käyttäjältä ohjelman suorituksen aikana, kuinka iso taulukko halutaan toteutettavaksi. Operaattorin = ylikuormituksen ansiosta dynaaminen taulukko voidaan kätevästi kopioida.

//// Darray.h//// Luokkan Dynamic_array määrittelytiedosto.//

class Dynamic_array{public:

// Konstruktorifunktiosta on neljä eri muotoa.Dynamic_array() ;Dynamic_array( unsigned int requested_array_size,

double initialization_value = 0.0 ) ;Dynamic_array( unsigned int requested_array_size,

const double another_array[ ] ) ;Dynamic_array( const Dynamic_array& another_dynamic_array ) ;

// Destruktori~Dynamic_array() ;

unsigned int get_array_size() ;

// Jäsenfunktiot jotka mahdollistavat operaattoreiden [ ], *, = ja << yli-// määrittämisen. Operaattoreiden ylikuormittamista varten on käytössä// varattu sana operator.

Page 123: C++-KIELI - Oamkjjauhiai/opetus/olio/Olio-ohjelmointi-40.pdf · 2007. 1. 5. · C++-kieli Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved. 4 5.7.2 OSOITTIMET TIETUEESEEN.....33

C++-kieli

Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved.

122

double& operator[ ] ( int array_index ) ;Dynamic_array operator* ( const Dynamic_array& another_dynamic_array ) ;Dynamic_array& operator= ( const Dynamic_array& another_dynamic_array ) ;

friend ostream& operator<< (ostream& array_output_stream,const Dynamic_array& dynamic_array_to_output ) ;

protected:unsigned int array_instance_size ; // Dynaamisen varauksen koko.double *array_in_free_store ; // Dynaamisen varauksen sijainti

// keskusmuistissa.} ;

Dynamic_array::Dynamic_array(){

// Siinä tapauksessa kun konstruktori funktiolle ei anneta yhtään// argumenttia, luotavan olion (instanssin) datajäsenet alustetaan// arvoon NULL ja 0.array_in_free_store = NULL ;array_instance_size = 0 ;

}

Dynamic_array::Dynamic_array( unsigned int requested_array_size,double initialization_value )

{array_in_free_store = new double[ requested_array_size ] ;array_instance_size = requested_array_size ;

for ( int array_index = 0 ;array_index < array_instance_size ;array_index ++ )

{array_in_free_store[ array_index ] = initialization_value ;

}}

Dynamic_array::Dynamic_array( unsigned int requested_array_size,/* Kun argumentti määritellään vakioksi varatulla

sanalla const, se takaa että tämä funktio ei voiko. argumenttia muuttaa. */

const double another_array[ ] ){

array_in_free_store = new double[ requested_array_size ] ;array_instance_size = requested_array_size ;

for ( int array_index = 0 ;array_index < array_instance_size ;array_index ++ )

{array_in_free_store[ array_index ] = another_array[ array_index ] ;

}}

// Tämä konstruktori ottaa parametrikseen toisen dynaamisen taulukon// eli luotava taulukko alustetaan toisen dynaamisen taulukon arvoilla.Dynamic_array::Dynamic_array(const Dynamic_array& another_dynamic_array ){

array_instance_size = another_dynamic_array.array_instance_size ;array_in_free_store = new double[ array_instance_size ] ;

for ( int array_index = 0 ;array_index < array_instance_size ;array_index ++ )

{array_in_free_store[ array_index ] =

// Koska tämä on luokan Dynamic_array jäsenfunktio,// tässä voidaan viitata luokan protected-jäseniin.another_dynamic_array.array_in_free_store[array_index ] ;

}

Page 124: C++-KIELI - Oamkjjauhiai/opetus/olio/Olio-ohjelmointi-40.pdf · 2007. 1. 5. · C++-kieli Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved. 4 5.7.2 OSOITTIMET TIETUEESEEN.....33

C++-kieli

Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved.

123

}

// Hajotin, hajottimen tehtävänä on tässä vapauttaa aiemmin olion konstruoinnin,// luomisen, yhteydessä varattu muisti vapaaltamuistialueelta.Dynamic_array::~Dynamic_array(){

delete array_in_free_store ;}

// Jäsenfunktio jolla saadaan selville taulukon koko. Koska luokan// ulkopuoliset funktiot eivät pääse lukemaan luokan protected-// muuttujia, niin tämäntyyppisiä jäsenfunktioita tarvitan.unsigned int Dynamic_array::get_array_size(){

return array_instance_size ;}

IKUORMITUS:

• Olio-ohjelmointiin keskeisesti kuuluvaa ylikuormitusmekanismia voidaan soveltaa myös C++kielen useimpiin operaattoreihin.

• Funktionimien ylikuormituksesta olemme oppineet, että ylikuormittaminen tarkoittaa, ettäsama nimi voi olla monella eri funktiolla. Ylikuormitettujenfunktioiden on erottava toisistaan argumenttien tyyppien ja/tailukumäärän suhteen. Funktioiden paluuarvojen tyypit voivat sensijaanolla samaa tai eri tyyppiä. Ylikuormitetulla funktionimellä ontavallaan monta merkitystä.

• Operaattoreiden esim. +, *, = jne. ylikuormitus tarkoittaa sitä, että keinotekoisestiannamme niille merkityksiä, joita niillä ei normaalisti C++ kielessäole.

• On huomattava, että jotkut operaattorit ovat jo luonnostaan ylikuormittuneita. Esimerkiksivoimme käyttää operaattoria ’+’ monentyyppisten muuttujien jalausekkeiden yhteenlaskuun, ja operaattorilla ’=’ voimme tehdäerityyppisiä sijoituksia.

• Yleensä on tapana ylikuormittaa aritmeettisia operaattoreita ja sijoitusoperaattoriatoimimaan olioilla. Tässä ohjelmassa näemme, että dynaaminen taulukkovoidaan kopioida toisen taulukon päälle operaattorilla ’=’:

ray = source_array ;

• Operaattoreiden ylikuormittamisella voidaan tehdä suppeita notaatioita. Sijoitusoperaatiovoitaisiin korvata myös seuraavanlaisella jäsenfunktion kutsulla:

ource_array, destination_array ) ;

• Operaattoreiden ylikuormittamisessa kannattaa olla säästeliäs. Sillä ei saavuteta muutakuin, että esimerkiksi ’copy_array’ tekstin kirjoittamisen sijastakirjoitetaan ’=´.

• Liiallisella ja harkitsemattomalla operaatioiden ylikuormitulksella voidaan vain lisätäohjelman minimutkaisuutta. On mahdollista määritellä merkki ’+’tarkoittamaan vähennyslaskua.

• Aeyraavassa on esimerkki operaattoreiden [ ], *, = ja << ylikuormittamisesta.*/

tio mahdollistaa sen, että voimme viitata luokan Dynamic_array mukaiseen taulukko-olioon normaaleillaC++-kielen taulukkoviittausmekanismeilla, so. asettamalla taulukon indeksi hakasulkeisiin olionnimen perään. Tässä tapauksessa operaattori [ ] on ylikuormitettu. */

tä ja varsinkin merkki ’&’ aiheuttaa sen, että kun tämän olioluokan olioon (instanssiin) viitataanesim.

ssa viitataan instanssille varatulle muistialueelle vapaassa muistissa. */double& Dynamic_array::operator[ ] ( int array_index ){

// This member function makes it possible to access// dynamic arrays with indices in brackets.return array_in_free_store[ array_index ] ;

}

likuormittaa kertolaskuoperaattoria ’*’.Dynamic_array Dynamic_array::operator* ( const Dynamic_array& another_dynamic_array ){

// This member function multiplies two dynamic arrays element by element.

Page 125: C++-KIELI - Oamkjjauhiai/opetus/olio/Olio-ohjelmointi-40.pdf · 2007. 1. 5. · C++-kieli Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved. 4 5.7.2 OSOITTIMET TIETUEESEEN.....33

C++-kieli

Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved.

124

if ( array_instance_size != another_dynamic_array.array_instance_size ) {// Jos kyseessä olevien keskenään kerrottavien dynaamisten taulukoiden// koot ovat erilaisia, kertolaskuoperaatiota ei voida suorittaa.cout << "Arrays with different sizes cannot be \n" ;cout << "multiplied with each other. \n" ;exit ( 1 ) ;

}

// Määritellään uusi dynaaminen taulukko, johon talletetaan kertolaskun tulos.Dynamic_array multiplication_result( array_instance_size ) ;

for ( int array_index = 0 ; array_index < array_instance_size ; array_index ++ ){

multiplication_result[ array_index ] = array_in_free_store[ array_index ] *another_dynamic_array.array_in_free_store[ array_index ] ;

}return multiplication_result ;

}

/* this-POINTTERI (OSOITIN):• this on C++-kielen varattu sana, avainsana.

• Jokaiselle luokasta luotavalle oliolle varataan tilaa vapaalta muistialueelta. esimerkiksijokaiselle dynaamisen taulukon oliolle varataan tilaa muuttujien

array_instance_size ja*array_in_free_store

talletukseen sekä lisäksi allokoidaan tila varsinaiselle taulukolle new operaattorilla.

• Joskus tulee tilanteita, jolloin pitää tietää luokan oliomuuttujien, siis tiettyyn olioon kuuluvienmuuttujien, osoite jäsenfunktiossa. this-pointteri osoittaa olion muuttujien osoitteeseen.

• Jäsenfunktiotahan kutsutaan aina tiettyyn luokasta luotuun olioon nähden, Jäsenfunktion kannaltakyseessä on ”Tämä” olio eli instanssi. Tästä tulee pointterin nimi ”this”.• Jäsenfunktio ei tiedä varsinaista olion nimeä. Esimerkiksi, jos Stack-luokan oliota käytetäänseuraavasti

test_stack.pop ( );niin jäsenfunktiossa pop ei tiedetä nimeä test_stack.

• this-pointteri on hyödyllinen joskus, esimerkiksi kun halutaan tietää ovatko kaksi luokan oliotasamoja vai eivät.*/

/* Tämä jäsenfunktio ylikuormittaa operaattoria ’=’. Argumenttina saadaan dynaaminen taulukko(osoite) joka pitää kopioida “TÄHÄN” dynaamiseen taulukkoon. */Dynamic_array& Dynamic_array::operator= (const Dynamic_array& another_dynamic_array){

// this-pointterin avulla voidaan tutkia onko “TÄMÄ” taulukko-olio sama,// kuin argumenttina saatu taulukko-olio. Jos on, varsinaista kopiointia// ei tarvitse suorittaa.if ( this == &another_dynamic_array ){

// The array is being copied into itself. Nothing needs to be done.return *this ;

}

// Sijoitusoperaatiossa merkin = vasemmalla puolella olevan// taulukko-olion sisältö tuhoutuu. Tuhotaan siis nykyinen ”TÄMÄ”// taulukko-olio ja allokoidaan uusi ”TÄMÄ” taulukko, joka on// kooltaan sama kuin argumenttitaulukko.delete array_in_free_store ;array_instance_size =

another_dynamic_array.array_instance_size ;array_in_free_store = new double[ array_instance_size ] ;

// for-luupissa kopioidaan argumenttina saatu taulukko-olio “TÄMÄKSI”// taulukko-olioksi.for ( int array_index = 0 ; array_index < array_instance_size ; array_index ++ ){

array_in_free_store[ array_index ] =another_dynamic_array.array_in_free_store[ array_index ] ;

}// Kun palautetaan this pointteri, palautetaan osoite “TÄHÄN”// taulukko-olioon.return *this ;

}

Page 126: C++-KIELI - Oamkjjauhiai/opetus/olio/Olio-ohjelmointi-40.pdf · 2007. 1. 5. · C++-kieli Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved. 4 5.7.2 OSOITTIMET TIETUEESEEN.....33

C++-kieli

Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved.

125

// Tämä jäsenfunktio ylikuormittaa operaattoria ‘<<’, siis tulostusoliolle// tulostukseen käytetyn operaattorin. Tyyppinä sekä jäsenfunktiolla// että sen ensimmäisellä argumentilla on tulostusoliotyyppi ostream.// Toisena argumenttina tulee tulostettavaksi tarkoitettu taulukko-olio (osoite).ostream& operator<< ( ostream& array_output_stream,

const Dynamic_array& dynamic_array_to_output ){

// Tulostus tapahtuu for-luupissa taulukko-elementti kerrallaan.for ( int array_index = 0 ;

array_index < dynamic_array_to_output.array_instance_size ;array_index ++ )

{// Taulukko-olio tulostetaan tulostusoliolle array_output_stream, joka// on saatu argumenttina. Yleensä tulostusolio on cout. Tässä se piilotettu// nimeen array_output_stream.array_output_stream << dynamic_array_to_output.array_in_free_store[array_index]

<< " " ;

if ( array_index % 5 == 4 ){

array_output_stream << "\n" ;}

}array_output_stream << "\n" ;

return array_output_stream ;}

Kuva 26-9. Darray.h (Luokan Dynamic_array määrittelytiedosto).

//// Darray.cpp (c)//#include <iostream.h>#include <stdlib.h>#include "Darray.h"

// Ohjelma joka testaa luokkaa Dynamic_array.main (){

// Luodaan kolme oliota, joiden kaikkien koko on 10, mutta alustusarvot ovat// erilaiset.Dynamic_array test_array( 10, 3.5 ) ;Dynamic_array another_array( 10, 4.0 ) ;Dynamic_array multiplied_arrays( 10, 0.0 ) ;

// Tässä taulukko-olion another_array 7. elementin arvoksi asetetaan// desimaaliluku 5.0.// Operaattoria [ ] on tässä ylikuormitettu. Tästä viittauksesta taulukko-// olioon another_array, generoituu kutsu jäsenfunktioon// Dynamic_array::operator[ ].

// Indeksin arvo 6 menee kyseiselle jäsenfunktiolle argumenttina.another_array [ 6 ] = 5.0 ;

// Tässä on operaattori << ylikuormitettu. Tästä seuraa jäsenfunktion// Dynamic-array::operator<<,// jolle ensimmäisenä argumenttina menee cout ja toisena argumenttina// test_array.cout << test_array ;cout << another_array ;

// Tällä rivillä sekä operaattori ‘=’ että operaattori ’*’ ovat ylikuormitettuja.// Näistä seuraa kutsut jäsenfunktioihin// Dynamic_array::operator* ja// Dynamic_array::operator=.// test_array:n ja another_array:n kertomisesta seuraa, että muodostuu// välillä ”nimetön olio” joka sijoitetaan olion multiplied_arrays tilalle.// Alkuperäinen multiplied_arrays ylikirjoitetaan sijoitusoperaattorissa.multiplied_arrays = test_array * another_array ;cout << multiplied_arrays ;

Page 127: C++-KIELI - Oamkjjauhiai/opetus/olio/Olio-ohjelmointi-40.pdf · 2007. 1. 5. · C++-kieli Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved. 4 5.7.2 OSOITTIMET TIETUEESEEN.....33

C++-kieli

Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved.

126

multiplied_arrays = test_array * multiplied_arrays ;cout << multiplied_arrays ;

// Määritetään pari muuttujaa, joihin pyydetään sisällöt ohjelman käyttäjältä.// Jälleen huomaamme, että sisäänsyöttö-olio cin ja operaattori >> osaavat// automaattisesti tunnistaa, minkä tyyppistä tietoa ollaan lukemassa.unsigned int array_size_given_by_the_user ;double initial_value_from_the_user ;cout << "\n Please, give me some array size: \n" ;cin >> array_size_given_by_the_user ;

// Tällä rivillä operaattoria ‘<<’ käytetään normaalisti.cout << "\n Give me also some double value: \n" ;cin >> initial_value_from_the_user ;

// Tässä dynaaminen taulukko-olio määritellään “lennossa” ohjelman// suorituksen aikana. Taulukkon koko määräytyy ohjelman käyttäjän// näppäimistöltä antaman lukuarvon perusteella.Dynamic_array user_defined_array( array_size_given_by_the_user,

initial_value_from_the_user ) ;

// Tällä rivillä ‘<<’ -operaattori on jälleen ylikuormitettu, ts. Sen käytöstä// aiheutuu kutsu jäsenfunktioon// Dynamic_array::operator<<.cout << user_defined_array ;

return 0 ;}

Kuva 26-10. Darray.cpp

Page 128: C++-KIELI - Oamkjjauhiai/opetus/olio/Olio-ohjelmointi-40.pdf · 2007. 1. 5. · C++-kieli Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved. 4 5.7.2 OSOITTIMET TIETUEESEEN.....33

C++-kieli

Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved.

127

27. LUOKAN YSTÄVÄT (Friend) Luokan ystävä on toinen luokka, aliohjelma tai toisen luokan metodi, jolla on oikeus käsitellä luokan private- ja protected-jäseniä. Jos ystävä on kokonainen luokka, on luokan jäsenten käyttö mahdollista kaikissa ystäväluokan metodeissa. Ystäviä tarvitaan esim. syöttö- ja tulostusoperaattoreita kuormitettaessa. Luokan ystävä ei ole luokan jäsen, vaikka sillä on luokan jäsenten käyttöoikeus. Ystävät ovat eräänlainen laajennus luokan liittymään. Ystävät ovat C++-kielen erityispiirre, eivätkä kuulu olio-ohjelmoinnin perustekniikoihin. Ystäviä ei tule käyttää yleisesti tietojäsenten käyttöoikeuksien laajentamiseksi, koska luokkien ylläpidettävyys heikkenee. Luokkaan tehtävä muutos vaikuttaa tällöin myös luokan ystäviin. Ystäviä kannattaa käyttää ainoastaan sellaisten luokkien yhteydessä, joissa luokat muodostavat kiinteän kokonaisuuden ja niitä on käytettävä aina yhdessä.

class Luokka{private:

friend void Ystava(Luokka &) ;friend void LuokkaYstava::Ystava(Luokka *) ;friend class Ystävä ;

public:…

};

Kuva 27-1. Luokan ystävien esittely. Luokan ystävän esittely alkaa varatulla sanalla friend sen luokan yhteydessä, joka antaa private- ja protected-jäsentensä käyttöoikeuden ystävälle. Esittely voi tapahtua missä tahansa kohtaa luokan määrittelyssä. Esittely private- tai public-kohdassa ei vaikuta tietojäsenten käyttöoikeuteen ystäväluokassa, -aliohjelmassa tai –metodissa eikä ystävän näkyvyyteen. Luokan ystävä voi olla tavallinen luokkaan kuulumaton aliohjelma, luokan metodi tai kokonainen luokka. Yllä olevassa kuvassa on mallit näiden esittelyä varten. Kuvassa ensimmäinen friend-määreellä esitelty aliohjelma on tavallinen luokkaan kuulumaton aliohjelma. Toinen ystäväaliohjelma (eli metodi) kuuluu johonkin luokkaan, koska aliohjelmanimen yhteydessä esiintyy luokan nimi. Kolmas ystävä on kokonainen luokka. Tällöin kaikki ystäväluokan metodit saavat ystäväaliohjelmien oikeudet. Koska luokan ystävä ei ole luokan jäsen, se ei voi viitata suoraan luokan olion tietojäseniin, vaan ystävällä on oltava viittaus tai osoitin olioon. Kuvan (edellä) ensimmäinen ystäväaliohjelma saa parametrina viittauksen käsiteltävään olioon. Toinen ystävämetodi saa parametrina osoittimen käsiteltävään olioon. Ystävyys ei ole siirtyvä tai periytyvä ominaisuus. Jos luokka A on luokan B ystävä ja luokka E on luokan B ystävä, ei luokka E ole välttämättä luokan A ystävä.

#include <iostream>using namespace std ;

class Luokka ;void Tulosta (const Luokka &olio) ;

class A_Luokka{public:

void A_Aliohj (const Luokka &Olio) ;};

class B_Luokka{public:

void B_Aliohj (const Luokka *Olio) ;};

Page 129: C++-KIELI - Oamkjjauhiai/opetus/olio/Olio-ohjelmointi-40.pdf · 2007. 1. 5. · C++-kieli Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved. 4 5.7.2 OSOITTIMET TIETUEESEEN.....33

C++-kieli

Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved.

128

class Luokka{private:

int Luku ;// Eri ystävät:

friend void Tulosta (const Luokka &) ; // Luokkaan kuulumaton aliohjelma.friend class A_Luokka ; // Kokonainen luokka.friend void B_Luokka::B_Aliohj (const Luokka *) ; // Jonkin toisen luokan metodi.

public:Luokka (int Alustus) ;

};

Luokka::Luokka (int Alustus){

Luku = Alustus ;}

void A_Luokka::A_Aliohj (const Luokka &Olio){

cout << Olio.Luku << endl ;}

void B_Luokka::B_Aliohj (const Luokka *Olio){

cout << Olio->Luku << endl ;}

void Tulosta(const Luokka &Olio){

cout << Olio.Luku << endl ;}

int main ( ){

Luokka LuokkaOlio (2001) ;A_Luokka A_Olio ;B_Luokka B_Olio ;

Tulosta (LuokkaOlio) ;A_Olio.A_Aliohj (LuokkaOlio) ;B_Olio.B_Aliohj (&LuokkaOlio) ;

return 0 ;}

Kuva 27-2. Esimerkki luokan ystävistä.

Kuva 27-3. Edellisen esimerkin tulostus.

27.1 Esimerkkejä Olio-ohjelmoinnissa on usein ideana, että käytetään valmiita luokkia. On tärkeää, että ymmärtää kuinka valmiin luokan jäsenfunktioita käytetään eli kuinka niitä voidaan kutsua jostakin toisesta ohjelmasta. Ei ole

Page 130: C++-KIELI - Oamkjjauhiai/opetus/olio/Olio-ohjelmointi-40.pdf · 2007. 1. 5. · C++-kieli Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved. 4 5.7.2 OSOITTIMET TIETUEESEEN.....33

C++-kieli

Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved.

129

välttämätöntä aina ymmärtää jäsenfunktioiden sisäistä rakennetta eli luokan jäsenfunktioiden ohjelmakoodia ei useinkaan tarvitse ymmärtää täydellisesti. 27.1.1 Friend01.cpp Esimerkki luokkaan kuulumattoman aliohjelman määrittämisestä luokan ystäväksi. Tällöin ko aliohjelma pääsee käytämään luokan luokan palveluita. Eli kysymyksessä on kyseisen luokan palveluliittymän laajentaminen. Ohjelmaan kuuluu tiedostot Friend01.cpp ja Friend01.h.

/*Friend.h

Otsikkotiedosto joka sisältää 'Ruohonleikkuri'-luokan määrityksen.(c) Markku Rahikainen, 2003

*/

/*** LUOKKA ***/

class Ruohonleikkuri{private:

char Merkki [20] ;int Vuosimalli ;bool LEIKKURI_KAYNNISSA ;

public:Ruohonleikkuri () ;~Ruohonleikkuri () ;

void Kaynnista () ;void Sammuta () ;

// Napuri on luokan ystävä, joten naapuri voi täten// käyttää ruohonleikkuria oman pihan leikkaamiseen.friend void Naapuri (Ruohonleikkuri &Leikkuri) ;

};

/*** MUODOSTIN ja HAJOTIN ***/

Ruohonleikkuri::Ruohonleikkuri(){

LEIKKURI_KAYNNISSA = false ;}

Ruohonleikkuri::~Ruohonleikkuri(){

LEIKKURI_KAYNNISSA = false ;}

/*** METODIT ***/

void Ruohonleikkuri::Kaynnista(){

LEIKKURI_KAYNNISSA = true ;}

void Ruohonleikkuri::Sammuta(){

LEIKKURI_KAYNNISSA = false ;}

Kuva 27-4. Friend01.h

Page 131: C++-KIELI - Oamkjjauhiai/opetus/olio/Olio-ohjelmointi-40.pdf · 2007. 1. 5. · C++-kieli Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved. 4 5.7.2 OSOITTIMET TIETUEESEEN.....33

C++-kieli

Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved.

130

/*Friend.cpp

Ohjelma joka käyttää Stack.h tiedostossa olevaa'Stack'-luokkaa.(c) Markku Rahikainen, 2003

*/

#include <iostream>using namespace std ;

#include "Friend01.h"

void Naapuri (Ruohonleikkuri &Leikkuri){

Leikkuri.Kaynnista() ;

cout << "\nNaapuri tassa leikkaa vaan ruohoa ! \n\n" ;

Leikkuri.Sammuta() ;}

int main (){

// Ostetaan uusi ruohonleikkuri.Ruohonleikkuri Stiga ;

// Naapuri lainaa leikkuria.Naapuri (Stiga) ;

return 0 ;}

Kuva 27-5. Friend01.cpp

Kuva 27-6. Edellisen esimerkin tulostus.

Page 132: C++-KIELI - Oamkjjauhiai/opetus/olio/Olio-ohjelmointi-40.pdf · 2007. 1. 5. · C++-kieli Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved. 4 5.7.2 OSOITTIMET TIETUEESEEN.....33

C++-kieli

Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved.

131

28. JOHDANTO PERIYTYMISEEN Periytyminen (Inheritance) on ohjelmointitekniikka, jonka avulla ohjelmoija voi uudelleenkäyttää aiemmin kirjoitetun luokan määrityksiä uutta luokkaa määritellessään. Yleensä peritty luokka ja periytetty luokka kirjoitetaan eri aikoina ja kumpikin on suunniteltava eri näkökulmat huomioon ottaen. Luokkaa toteutettaessa on otettava huomioon, onko kirjoitettava luokka mahdollisesti myöhemmin käytettävissä periyttämistä varten. Luokan kirjoittamisessa siis varaudutaan tuleviin muutos- ja ylläpitotilanteisiin. Muutokset ja ylläpito eivät kohdistu välttämättä perittävään yliluokkaan. Luokka voidaan sovittaa uuteen tilanteeseen periyttämällä ja tekemällä muutokset periytettyyn aliluokkaan kääntämättä yliluokan ohjelmakoodia uudelleen. Periytymisen perusteisiin liittyviä aiheita ovat yli- ja aliluokkakäsitteet, yksi- ja moniperiytyminen, erilaiset periytymistavat, abstraktit ja konkreettiset luokat sekä monimuotoisuus. Mallinnuksen kannalta periytyminen voi olla kolmenlaista. Näitä periytymismuotoja kuvailevat hyvin englannin kieliset lyhenteet seuraavasti: 1) is-a

• Luetaan: Aliluokka on yliluokka, esim. Työntekijä on Henkilö. • Aliluokka perii sekä liittymän että toteutustavan yliluokan kaikista tavallisista metodeista ja tarvittaessa virtuaalisista metodeista. • public-periytyminen, näkyy luokkahierarkiasta ulospäin myös luokkahier- arkian asiakkaille.

2) is-like-a

• Luetaan: Aliluokka on kuten yliluokka, esim. Kori on kuten Talletusrakenne. • Aliluokka perii sekä liittymän että toteutustavan, mutta piilottaa periytymisen luokkahierarkian sisään. • protected-periytyminen, näkyy luokkahierarkiassa alaspäin mutta ei asiakkaille.

3) is-implemented-as-a, has-a • Luetaan: Aliluokka toteutetaan kuten yliluokka, aliluokalla on yliluokka (Vaihtoehtoinen koosteen toteutustapa), esim. Pino on toteutettu Taulukolla. • Aliluokka perii yliluokan liittymän ja toteutustavan, mutta piilottaa täydellisesti periytymisen sisäänsä. • private-periytymien, näkyy vain periytyvälle luokalle itselleen.

28.1 Periytymisen käyttötilanteita Aliluokka (Subclass, Derived class) on yliluokasta (Superclass, Base class) johdettu uusi luokka. Periytyminen mahdollistaa siis luokkien eli oliotyyppien välisen periytymisen. On huomattava, että oliot eivät voi periä toisiaan, vaan luokat voivat periytyä toisistaan. Olio voi siten “periä” uusia ominaisuuksia yliluokaltaan vain aliluokan kautta.

Yhdestä yliluokasta voidaan periyttää tarvittaessa useita eri aliluokkia ja yksi aliluokka voi periä monta yliluokkaa. Periytyminen on yksiperiytymistä (Single inheritance), kun luokka perii yhden yliluokan ja moniperiytymistä (Multiple inheritance), kun luokka perii monta yliluokkaa. Periytymishierarkian syvyyttä ei ole rajoitettu, joten periytymistasoja voi olla useita.

Page 133: C++-KIELI - Oamkjjauhiai/opetus/olio/Olio-ohjelmointi-40.pdf · 2007. 1. 5. · C++-kieli Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved. 4 5.7.2 OSOITTIMET TIETUEESEEN.....33

C++-kieli

Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved.

132

Eläin

KissaKoira

Maa-ajoneuvo

Vesi-ajoneuvo

Amfibi

Yksiperiytyminen Moniperiytyminen

Kuva 28-1. Yksi- ja moniperiytyminen. Normaalissa periytymisessä luokat muodostavat is-a –rakenteita. Aliluokan olio on myös yliluokan olio. Yksiperiytymisessä aliluokat ovat vaihtoehtoisia tarkennuksia yliluokasta. Eläin voi olla koira tai kissa. Moniperiytymisessä aliluokan olion on vastattava kaikkien yliluokkiensa ominaisuuksia samanaikaisesti. Amfibi on siis sekä maa-ajoneuvo että vesiajoneuvo. Vene ei siis voi kuulua amfibi-luokkaan. Periytyminen on liittymän periytymistä (Interface inheritance) tai toteutustavan periytymistä (Implementation inheritance). Liittymän periytyminen kohdistuu yliluokassa esiteltyjen julkisten palveluiden nimiin (Vrt. Seuraavassa kuvassa kohta 2). Toteutustavan periytyminen kohdistuu yliluokan tietojen toteutustapaan metodeina (Vrt. Seuraavassa kuvassa kohdat 1 ja 3). Palveluliittymää periytettäessä ei välttämättä haluta käyttää yliluokassa sijaitsevan palvelun toteutusta, vaan aliluokassa sijaitsevaa korvaavaa toteutusratkaisua.

2

class Yliluokka{

public: void Ali ();};

class Yliluokka::Ali (){

}

1 3

Kuva 28-2. Liittymä ja toteutustavan periytyminen. Periytettävät ominaisuudet on valittava kahden eri näkökulman perusteella. Nämä näkökulmat ovat aliluokan asiakkaiden näkökulma ja aliluokan toteuttajan näkökulma. Aliluokan asiakkaat ovat ohjelmia, jotka voivat luoda aliluokkaan olioita ja lähettää näille viestejä. Asiakas ei tunne aliluokan toteutustapaa, mutta tuntee aliluokan julkisen palveluliittymän. Aliluokan toteuttajan on päätettävä, millainen on aliluokan asiakkaille näkyvä palveluliittymä. Sen lisäksi toteuttajan on päätettävä, milloin on mahdollista käyttää suoraan yliluokan sisältämää palvelun toteutusta ja milloin aliluokkaan on kirjoitettava uusi toteutusratkaisu. Ohjelmoija voi käyttää periytymistä hyväkseen erilaisissa tilanteissa: 1) Palveluliittymän laajentaminen aliluokan asiakkaille

• Yliluokan palveluliittymän ja mahdollisesti toteutusratkaisun (Metodien) periyttäminen aliluokalle. • Aliluokan olion asiakas voi pyytää oliolta myös yliluokan palveluliittymässä esiteltyjä palveluita ja kutsua yliluokassa toteutettuja metodeita. • Toteutustapa: Periytymistapa public.

2) Palveluliittymän laajentaminen aliluokan kehittäjille • Yliluokan palveluliittymän ja metodien periyttäminen aliluokalle. • Aliluokan metodit voivat kutsua yliluokassa esiteltyä ja toteutettua metodia. • Toteutustapa: Yliluokan protected-jäsenet, periytymistavat protected ja public.

3) Toteutustavan periyttäminen aliluokkaan • Yliluokan palvelujen toteutustavan eli metodien ja attribuuttien toteutustavan periyttäminen. • Aliluokan olion palveluliittymä piilottaa yliluokan palveluliittymän. • Aliluokka kontrolloi yliluokan metodien käyttötilanteita. • Toteutustapa: Periytymistavat private ja protected.

Page 134: C++-KIELI - Oamkjjauhiai/opetus/olio/Olio-ohjelmointi-40.pdf · 2007. 1. 5. · C++-kieli Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved. 4 5.7.2 OSOITTIMET TIETUEESEEN.....33

C++-kieli

Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved.

133

Yliluokkaa suunniteltaessa on päätettävä, millä tavoilla yliluokan palveluliittymää ja toteutustapaa saa käyttää periytymisen yhteydessä. Yliluokan määrittelijä päättää, mistä palveluista aliluokat voivat periä pelkän liittymän ja mistä toteutuksen, sekä mitkä metodit tulevan aliluokan kehittäjän on aliluokkaan toteutettava. 28.1.1 Aliluokan palveluliittymän laajentaminen aliluokan asiakkaille

Kun aliluokan tarjoamien palveluiden määrää halutaan lisätä, voidaan aliluokka periyttää yliluokasta public-periytymistavalla. Yliluokka sisältää tieto- ja aliohjelmajäsenet, jotka ovat samoja kaikille luokkahierarkian olioille. Aliluokka sisältää vain ne tieto- ja aliohjelmajäsenet, jotka ovat lisäksi tarpeellisia vain aliluokan olioille. Aliluokka perii kaikki yliluokan tavalliset jäsenet ja ne virtuaaliset metodit, joiden toteutusta se ei korvaa.

Aliluokkaan ei esitellä uudelleen yliluokassa jo esiteltyjä tietojäseniä ja metodeita, vaan tarkoituksena on käyttää hyödyksi yliluokan jäseniä sellaisinaan. Aliluokan olioille voidaan lähettää kaikkia niitä palvelupyyntöjä, mitä luokkahierarkiaan on metodeina toteutettu.

Aliluokan olio muodostaa kerrosteisen rakenteen, siitä on siis ilmentymä kussakin luokkahierarkian luokassa. Seuraavassa esimerkki Elain-luokan käyttämisestä yliluokkana.

Eläin- Nimi- Tyypillinen_aantely- Vatsan_sisalto

Ruoki ()Aantele ()

Koira- Rotu- Veromerkki

Pure ()NaytaVeromerkki()

Kissa- Kehraysaani

Kehraa ()

Kuva 28-3. Eläin-luokka yliluokkana. Eläin-luokkaa on käytetty Koira- ja Kissa-luokan yliluokkana. Huomaa, että kysymys on yksiperiytymisestä, koska aliluokka perii vain yhden yliluokan. Periytymisen seurauksena aliluokan olio sisältää yli- ja aliluokassa määritellyt tiedot. Sekä koirasta että kissasta tiedetään nimi, tyypillinen ääntely ja vatsan sisältö. Koiraan liittyy lisäksi rotu ja veromerkki. Kissaan liittyy kehräysääni. Periytyminen laajentaa aliluokan olioiden palveluliittymää, kun periytymistapa on public. Ilman periytymistä Koira-luokan oliolle voisi lähettää viestit Pure ja NaytaVeromerkki. Periytymisen seurauksena aliluokan olio tunnistaa myös viestit Ruoki ja Aantele. Vastaavasti ilman periytymistä Kissa-luokan oliolle on mahdollista lähettää viesti Kehrää ja periytymistä käytettäessä myös viestit Ruoki ja Aantele. Yliluokan metodit käsittelevät yliluokassa määriteltyjä tietoja ja aliluokan metodit käsittelevät aliluokassa määriteltyjä tietoja. Aliluokan olion kerrosteista rakennetta voidaan kuvata seuraavankaltaisilla taulukoilla. Taulukon vasemmanpuoleisessa sarakkeessa on lueteltu ne palvelut, jotka palveluliittymän periytymisessä ovat aliluokan olion asiakkaiden käytettävissä. Taulukon keskimmäinen rivi osoittaa Eläin-luokan kerroksen ja alin rivi aliluokasta muodostuvan kerroksen.

Page 135: C++-KIELI - Oamkjjauhiai/opetus/olio/Olio-ohjelmointi-40.pdf · 2007. 1. 5. · C++-kieli Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved. 4 5.7.2 OSOITTIMET TIETUEESEEN.....33

C++-kieli

Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved.

134

Koira-olionjulkinen palveluliittymä:

Koira-olionpiilotetut tiedot:

Ruoki ()Aantele ()

NimiTyypillinen_aantelyVatsan_sisalto

Pure ()NaytaVeromerkki ()

RotuVeromerkki

Kissa-olionjulkinen palveluliittymä:

Kissa-olionpiilotetut tiedot:

Ruoki ()Aantele ()

NimiTyypillinen_aantelyVatsan_sisalto

Kehraa () Kehraysaani

Kuva 28-4. Aliluokan kerrosteinen rakenne.

28.1.2 Aliluokan palveluliittymän laajentaminen aliluokan toteuttajan näkökulmasta Aliluokan metodeista on mahdollista käyttää kaikkia yliluokan asiakkaiden käyttöön tarkoitettuja metodeita. Yliluokka saattaa sisältää myös metodeita, joita ei ole tarkoitettu luokan asiakkaiden käyttöön vaan ne on tarkoitettu luokkahierarkiaan kuuluvien luokkien sisäiseen käyttöön. Aliluokan metodeissa voidaan käyttää tälläisiä yliluokassa protected-määreen jäljessä esiteltyjä palveluita suoraan. Esimerkiksi Eläin-luokkaan voidaan toteuttaa metodi Ika, joka palauttaa eläimen iän syntymävuodesta laskettuna. Tämä metodi on käytettävissä Eläin-luokan metodeissa ja Koira- ja Kissa-luokan metodeissa suoraan. Ika ei kuulu luokan julkiseen palveluliittymään, joten sitä ei voi lähettää viestinä luokkahierarkian oliolle. Tällöin luokan asiakkaille näkyvä palveluliittymä on samanlainen kuin aiemmassakin esimerkissä. Sen lisäksi luokkahierarkian sisäiseen käyttöön on tullut yksi metodi lisää. Seuraava taulukko havainnollistaa tilannetta.

Koira-olionjulkinen palveluliittymä:

Koira-olionpiilotetut tiedot:

Ruoki ()Aantele ()

NimiTyypillinen_aantelyVatsan_sisalto

Pure ()NaytaVeromerkki ()

RotuVeromerkki

Luokkahierarkian sisäisetmetodit:

Ika ()

Kuva 28-5. Luokka hierarkian sisäinen metodi Ika. 28.1.3 Toteutustavan periytyminen Toteutustavan periytyminen (Implementation inheritance) tarkoittaa periytymissuhdetta, jossa aliluokka peittää yliluokan palveluliittymän niin, että se ei näy aliluokan asiakkaille. Keskeistä ei siis ole aliluokan asiakkaiden näkökulma vaan aliluokan toteuttajan näkökulma. Toteutusperiytymisessä aliluokka käyttää yliluokkaa jonkin attribuutin tai palvelun teknisen toteutusratkaisun sisällyttämiseksi aliluokkaan aliluokan toteutuksen helpottamiseksi. Toteutustavan periyttäminen aliluokkaan tapahtuu protected- ja private-periytymistavoilla. Toteutustavan periytyminen on lähellä koostumussuhteen toteuttamista. Koostumussuhteessa on kysymys eri olioiden välisestä sisältyvyydestä ja omistamisesta, kun taas periytymisessä aliluokan olio on yksi olio, joka on erikoistapaus yliluokan oliosta. Tästä syystä toteutustavan periytymistä ei yleisesti pidetä oikeaoppisena tapana toteuttaa koostumussuhteita. Toisinaan periytymisen ja koostumussuhteen erottaminen on vaikeaa. On

Page 136: C++-KIELI - Oamkjjauhiai/opetus/olio/Olio-ohjelmointi-40.pdf · 2007. 1. 5. · C++-kieli Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved. 4 5.7.2 OSOITTIMET TIETUEESEEN.....33

C++-kieli

Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved.

135

olemassa kuitenkin yksinkertainen tarkistamiskeino. Englanninkielessä periytyvyyttä kuvataan is-a tai is-kind-of –suhteeksi ja koostumusta has-a –suhteeksi.

An employee is a person.Työntekijä on henkilö.

Periytyminen

A forest has trees.Metsässä on puita.

Koostumus

Kuva 28-6. Esimerkki periytymis- ja koostumussuhteesta. Periytymisen ja koostumuksen ero näkyy myös luokkien olioiden lukumääräsuhteessa. Periytymisessä suhde on aina 1.1, eli yhtä aliluokan oliota vastaa yksi yliluokan ilmentymä ja yliluokan ilmentymä on välttämätön. Koostumuksessa lukumäärä voi vaihdella. Jos lukumääräsuhde on 1:1, on mahdollista käyttää periytymistä. Toteutustavan periytymistä voidaan käyttää silloin, kun esimerkiksi pino voidaan toteuttaa tarvittaessa erilaisilla tietorakenteilla. Pino-luokka voidaan periyttää esimerkiksi taulukko-luokasta. Pinon on piilotettava taulukon palveluliittymä, koska pinoa ei voida käsitellä yhtä monipuolisesti kuin taulukkoa. Taulukkoa voidaan käsitellä monella eri tavalla: alkioita voidaan selailla poistamatta niitä taulukosta, taulukkoa voidaan tiivistää jne. Sen sijaan pinolle on määritelty vain kaksi operaatiota: LaitaPinoon, OtaPinosta. Pinossa voidaan käsitellä vain päällimmäisenä olevaa alkiota.

Taulukko- Taulu [20];

Lisaa ()Poista ()Seuraava ()Edellinen ()

Pino;

OtaPinosta ()LaitaPinoon ()

Kuva 28-7. Pino- ja Taulukko-luokka. Pino-luokan asiakkaat eivät tunne pinon toteutustapaa. Vain Pino-luokan palveluliittymä näkyy Pino-luokan asiakkaille. Pino piilottaa yliluokan palvelut asiakkailtaan ja ohjaa palvelupyynnön oikealle metodille. Pinoa voidaan havainnollistaan seuraavalla taulukolla:

Pino-olionjulkinen palveluliittymä:

Taulukko-olionpiilotetut tiedot:

Taulu

OtaPinosta ()LaitaPinooni ()

Luokkahierarkian sisäisetmetodit:

Lisaa ()Poista ()Seuraava ()Edellinen ()

Kuva 28-8. Pinoa havainnollistava taulukko. Yliluokasta perityt metodit eivät kuulu Pino-luokan julkiseen palveluliittymään. Ne ovat vain Pino-luokan metodien käytettävissä.

Page 137: C++-KIELI - Oamkjjauhiai/opetus/olio/Olio-ohjelmointi-40.pdf · 2007. 1. 5. · C++-kieli Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved. 4 5.7.2 OSOITTIMET TIETUEESEEN.....33

C++-kieli

Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved.

136

28.2 Yliluokan määrittely Periytymisen käyttöön liittyvät varatut sanat private, protected ja public. Näitä varattuja sanoja käytetään kahdessa eri merkityksessä. Ne voivat tarkoittaa luokan jäsenten perusnäkyvyyssääntöjä tai luokan periytymistapaa. Luokan jäsenten näkyvyys vaikuttaa niiden viittausalueeseen. Luokan periytymistapa vaikuttaa yliluokan jäsenten viittausalueeseen aliluokan näkökulmasta. 28.2.1 Näkyvyyssäännöt yliluokassa Kun tulevaa yliluokkaa kirjoitetaan, on otettava huomioon luokan asiakkaiden näkökulma ja luokan jatkokehittäjän näkökulma. Luokan asiakkaiden näkökulma tarkoittaa niiden aliohjelmien näkökulmaa, jotka voivat luoda olion luokkahierarkiaan ja jotka voivat kutsua luokan metodeita. Luokan jatkokehittäjän näkökulma tarkoittaa aliluokan toteuttajan näkökulmaa. Näistä näkökulmista on suunniteltava seuraavat asiat. Luokan asiakkaiden näkökulma

• Luokan asiakkaille näkymättömät tiedot ja metodit esitellään private-määreen jäljessä. • Luokan asiakkaille tarjottavat palvelut (~aliohjelmajäsenet) esitellään public-määreen jäljessä.

Luokan jatkokehittäjän näkökulma

• Tuleville aliluokille, mutta ei luokan asiakkaille, tarjottavat palvelut (~aliohjelmajäsenet) esitellään protected-määreen jäljessä.

Luokan jäsenten perusnäkyvyyssäännöt merkitään luokan jäsenten yhteyteen saantimääreellä.

class Yliluokka{private:

// Vain yliluokassa näkyvät jäsenet.protected:

// Myös aliluokissa näkyvät jäsenet.public:

// Kaikkialla näkyvät jäsenet.};

Kuva 28-9. Saantimääreiden merkitseminen. Protected-määreen jäljessä esitelty jäsen on käytettävissä luokan omissa metodeissa ja luokasta periytettävän luokan metodeissa (ja aliluokan ystäväaliohjelmissa). Periytymisen yhteydessäkin tiedon piilotuksen periaate pätee eli vain luokan omilla metodeilla (ja ystäväaliohjelmilla friend) voi käsitellä luokassa esiteltyjä yksityisiä (private) tietoja. Tietojen määrittelyä protected-määreen jäljessä kannattaa välttää hyvin ylläpidettävyyden säilyttämiseksi. 28.2.2 Yliluokan palveluliittymän ja toteutuksen periytymisen suunnittelu Perittävä yliluokka voi olla konkreettinen tai abstrakti luokka. Luokkahierarkiassa alimman tason luokka on aina konkreettinen. Konkreettiseen luokkaan voidaan luoda olioita, kun taas abstraktiin luokkaan ei voida luoda olioita. Abstrakteja luokkia käytetään luokkahierarkian palveluliittymän standardointiin.

Page 138: C++-KIELI - Oamkjjauhiai/opetus/olio/Olio-ohjelmointi-40.pdf · 2007. 1. 5. · C++-kieli Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved. 4 5.7.2 OSOITTIMET TIETUEESEEN.....33

C++-kieli

Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved.

137

Abstrakti

Konkreettinen

Konkreettinen

Konkreettinen

Kuva 28-10. Konkreettisesta luokasta voidaan vain luoda olioita.

Abstraktiin luokkaan ei voi luoda olioita, koska abstrakti luokka ei sisällä kaikkien tarvittavien palvelujen toteutusta, vaan palvelujen toteutus metodeina saattaa sijaita konkreettisessa luokassa. Abstrakti ja konkreettinen luokka erottelevat siis selkeästi luokan liittymän ja toteutuksen toisistaan. Yliluokan määrittelijän on suunniteltava palvelujen ja metodien käyttömahdollisuudet. Ryhmittelemme yliluokan metodit kolmeen eri ryhmään niiden käyttötarkoituksen mukaan. 1) Tavalliset metodit

• Metodit tarkoitetaan käytettäväksi kaikille luokkahierarkian olioille. Aliluokka siis perii tavallisen metodin liittymän ja toteutustavan. • Aliluokka voi peittää (hide) yliluokan metodin, peittämistä ei kuitenkaan suositella.

2) Mahdollisesti korvattavat metodit • Toteutustapa: Virtuaaliset metodit (Virtual functions). • Metodia voidaan käyttää kaikille luokkahierarkian olioille, yliluokka sisältää oletustoteutuksen. Aliluokka perii virtualisen metodin liittymän ja mahdollisesti sen oletustoteutustavan. • Samasta metodista voi olla useita toteutuksia luokkahierarkiassa, aliluokka voi korvata (Override) yliluokan metodin oletustoteutuksen tarvittaessa.

3) Aina korvattavat metodit • Toteutustapa: Puhtaat virtuaaliset metodit (Pure virtual functions) ja abstrakti luokka. • Metodin nimi on tarkoitettu käytettäväksi kaikille luokkahierarkian olioille. Aliluokka perii pelkän liittymän puhtaasta virtuaalisesta metodista. Eri aliluokkien olioille käytetään eri ohjelmakoodia, aliluokkaan on toteutettava metodi aina määrätyllä nimellä.

Konkreettinen luokka voi sisältää vain tavallisia ja virtuaalisia metodeita. Vain abstrakti luokka voi sisältää puhtaita virtuaalisia metodeita.

class Yliluokka{

…public:

void Metodi_1 () ;virtual void Metodi_2 ( … ) ;virtual void Metodi_3 () = 0 ;

};

Kuva 28-11. Erilaisten metodien esittely. Metodi_1 on tavallinen metodi, joten sitä voi käyttää sekä yliluokan että tulevan aliluokan oliot. Aliluokka voi peittää sen, vaikka peittämistä ei suositella. Metodi_2 on virtuaalinen oletustoteutuksen sisältävä metodi. Jos oletustoteutus ei ole sovelias aliluokan olioille, ohjelmoija voi korvata oletustoteutuksen aliluokkaan kirjoittamallaan toteutuksella. Metodi_3 on puhdas virtuaalinen, joten se on aina toteutettava uudessa aliluokassa. 28.3 Aliluokan määrittely Myös aliluokkaa suunniteltaessa on otettava huomioon aliluokan asiakkaiden ja aliluokan toteuttajan ja jatkokehittäjän näkökulma. Kummassakin tapauksessa on mietittävä, miten periytettyä yliluokkaa halutaan käytettävän. Käyttömahdollisuudet määräytyvät periytymistavasta.

Page 139: C++-KIELI - Oamkjjauhiai/opetus/olio/Olio-ohjelmointi-40.pdf · 2007. 1. 5. · C++-kieli Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved. 4 5.7.2 OSOITTIMET TIETUEESEEN.....33

C++-kieli

Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved.

138

Aliluokan asiakkaiden näkökulma • Tarkoitus: Aliluokan asiakkaiden palveluja halutaan lisätä yliluokan tarjoamilla palveluilla. • Toteutustapa: Aliluokka periytetään public-periytymistavalla yliluokasta.

Aliluokan jatkokehittäjän näkökulma • Tarkoitus: Yliluokan metodeista halutaan käyttää aliluokassa ja sen mahdollisissa aliluokissa, mutta käyttömahdollisuutta ei myönnetä aliluokan asiakkaille. • Toteutustapa: Aliluokka periytetään protected-periytymistavalla yliluokasta.

Aliluokan määrittelijän näkökulma

• Tarkoitus: Yliluokan metodeita halutaan käyttää aliluokasta, mutta käyttömahdollisuutta ei myönnetä uusille mahdollisille aliluokille eikä aliluokan asiakkaille. • Toteutustapa: Aliluokka periytetään private-periytymistavalla yliluokasta.

class Yliluokka{

// Yliluokan jäsenten esittely.};

class Aliluokka : Periytymistapa Yliluokka{

// Aliluokan jäsenten esittely..};

Kuva 28-12. Aliluokan määrittely. Oletusperiytymistapa on private, jos aliluokka on määritelty class-määreellä. Oletusperiytymistapa struct-määreellä määritellyssä aliluokassa on public. Yliluokan jäsenten näkyvyyteen aliluokan asiakkaille ja aliluokan metodeille vaikuttavat siis yhdessä yliluokan jäsenten määrittelyt private-, protected- ja public-määreillä sekä aliluokan periyttäminen yliluokasta private-, protected- ja public-määreillä.

TAULUKKO Näkyvyyssääntöjen ja periytymistavan yhteisvaikutus

Jäsenen Aliluokan Näkyvyys Merkitys Merkitys Merkitys ali- esittely periytymis aliluokassa aliluokan aliluokan luokan yliluokassa tapa asiakkaille aliohjelmille aliluokille private Ei Ei näy ------------- --------------- ------------- merkitystä aliluokassa protected private private ------------- Voi käyttää ------------- protected protected ------------- Voi käyttää Voi käyttää public protected ------------- Voi käyttää Voi käyttää public private private ------------- Voi käyttää ------------- protected protected ------------- Voi käyttää Voi käyttää public public Voi käyttää Voi käyttää Voi käyttää

Kolmas sarake kertoo, millainen on yliluokan jäsenen näkyvyys aliluokassa eli millainen on näkyvyyssäännön ja periytymistavan yhteisvaikutus. Koska private-jäsenet ovat näkyviä vain siinä luokassa, jossa ne on esitelty, ei periytymistavalla ole merkitystä. private-jäseniä ei siis voida käyttää koskaan suoraan aliluokan kautta. Periytymistavalla on vaikutusta yliluokan protected- ja public-jäsenten näkyvyyteen aliluokan kautta. Periytymistapa public pitää jäsenen näkyvyyssäännöt ennallaan, kun taas protected- ja private-periytymistavat kaventavat yliluokan jäsenten näkyvyyttä aliluokan kautta. 28.3.1 Aliluokan metodien suunnittelu Aliluokkaa määriteltäessä on päätettävä, miten yliluokassa esiteltyjä ja toteutettuja palveluita halutaan käyttää aliluokan kautta. Mahdollisuudet ovat:

• Yliluokan palvelun esittely ja toteutus hyväksytään sellaisenaan.

Page 140: C++-KIELI - Oamkjjauhiai/opetus/olio/Olio-ohjelmointi-40.pdf · 2007. 1. 5. · C++-kieli Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved. 4 5.7.2 OSOITTIMET TIETUEESEEN.....33

C++-kieli

Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved.

139

• Yliluokan palvelun esittely (Nimi ja parametrit) hyväksytään, mutta toteutus on korvattava aliluokassa uudella toteutuksella.

�Metodi on yliluokassa virtualinen: Toteutus voidaan korvata. �Metodi ei ole yliluokassa virtuaalinen: Toteutus voidaan peittää, ei kuitenkaan suositella.

• Yliluokassa on pelkkä esittely, mutta ei toteutusta. �Metodi on yliluokassa puhdas virtuaalinen: Toteutus on tehtävä aliluokkaan.

Yliluokan metodin peittäminen (Hide) tarkoittaa samannimisen metodin toteuttamista aliluokassa. Yliluokan metodin korvaaminen (Override) tarkoittaa virtuaalisen metodin toteuttamista aliluokassa. Tälöin metodin nimen lisäksi metodin parametrien tyyppien on vastattava yliluokassa esitellyn virtuaalisen metodin parametrien tyyppejä. Metodin peittämisestä seura, että aliluokan olioita ei ole mahdollista käyttää kaikissa niissä tilanteissa missä yliluokan olioita voidaan käyttää. Yli- ja aliluokan olioita tulisi voida käyttää samalla tavalla, koska aliluokan olio voidaan ajatella myös yliluokan olioksi (Vrt. is-a –rakenne). Tällöin aliluokan olioita voidaan käsitellä myös yliluokan tunnuksen avulla. Peittäviä metodeita käytettäessä ongelmia voi syntyä, kun aliluokan olioita käytetään yliluokan tunnuksen avulla. Näin tehtäessä metodi tulee ajetuksi yliluokasta eikä aliluokasta, jossa peittävä metodi sijaitsee. Virtuaalisia metodeita korvattaessa ei tällaista tilannetta synny, koska korvattava metodi tulee ajetuksi aina siitä luokasta, johon olio on luotu. Periytymättömät metodit ovat yliluokassa esiteltyjä metodeita, joita ei voida suoraan kutsua lähettämällä viestiä aliluokkaan luodulle oliolle. Nämä ovat metodeita, jotka tulee esitellä ja toteuttaa aina tarvittaessa jokaiselle luokalle erikseen. Periytymättömiä metodeita ovat

• Muodostimet • Hajotin • Sijoitusmetodi (operator=) • Ystäväaliohjelmat (friend)

Sen sijaan yliluokan tyyppimuunnosmetodeita, tilanvarausoperaattoreita (new ja delete) ja muita tavallisia metodeita on mahdollista käyttää sekä yli- että aliluokan olioille. 28.4 Muodostimien ja hajottimien suoritusjärjestys Järjestelmä kutsuu yliluokan muodostimia ja hajottimia automaattisesti aliluokan olion tilanvarauksen ja tilanvapautuksen yhteydessä. Myös sijoitusmetodien kutsu on automaattista: järjestelmän generoima metodi kutsuu yliluokan sijoitusmetodia. Kun ohjelmassa esiintyy olion määrittely, järjestelmä kutsuu olion määrittelyluokan muodostinta. Jos olion määrittelyluokka on periytetty toisesta luokasta, järjestelmä kutsuu ensin yliluokan muodostinta, suorittaa sen rungon ja palaa sitten suorittamaan aliluokan muodostimen runkoa. Olion ilmentymä yliluokassa alustuu ensin ja sitten vasta aliluokassa oleva ilmentymä. Aliluokan olion tilanvapautuksen yhteydessä hajottimien suoritusjärjestys on päinvastainen. Järjestelmä suorittaa ensin aliluokan hajottimen rungon ja sitten yliluokan hajottimen rungon. Seuraavassa esimerkissä on toteutettu luokkien muodostimet ja hajottimet niin, että kutsujärjestys voidaan todeta. Normaalisti muodostimet sisältävät tietojäsenten alustukset ja hajotin niiden tyhjennyksen. Käyttäjälle näytettävien viestien tulostus näissä metodeissa on mielekästä vain testauksen yhteydessä.

Page 141: C++-KIELI - Oamkjjauhiai/opetus/olio/Olio-ohjelmointi-40.pdf · 2007. 1. 5. · C++-kieli Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved. 4 5.7.2 OSOITTIMET TIETUEESEEN.....33

C++-kieli

Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved.

140

#include <iostream>using namespace std ;

class Yliluokka{public:

Yliluokka (){

cout << "\n Luotu yliluokkaan: " << this ;}~Yliluokka (){

cout << "\n Tuhottu yliluokasta: " << this ;}

};

class Aliluokka : public Yliluokka{public:

Aliluokka (){

cout << "\n Luotu aliluokkaan: " << this ;}~Aliluokka (){

cout << "\n Tuhottu aliluokasta: " << this ;}

};

int main (){

Aliluokka Olio ;

return 0 ;}

Kuva 28-13. Oletusmuodostimen ja hajottimen kutsujärjestys.

Luotu yliluokkaan: 0x0012FF7CLuotu aliluokkaan: 0x0012FF7CTuhottu aliluokasta: 0x0012FF7CTuhottu yliluokasta: 0x0012FF7C

Kuva 28-14. Edellisen esimerkin tulostus. Yliluokan muodostin ja hajotin on toteutettu inline-metodina. Pääohjelmassa on aliluokkaan luotu olio. Tämä aiheuttaa aliluokan muodostimen kutsun. Järjestelmä ei kuitenkaan suorita aliluokan muodostimen runkoa, vaan kutsuu ensin automaattisesti yliluokan muodostinta. Lopuksi pääohjelman automaattinen olio tuhoutuu. Järjestelmä kutsuu aliluokan hajotinta, jonka runko suoritetaan ja sen jälkeen järjestelmä kutsuu yliluokan hajotinta. 28.5 Yliluokan muodostimen kutsuminen Muodostimet ovat periytymättömiä jäseniä eli ne eivät periydy aliluokkaan (-kiin). Tämä tarkoittaa sitä, että muodostimia ei voi kutsua suoraan aliluokasta märitetyn olion suhteen, vaan aliluokkaan on toteutettava omat muodostimet. Näiden aliluokan muodostimien yhteydessä voidaan kuitenkin ns. kutsua yliluokan parametrillista muodostinta, jolloin yliluokan muodostimelle voidaan välittä tarkoitukseen sopivat parametrit. Kuvassa 29-15 on esimerkki yliluokan muodostimen kutsumisesta.

Page 142: C++-KIELI - Oamkjjauhiai/opetus/olio/Olio-ohjelmointi-40.pdf · 2007. 1. 5. · C++-kieli Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved. 4 5.7.2 OSOITTIMET TIETUEESEEN.....33

C++-kieli

Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved.

141

/*ConstructorCall.h

Otsikkotiedosto joka sisältää 'Tietokone'- ja 'PDA'-luokan määritykset.(c) Markku Rahikainen, 2003

*/

/*** LUOKKA Tietokone ***/

class Tietokone{protected:

char Valmistaja [15] ;char Prosessori [25] ;unsigned int Kellotaajuus ;

public:Tietokone (char Manufacturer [], char Processor [], int Frequency) ;

};

Tietokone::Tietokone(char Manufacturer [], char Processor [], int Frequency){

strcpy (Valmistaja, Manufacturer) ;strcpy (Prosessori, Processor) ;Kellotaajuus = Frequency ;

}

/*** LUOKKA PDA ***/

class PDA : public Tietokone{private:

char Kayttojarjestelma [25] ;

public:// Aliluokan muodostin, jonka yhteydessä kutsutaan yliluokan muodostinta.PDA (char Manufacturer [], char Processor [], int Frequency)

: Tietokone(Manufacturer, Processor, Frequency){}

// Aliluokan muodostin, jonka yhteydessä kutsutaan yliluokan muodostinta ja// samalla siinä on aliluokan datajäsen alustus eli varsinainen aliluokan// parametrillinen muodostin (Hieman tavallisesta poikkeava kylläkin.).PDA (char Manufacturer [], char Processor [], int Frequency, char OS [])

: Tietokone(Manufacturer, Processor, Frequency){

strcpy (Kayttojarjestelma, OS) ;}

void TulostaTiedot () ;};

void PDA::TulostaTiedot(){

cout << "PDA-laitteen tekniset tiedot:\n" ;cout << Valmistaja << endl ;cout << Prosessori << endl ;cout << Kellotaajuus << endl ;cout << Kayttojarjestelma << endl << endl ;

}

Kuva 28-15. ConstructorCall.h

/*ConstructorCall.cpp

Ohjelma joka käyttää ConstructorCall.h tiedostossa olevia luokkia.(c) Markku Rahikainen, 2003

*/

#include <iostream>using namespace std ;

Page 143: C++-KIELI - Oamkjjauhiai/opetus/olio/Olio-ohjelmointi-40.pdf · 2007. 1. 5. · C++-kieli Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved. 4 5.7.2 OSOITTIMET TIETUEESEEN.....33

C++-kieli

Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved.

142

#include "ConstructorCall.h"

int main (){

PDA m515 ("Palm", "Motorola Dragonball VZ", 33) ;m515.TulostaTiedot() ;

PDA iPAQ ("Compaq", "ARM", 400, "Pocket PC 2002") ;iPAQ.TulostaTiedot() ;

return 0 ;}

Kuva 28-16. ConstructorCall.cpp

Kuva 28-17. Edellisen esimerkin tulostus.

Page 144: C++-KIELI - Oamkjjauhiai/opetus/olio/Olio-ohjelmointi-40.pdf · 2007. 1. 5. · C++-kieli Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved. 4 5.7.2 OSOITTIMET TIETUEESEEN.....33

C++-kieli

Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved.

143

29. VIRTUAALINEN METODI (Virtual function) Virtuaalinen metodi on metodi, josta voi olla useita toteutusratkaisuja ja jonka kutsua vastaavan toteutusratkaisun järjestelmä etsii olion määrittelyluokasta ohjelman suorituksen aikana. Eli virtuaalinen luokan jäsenfunktio on sellainen että se voidaan haluttaessa määritellä ja kirjoittaa aliluokassa uudelleen.

class Yliluokka{public:

virtual void Metodi () ;} ;

Kuva 29-1. Virtuaalisen metodin esittely. Virtuaalisen metodin esittely alkaa varatulla sanalla virtual. Virtuaalinen metodi on aina oliokohtainen metodi eikä sen esittelyn yhteydessä saa esiintyä varattua sanaa static. Muodostin ei voi olla virtuaalinen, koska olion määrittelyluokka on tiedettävä muodostinta kutsuttaessa. Jos luokassa on virtuaalisia metodeita, on myös hajottimen oltava virtuaalinen. Yliluokasta tulee monimuotoinen, kun luokassa on yksikin virtuaalinen metodi. Varattu sana virtual kertoo, että luokka sisältää metodin oletustoteutuksen ja, että aliluokissa voi olla useita oletuksen korvaavia toteutusratkaisuja. Luokkaa määriteltäessä tulisi aina miettiä, onko mahdollista, että luokka voidaan joskus tulevaisuudessa käyttää monimuotoisena yliluokkana. Jos näin on, kannattaa hajotin ja muut mahdollisesti korvattavat metodit esitellä virtuaalisiksi.

void Yliluokka::Metodi(){

// Oletustoteutus} ;

Kuva 29-2. Monimuotoinen luokka sisältää virtuaalisen metodin oletustoteutuksen. Virtuaalisen metodin toteutus vastaa tavallisen metodin toteutusta. Virtuaalinen metodi voi olla myös inline-metodi. Inline-sanalla ei kuitenkaan ole ohjelman suoritusta tehostavaa vaikutusta virtuaalisten metodien yhteydessä. Kääntäjä ei voi tehdä käännösaikana kutsun korvausta metodin toteutusratkaisulla, koska käytettävä toteutus riippuu osoitetun olion määrittelyluokasta eikä tunnuksen tyypistä. Monimuotoiseen luokkaan toteutettu virtuaalisen metodin toteutus on oletustoteutus, jota voidaan käyttää minkä tahansa luokkahierarkian olion käsittelyyn. Jos oletustoteutus ei ole sopiva jonkin monimuotoisen luokan aliluokalle, voi aliluokka sisältää oletustoteutuksen korvaavan toteutuksen.

class Aliluokka : Yliluokka{public:

void Metodi () {…} ;} ;

Kuva 29-3. Oletustoteutuksen korvaaminen aliluokassa. Oletustoteutuksen korvaava metodi toteutetaan tavallisen metodin tapaan (Voi olla myös inline-metodi) niihin aliluokkiin, joiden olioille monimuotoisen yliluokan oletustoteutusta ei haluta käyttää. Korvaava metodi voidaan esitellä myös virtuaalisena. Virtuaalisen metodin korvaavan metodin sisältävä luokka on periytettävä yliluokasta public-periytymistavalla, koska aliluokan olioita käytetään usein yliluokkaan osoittavan tunnuksen avulla. Jos periytymistapa ei olisi public, ei yliluokan tunnukseen ole mahdollista sijoittaa aliluokassa määriteltyä oliota.

Page 145: C++-KIELI - Oamkjjauhiai/opetus/olio/Olio-ohjelmointi-40.pdf · 2007. 1. 5. · C++-kieli Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved. 4 5.7.2 OSOITTIMET TIETUEESEEN.....33

C++-kieli

Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved.

144

Aliluokkaan toteutettavan metodin esittelyn on vastattava monimuotoisessa yliluokassa esiteltyä virtuaalista metodia. Vaatimukset ovat:

• Nimen on oltava sama kuin yliluokassakin. • Parametrien lukumäärän ja tyyppien on oltava samat kuin yliluokassa. • Metodin tyypin on oltava sama kuin yliluokassa.

�Poikkeus: Yliluokan metodi voi palauttaa osoittimen tai viittauksen yliluokkaan. �Poikkeus: Aliluokan metodi voi palauttaa osoittimen tai viittauksen aliluokkaan.

Jos yliluokassa on monta samannimistä virtuaalista metodia kuormitettuna on aliluokan korvattava ne kaikki tai ei yhtään. Jos yliluokassa on esitelty virtuaalinen metodi char Metodi (char); on korvaavan metodin esittelyn oltava aliluokassa täsmälleen samanlainen. Jos yliluokassa on esitelty Yliluokka &Metodi(); voi aliluokka kuitenkin korvata sen metodilla Aliluokka &Metodi();. Jos metodin parametrit tai tyyppi poikkeaa (Poikkeusta lukuun ottamatta) aliluokassa, ei metodit korvaa yliluokan virtuaalista metodia. Tällöin kääntäjä ei tulkitse virtual-sanaa lainkaan. Tästä seuraa, että metodin sidonta ei ole dynaamista vaan staattista, joten metodi suoritetaan aina olion tunnuksen esittelyluokasta eikä määrittelyluokasta.

Page 146: C++-KIELI - Oamkjjauhiai/opetus/olio/Olio-ohjelmointi-40.pdf · 2007. 1. 5. · C++-kieli Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved. 4 5.7.2 OSOITTIMET TIETUEESEEN.....33

C++-kieli

Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved.

145

30. TOTEUTUSTAVAN PERIYTYMINEN protected- JA private-PERIYTYMISTAVOILLA Toteutustavan periytymisessä (Implemantation inheritance) aliluokalle periytyvät yliluokassa määritellyt teknisestä ratkaisusta riippuvat tiedot ja metodit. Toteutustavan periytyminen ei näy aliluokasta ulospäin, aliluokka piilottaa periytymisen vaikutukset sisälleen. Tälläistä periytymistä voidaan käyttää, kun erilaisia toteutusratkaisuja sisältäviä konkreettisia luokkia on valmiina ja jotakin toteutusratkaisua halutaan soveltaa uudessa tilanteessa kirjoittamatta sitä uudelleen. Toteutustavan periytymistä kuvailee englannin kieliset maininnat is-implemented-as-a ja has-a. Toteutustavan periytymistä voidaan siis käyttää myös koosteen toteutuksessa. Usein aliluokan vastuut ovat senkaltaisia, että ne on mahdollista toteuttaa useilla eri tavoilla. Esimerkiksi käsitteet Joukko ja Pino ovat luokkia, jotka on mahdollista toteuttaa monen erilaisen tietorakenteen avulla. Vaihtoehtoisia toteutusratkaisuja voivat olla esimerkiksi Taulukko ja dynaaminen Lista. Taulukko ja lista ovat tietorakenteita, jotka eivät ole sidottuja pelkästään joukon tai pinon toteutukseen, vaan niitä voidaan käyttää missä tilanteessa tahansa talletusrakenteina.

Konkreettinen

Konkreettinen

Konkreettinen

Konkreettinen

Toteutus

Liittymä +

Esittely-luokka

Määrittely-luokka

Kuva 30-1. Toteutustavan periytyminen.

Toteutustavan periytymisessä yliluokka on konkreettinen metodien toteutuksen sisältävä luokka, esimerkiksi Taulukko tai Lista. Aliluokka, esim. Joukko tai Pino, on myös konkreettinen luokka, joka on toteutettu loogisella tasolla ottamatta kantaa toteutusratkaisuun. Yliluokan käyttö poikkeaa aliluokan ja aliluokan asiakkaiden näkökulmasta. Yliluokka ei ole lainkaan aliluokan asiakkaiden näkyvyysalueella, aliluokka peittää sen omilta asiakkailtaan. Toteutustavan periytyminen toteutetaan protected- ja private-periytymistavoilla. Periytymistavan valinnalla on merkitystä, kun suunnitellaan periytettävän aliluokan roolia tulevana yliluokkana. 30.1 Yliluokan näkyvyys aliluokan asiakkaiden ja toteuttajan näkökulmista Yliluokka on täysin näkymätön aliluokan asiakkaille. Yliluokka sisältää aliluokan toteutustavan. Toteutustapa ei milloinkaan näy aliluokan asiakkaille. Aliluokka siis piilottaa asiakkailtaan oman toteutustapansa ja yliluokan käyttötavan. Aliluokan palveluliittymä määrää siis täysin sen asiakkaiden käytössä olevat palvelut.

Yliluokka(toteutustapa)

Aliluokka(näkyvä liittymä)

Ei näy aliluokanasiakkaille

Kuva 30-2. Toteutustapa ja näkyvä liittymä. Seuraavassa on lueteltu yliluokan käyttömahdollisuudet aliluokan omasta ja aliluokan asiakkaiden näkökulmasta.

Page 147: C++-KIELI - Oamkjjauhiai/opetus/olio/Olio-ohjelmointi-40.pdf · 2007. 1. 5. · C++-kieli Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved. 4 5.7.2 OSOITTIMET TIETUEESEEN.....33

C++-kieli

Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved.

146

Aliluokka (Toteuttajan näkökulma)

• Voi käyttää yliluokan palveluita. • Voi käsitellä oman luokkansa tai aliluokkansa olioita yliluokan tunnuksella: Monimuotoisuus toimii luokkien metodeissa. • Määrää täysin oman luokkansa olioille näkyvästä palveluliittymästä. • Voi julkaista yliluokan palvelun oman luokkansa olioille kumoamalla periytymistavan. • Voi välittää yliluokan jäsenten näkyvyyden tuleville aliluokille, kun luokka periytyy yliluokasta protected-periytymistavalla. • Voi estää yliluokan jäsenten näkyvyyden tuleville aliluokille, kun luokka periytyy yliluokasta private-periytymistavalla.

Aliluokan asiakas

• Ei näe lainkaan yliluokan palveluliittymää: Ei voi käsitellä aliluokan olioita yliluokan tunnuksella (Luonti, tyyppimuunnokset, viestin välitys eivät ole mahdollisia). • Näkee vain aliluokan tarjoaman palveluliittymän, joka voi sisältää aliluokassa toteutettuja palveluita ja aliluokan julkistamia yliluokan palveluita.

Seuraava esimerkki esittelee metodikutsut, jotka ovat oletusarvoisesti mahdollisia private- ja protected-periytymistapoja käytettäessä. Periytymistapa private vaikuttaa siten, että yliluokan protected- ja public-jäsenet ovat aliluokassa private-tyyppisiä. Periytymistapa protected vaikuttaa siten, että yliluokan protected- ja public-jäsenet ovat aliluokassa protected-tyyppisiä.

#include <iostream>using namespace std ;

class Yliluokka{public:

virtual void Ali1(){

cout << "\n Yliluokan Ali1" ;}virtual void Ali2(){

cout << "\n Yliluokan Ali2" ;}

};

class Aliluokka : private Yliluokka{public:

void Ali2(){

cout << "\n Aliluokan Ali2" ;}void Ali3(){

cout << "\n Aliluokan Ali3 kutsuu: " ;Ali1 () ;

}};

int main ( ){

Aliluokka olio ;olio.Ali2() ;olio.Ali3() ;

return 0 ;}

Kuva 30-3. Metodin kutsumahdollisuudet private-periytymistapaa käytettäessä.

Page 148: C++-KIELI - Oamkjjauhiai/opetus/olio/Olio-ohjelmointi-40.pdf · 2007. 1. 5. · C++-kieli Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved. 4 5.7.2 OSOITTIMET TIETUEESEEN.....33

C++-kieli

Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved.

147

Aliluokan Ali2Aliluokan Ali3 kutsu:Yliluokan Ali1

Kuva30-4. Edellisen esimerkin tulostus. Edellisen esimerkin yliluokka sisältää kaksi virtuaalisen metodin oletustoteutusta, jotka ovat kaikkien luokkahierarkian olioiden käytettävissä. Aliluokka on periytetty yliluokasta private-periytymistavalla, jolloin yliluokan protected- ja public-jäsenistä tulee private-tyyppisiä aliluokassa. Tämä aiheuttaa sen, että yliluokan metodit eivät ole näkyvissä pääohjelmassa aliluokan olioita käsiteltäessä. Huomaa, että periytymistapa ei kuitenkaan vaikuta aliluokan metodeihin, ne voivat kutsua suoraan yliluokan metodeita. Pääohjelmassa luodaan olio aliluokkaan. Tälle oliolle on lähetetty kaikki sellaiset viestit, mitkä ovat mahdollisia. Aliluokan oliolle on mahdollista lähettää vain niitä viestejä, jotka on esitelty aliluokassa. Kaikki seuraavat rivit aiheuttaisivat pääohjelmassa käännösvirheen:

Olio.Ali1 () ;Yliluokka *olio2 = new Aliluokka ;Olio2->Ali1 () ;

Huomaa, että yliluokan olioiden käsittely on mahdollista normaalisti aliluokista riippumatta. Seuraavat rivit ovat siis oikein:

Yliluokka *olio = new Yliluokka ;Olio->Ali1 () ;

30.2 Periytymistavan vaikutuksen kumoaminen Periytymistavan vaikutus voidaan kumota tarvittaessa yksittäisten yliluokan jäsenten kohdalta. Tämä mahdollistaa valittujen yliluokan palvelujen liittämisen aliluokan olioiden palveluliittymään. Tällöin aliluokan olioille voidaan lähettää viesti, jota ei ole toteutettu aliluokassa.

Yliluokka::jäsen ;using Yliluokka::jäsen ;

Kuva 30-5. Perityn jäsenen merkintä periytymistavan kumoamisessa. Periytymistavan vaikutuksen kumoaminen toteutetaan kirjoittamalla yliluokan jäsenen nimi aliluokkaan. Nimi on kirjoitettava saman saantimääreen jälkeen, kuin se esiintyi yliluokassa. Näkyvyyssääntöjä ei ole siis mahdollista muuttaa tiukemmiksi tai väljemmiksi kuin yliluokassa. Ensimmäisellä rivillä oleva merkintätapa on vanhempi kuin toisella rivillä näkyvä merkintätapa. Toisen rivin merkintätapa ei välttämättä käy vanhemmissa kääntäjäympäristöissä. Seuraavassa esimerkissä on periytymistapa kumottu yliluokan Ali1-nimisen metodin osalta.

#include <iostream>using namespace std ;

class Yliluokka{public:

virtual void Ali1() const{

cout << "\n Yliluokan Ali1" ;}

Page 149: C++-KIELI - Oamkjjauhiai/opetus/olio/Olio-ohjelmointi-40.pdf · 2007. 1. 5. · C++-kieli Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved. 4 5.7.2 OSOITTIMET TIETUEESEEN.....33

C++-kieli

Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved.

148

virtual void Ali2() const{

cout << "\n Yliluokan Ali2" ;}

};

class Aliluokka : private Yliluokka{public:

void Ali2() const{

cout << "\n Aliluokan Ali2" ;}void Ali3() const{

cout << "\n Aliluokan Ali3 kutsuu: " ;Ali1() ;

}using Yliluokka::Ali1 ;

};

int main ( ){

Aliluokka olio ;olio.Ali1() ;

return 0 ;}

Kuva 30-6. Periytymistavan kumoaminen.

Yliluokan Ali1

Kuva 30-7. Edellisen esimerkin tulostus. Aliluokassa on kumottu private-periytymistapa yliluokan Ali1-metodin osalta kirjoittamalla metodin nimi public-saantimääreen jälkeen. Metodin nimen yhteyteen on kirjoitettava myös luokan nimi. Huomaa, että kysymyksessä ei ole metodin uudelleen esittely, metodin tyyppiä ja parametreja ei kirjoiteta lainkaan nimen yhteyteen. Pääohjelmassa oleva metodikutsu (olio.Ali1();) on nyt mahdollinen eli aliluokan oliolle voidaan lähettää viesti, joka on määritelty yliluokassa. 30.3 Esimerkkejä Olio-ohjelmoinnissa ajatellaan, että luokka (esim. Pankkitili) on joukko tietoja (esim. tilin omistajan nimi, pankkitilin numero ja tilillä oleva rahamäärä eli tilin saldo), ja näiden tietojen käsittelyyn luokka tarjoaa joukon palveluita (esim. jäsenfunktio joka näyttää kaikki pankkitilin tiedot). Luokan tarjoamia palveluita nimitetään siis jäsenfunktioiksi. Joskus niitä nimitetäänn myös metodeiksi tai operaatioiksi, jotka ovat luokan olioille tehtävissä. Kun luokkia määritellään, on oleellista että samankaltaisia asioita ei määritellä ja toteuteta useaan kertaan. C++ mahdollistaa sen, että esimerkiksi johonkin luokkajoukkoon kuuluvat yleiset asiat määritellään jossain yhdessä yläluokassa, josta ne sitten ns. perintämekanismin avulla siirretään toisten luokkien, niin kutsuttujen alaluokkien, käytettäviksi. Esimerkiksi pankkitilien tapauksessa voidaan ajatella, että kaikilla pankkitileillä on joitakin yleisiä ominaisuuksia ja niihin liittyy joitakin yleisiä toimintoja. Eri tyyppisillä pankkitileillä on yleisten ominaisuuksien lisäksi erityispiirteitä. Olio-ohjelmoinnissa voidaan asiat luokitella yleisiin ja vähemmän yleisiin asioihin ns. perinnän avulla.

Page 150: C++-KIELI - Oamkjjauhiai/opetus/olio/Olio-ohjelmointi-40.pdf · 2007. 1. 5. · C++-kieli Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved. 4 5.7.2 OSOITTIMET TIETUEESEEN.....33

C++-kieli

Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved.

149

30.3.1 Pankkii.cpp Seuraavassa esitellään C++-kielen periytymismekanismia pankkitileihin liittyvän yksinkertaisen esimerkkiohjelman Pankkii.cpp sekä luokat Pankkitili ja Parempi_tili sisältävän luokkatiedoston Pankkii.h avulla.

//// Pankkii.h//// This file contains the definition for class Pankkitili,// class Parempi_tili and these member functions.//

// Luokka Pankkitili on yksinkertainen pankkitililuokka, jolla on kolme// datajäsentä. Nämä datajäsenet saavat arvot konstruktorifumktion// avulla silloin, kun Pankkitili-tyyppinen olio luodaan.class Pankkitili{protected:

char tilin_omistajan_nimi [ 50 ] ;long tilinumero ;double tilin_saldo ;

public:// Konstruktorin kolmannella argumentilla on oletusarvona 0.0. Tämä// tarkoittaa sitä, että mikäli oliota luotaessa ei anneta alkusaldoa, niin// se merkitään nollaksi.Pankkitili( char annettu_tilin_omistajan_nimi[ ],

long annettu_tilinumero,double tilin_alkusaldo = 0.0 ) ;

void nayta_tilin_tiedot ( ) ;} ;

// Konstruktorifunktio, jota siis kutsutaan automaattisesti, kun Pankkitili-olio// luodaan, kopioi argumenttinaan saamansa tiedot olion datajäsenten// arvoiksi. Stringi täytyy kopioida standardifunktion strcpy avulla.Pankkitili::Pankkitili( char annettu_tilin_omistajan_nimi[ ],

long annettu_tilinumero,double tilin_alkusaldo )

{strcpy ( tilin_omistajan_nimi, annettu_tilin_omistajan_nimi ) ;tilinumero = annettu_tilinumero ;tilin_saldo = tilin_alkusaldo ;

}

// Tämä on ainoa Pankkitililuokan varsinainen jäsenfunktio. Konstruktorikin// on kyllä jäsenfunktio, mutta se on erikoinen jäsenfunktio. Tämä funktio// yksinkertaisesti näyttää ruudulla luokan datajäsenten arvot sopivilla// teksteillä höystettynä.void Pankkitili::nayta_tilin_tiedot(){

cout << "\n\n P A N K K I T I L I N T I E D O T : "<< "\n Tilin omistajan nimi: " << tilin_omistajan_nimi<< "\n Tilinumero: " << tilinumero<< "\n Nykyinen tilin saldo: " << tilin_saldo << "\n" ;

}

// Seuraava luokka "Parempi_tili" johdetaan luokasta "Pankkitili".// Luokka "Parempi_tili" siis perii luokan "Pankkitili" datajäsenet// ja jäsenfunktiot.

// Merkintä : public Pankkitili kertoo C++ kääntäjälle, että luokka// Parempi_tili perii luokan Pankkitili. Luokan Pankkitili jäsenistä// tulee protected- ja public-jäseniä luokkaan Parempi_tili. Voidaan// kuvitella, että kaikki luokan Pankkitili jäsenet, siis jäsenfunktiot ja// datajäsenet, tulevat tämän merkinnän avulla ”näkymättömästi kirjoitetuksi”// myös tähän Parempi_tili –nimiseen luokkaan.

class Parempi_tili : public Pankkitili{public:

Page 151: C++-KIELI - Oamkjjauhiai/opetus/olio/Olio-ohjelmointi-40.pdf · 2007. 1. 5. · C++-kieli Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved. 4 5.7.2 OSOITTIMET TIETUEESEEN.....33

C++-kieli

Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved.

150

Parempi_tili( char annettu_tilin_omistajan_nimi [ ], long annettu_tilinumero,double tilin_alkusaldo )

// Perittäessä peritään kaikki datajäsenet ja jäsenfunktiot, mutta ei// konstruktoreita eikä destruktoreita. Tässä on luokan Parempi_tili// oma konstruktori, joka on itse asiassa kutsu luokan Pankkitili// konstruktoriin ja ”käskylauseeton funktio” (tyhjät aaltosulut).: Pankkitili( annettu_tilin_omistajan_nimi, annettu_tilinumero,

tilin_alkusaldo ) { }

void talleta_rahaa ( double talletettava_rahamaara ) ;void nosta_rahaa ( double nostettava_rahamaara ) ;

} ;

// Luokalla Parempi_tili on kaksi omaa jäsenfunktiota, joista tässä on// ensimmäinen. Tämän avulla voidaan pankkitiliolioon tallettaa funktiolle// argumenttina annettu rahamäärä.void Parempi_tili::talleta_rahaa( double talletettava_rahamaara ){

cout << "\n\n TALLETUS TILILLE " << tilinumero<< " (Omistaja " << tilin_omistajan_nimi << ")"<< "\n Talletettu: " << talletettava_rahamaara<< "\n Vanha saldo: " << tilin_saldo<< " Uusi saldo: " ;

// Rahan talletus tilille luonnollisesti kasvattaa tilin saldoa.tilin_saldo = tilin_saldo + talletettava_rahamaara ;// Tilin saldo tulostetaan tässä sen kasvattamisen jälkeen. Aiemmin// se on tulostettu jo ennen kasvattamista.cout << tilin_saldo << "\n" ;

}

// Tämä on toinen luokan Parempi_tili oma jäsenfunktio. Jäsenfunktiolle// annetaan argumenttina rahamäärä, joka tililtä halutaan nostettavan.void Parempi_tili::nosta_rahaa( double nostettava_rahamaara ){

// Tililtä rahaa nostettaessa tulee tutkia, että tilillä on todella katetta// riittävästi nostoa varten.if ( tilin_saldo < nostettava_rahamaara ){

cout << "\n\n VAROITUS: Tililla " << tilinumero<< " ei ole katetta nostaa " << nostettava_rahamaara<< " !!! \n" ;

}else{

cout << "\n\n NOSTO TILILTA " << tilinumero<< " (Omistaja " << tilin_omistajan_nimi << ")"<< "\n Nostettu: " << nostettava_rahamaara<< "\n Vanha saldo: " << tilin_saldo<< " Uusi saldo: " ;

tilin_saldo = tilin_saldo - nostettava_rahamaara ;cout << tilin_saldo << "\n" ;

}}

Kuva 30-8. Pankkii.h

//// Pankkii.cpp//// Tassa ohjelmassa on luokasta Pankkitili johdettu parempi// pankkitililuokka Parempi_tili (Kts. otsikkotiedosto).//

#include <iostream.h>#include <string.h>

#include "Pankkii.h"

void main (){

Page 152: C++-KIELI - Oamkjjauhiai/opetus/olio/Olio-ohjelmointi-40.pdf · 2007. 1. 5. · C++-kieli Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved. 4 5.7.2 OSOITTIMET TIETUEESEEN.....33

C++-kieli

Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved.

151

Pankkitili joku_pankkitili( "Martti Ahtisaari", 1234567L, 1234.55 ) ;

joku_pankkitili.nayta_tilin_tiedot( ) ;

Parempi_tili toinen_pankkitili( "Markku Rahikainen", 55443322L, 3000.00 ) ;

// Tässä nähdään konkreettisesti, että periytyminen on tapahtunut. On// mahdollista kutsua funktiota nayta_tilin_tiedot myös luokan Parempi_tili// oliolle toinen_pankkitili, vaikka kyseinen funktio on määritelty luokassa// Pankkitili. Tämän funktion on siis täytynyt periytyä luokasta Pankkitili// luokkaan Parempi_tili.toinen_pankkitili.nayta_tilin_tiedot() ;toinen_pankkitili.talleta_rahaa( 555.55 ) ;toinen_pankkitili.nosta_rahaa( 444.44 ) ;toinen_pankkitili.nosta_rahaa( 6666.66 ) ;

} // End of main.

Kuva 30-9. Pankkii.cpp

Kuva 30-10. Ohjelman Pankkii.cpp tulostus.

30.3.2 Pankkiv.cpp Virtuaalinen luokan jäsenfunktio on sellainen, että se voidaan haluttaessa määritellä ja kirjoittaa alaluokassa uudelleen. Luokan jäsenfunktio määritellään virtuaaliseksi kirjoittamalla C++ kielen varattu sana virtual jäsenfunktion esittelyn eteen seuraavaan tapaan:

class Luokan_nimi{protected:

// Datajäsenet

public:…

virtual void jäsenfunktion_nimi (……

} ;

Kun jäsenfunktio määritellään virtuaaliseksi, annetaan ikään kuin lupa sen uudelleenkirjoittamiseen alaluokassa. Normaalistihan jäsenfunktiot periytyvät alaluokille eikä niiden toimintaa voi alaluokissa muuttaa. Seuraavassa on esimerkkiohjelma Pankkiv.cpp sekä luokat Yleistili ja Rajoitettu_tili sisältävän luokkatiedoston Pankkiv.cpp, jossa demonstroidaan virtuaalifunktioiden käyttöä. Huomattavaa on se, että ohjelman Pankkiv.cpp funktiot ja datajäsenet ovat suurelta osin sama, kuin aiemmin olleessa ohjelmassa Pankkii.cpp.

Page 153: C++-KIELI - Oamkjjauhiai/opetus/olio/Olio-ohjelmointi-40.pdf · 2007. 1. 5. · C++-kieli Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved. 4 5.7.2 OSOITTIMET TIETUEESEEN.....33

C++-kieli

Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved.

152

//// Pankkiv.h//// This file contains the definition for class Pankkitili,// class Parempi_tili and these member functions.//// Tassa johdetaan luokasta Yleistili// uusi luokka Rajoitettu_tili, jossa jasenfunktio// nosta_rahaa on maaritelty uudelleen. Kyseinen funktio// on siis virtuaalinen luokassa Yleistili.//

class Yleistili{protected:

char tilin_omistajan_nimi[ 50 ] ;long tilinumero ;double tilin_saldo ;

public:Yleistili( char annettu_tilin_omistajan_nimi[], long annettu_tilinumero,

double tilin_alkusaldo = 0.0 ) ;

void nayta_tilin_tiedot() ;

// Seuraavat kaksi jäsenfunktiota on määritetty virtuaalisiksi. Tämä// tarkoittaa sitä, että jos tästä luokasta johdetaan toisia luokkia, nämä// jäsenfunktiot voidaan määritellä uudelleen.// Jäljempänä määritellään luokka Rajoitettu_tili, jossa jäsenfunktio// nosta_rahaa on määritelty ja kirjoitettu uudestaan. Näin ollen luokan// Rajoitettu_tili oliot hyödyntävät tämän yläluokan Yleistili jäsenfunktioita,// paitsi että ne käyttävät oman luokkansaerikoista nosta_rahaa funktiota.virtual void talleta_rahaa( double talletettava_rahamaara ) ;virtual void nosta_rahaa( double nostettava_rahamaara ) ;

} ;

Yleistili::Yleistili(char annettu_tilin_omistajan_nimi[ ], long annettu_tilinumero,double tilin_alkusaldo )

{strcpy( tilin_omistajan_nimi, annettu_tilin_omistajan_nimi ) ;

tilinumero = annettu_tilinumero ;tilin_saldo = tilin_alkusaldo ;

}

void Yleistili::nayta_tilin_tiedot(){

cout << "\n\n P A N K K I T I L I N T I E D O T : "<< "\n Tilin omistajan nimi: " << tilin_omistajan_nimi<< "\n Tilinumero: " << tilinumero<< "\n Nykyinen tilin saldo: " << tilin_saldo << "\n" ;

}

// Jäsenfunktiot talleta_rahaa ja nosta_rahaa ovat samanlaiset, kuin// aiemmin esitellyssä ohjelmassa Pankkii.cpp.

void Yleistili::talleta_rahaa( double talletettava_rahamaara ){

cout << "\n\n TALLETUS TILILLE " << tilinumero<< " (Omistaja " << tilin_omistajan_nimi << ")"<< "\n Talletettu: " << talletettava_rahamaara<< "\n Vanha saldo: " << tilin_saldo << " Uusi saldo: " ;

tilin_saldo = tilin_saldo + talletettava_rahamaara ;cout << tilin_saldo << "\n" ;

}

void Yleistili::nosta_rahaa( double nostettava_rahamaara ){

if ( tilin_saldo < nostettava_rahamaara ){

cout << "\n\n VAROITUS: Tililla " << tilinumero

Page 154: C++-KIELI - Oamkjjauhiai/opetus/olio/Olio-ohjelmointi-40.pdf · 2007. 1. 5. · C++-kieli Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved. 4 5.7.2 OSOITTIMET TIETUEESEEN.....33

C++-kieli

Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved.

153

<< " ei ole katetta nostaa " << nostettava_rahamaara << " !!! \n" ;}else{

cout << "\n\n NOSTO TILILTA " << tilinumero<< " (Omistaja " << tilin_omistajan_nimi << ")"<< "\n Nostettu: " << nostettava_rahamaara<< "\n Vanha saldo: " << tilin_saldo << " Uusi saldo: " ;

tilin_saldo = tilin_saldo - nostettava_rahamaara ;cout << tilin_saldo << "\n" ;

}}

class Rajoitettu_tili : public Yleistili{protected:

double tilin_nostoraja ;

public:Rajoitettu_tili(char annettu_tilin_omistajan_nimi[], long annettu_tilinumero,

double tilin_alkusaldo, double annettu_tilin_nostoraja = 2000.00)

: Yleistili( annettu_tilin_omistajan_nimi, annettu_tilinumero, tilin_alkusaldo ){

// Luokan Rajoitettu_tili konstruktori ottaa yhden argumentin enemmän// kuinyläluokkansa konstruktori. Tässä neljäs argumentti sijoitetaan// uuden datajäsenen arvoksi.tilin_nostoraja = annettu_tilin_nostoraja ;

}

// Jäsenfunktio nosta_rahaa on siis tässä määritelty uudelleen.void nosta_rahaa( double nostettava_rahamaara ) ;

} ;

// Tässä on luokan Rajoitettu_tili erikoisen jäsenfunktion nosta_rahaa// ohjelmakoodi.Tämä nosta_rahaa –funktio on sellainen, että se ei anna// suorittaa nostoa, jos nostettava rahamäärä on suurempi, kuin tilille// määritelty nostoraja. Muuten tämä jäsenfunktio toimii samoin kuin// yläluokassa oleva vastaava funktio.void Rajoitettu_tili::nosta_rahaa( double nostettava_rahamaara ){

if ( nostettava_rahamaara > tilin_nostoraja ){

cout << "\n\n VAROITUS: Tililta " << tilinumero<< " ei voi nostaa " << nostettava_rahamaara<< " Nostoraja: " << tilin_nostoraja << " !!\n" ;

}else if ( tilin_saldo < nostettava_rahamaara ){

cout << "\n\n VAROITUS: Tililla " << tilinumero<< " ei ole katetta nostaa " << nostettava_rahamaara<< " !!! \n" ;

}else{

cout << "\n\n NOSTO TILILTA " << tilinumero<< " (Omistaja " << tilin_omistajan_nimi << ")"<< "\n Nostettu: " << nostettava_rahamaara<< "\n Vanha saldo: " << tilin_saldo<< " Uusi saldo: " ;

tilin_saldo = tilin_saldo - nostettava_rahamaara ;

cout << tilin_saldo << "\n" ;}

}

Kuva 30-11. Pankkiv.h

Page 155: C++-KIELI - Oamkjjauhiai/opetus/olio/Olio-ohjelmointi-40.pdf · 2007. 1. 5. · C++-kieli Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved. 4 5.7.2 OSOITTIMET TIETUEESEEN.....33

C++-kieli

Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved.

154

//// Pankkiv.cpp//#include <iostream.h>#include <string.h>

#include "Pankkiv.h"

void main (){

Yleistili tavallinen_tili( "Keke Rosberg", 1234567L, 4000.00 ) ;

tavallinen_tili.nosta_rahaa( 1111.11 ) ;

Rajoitettu_tili ruokarahatili( "Mika Hakkinen", 55443322L, 4000.00, 1000.00 ) ;

ruokarahatili.nosta_rahaa( 444.44 ) ;

// ruokarahatili_olion nostorajaksi on oliota luotaessa märätty 1000.00,// joten nosto 1111.11 ei onnistu.ruokarahatili.nosta_rahaa( 1111.11 ) ;

Rajoitettu_tili vaaterahatili( "Mika Salo", 99119911L, 4000.00 ) ;

vaaterahatili.nosta_rahaa( 1111.11 ) ;// Oliota vaaterahatili luotaessa ei annettu argumenttina nostorajaa, joten// tilin nostorajaksi tulee oletusarvo 2000.00. Näin nosto summalla 1111.11// onnsituu, mutta nosto summalla 2222.22 ei tule hyväksytyksi.vaaterahatili.nosta_rahaa( 2222.22 ) ;

} // End of main.

Kuva 30-12. Pankkiv.cpp

Kuva 30-13. Ohjelman Pankkiv.cpp tulostus.

Page 156: C++-KIELI - Oamkjjauhiai/opetus/olio/Olio-ohjelmointi-40.pdf · 2007. 1. 5. · C++-kieli Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved. 4 5.7.2 OSOITTIMET TIETUEESEEN.....33

C++-kieli

Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved.

155

36. KELLONAIKA JA PÄIVÄYS time-kirjasto sisältää joukon funktioita, joilla voidaan pyytää kuluva päivämäärä ja kellonaika. Kirjastossa on myös funktioita, joilla voidaan vertailla päivämääriä ja kellonaikoja keskenään. Kirjasto pyörii tm-nimisen struktuurin ympärillä. Tässä struktuurissa on 9 int-jäsenmuuttujaa, joilla kuvataan sekunteja, minuutteja, tunteja, kuukauden päivää, kuukauden numeroa (Tammikuu = 0), vuodesta 1900 kuluneiden vuosien määrää, viikonpäivää (Sunnuntai = 0), vuodenpäivää (0-365) ja totuusarvoa joka kertoo otetaanko kesä- ja talviaika huomioon (Kaikki ympäristöt eivät tue tätä viimeistä arvoa.). Useimmille aika-funktioille välitetään parametriksi time_t-tyyppinen arvo tai osoitin sen tyyppiseen muuttujaan. Kirjastossa on muunnosfunktioita, joilla time_t-tyyppinen muuttuja muutetaan tm-struktuuriksi. Standardikirjastossa on mm. time ( ) –funktio, jolle annetaan osoitin time_t-tyyppiseen muuttujaan. Funktio vie kellonajan osoittimen osoittamaan paikkaan. Kirjastossa on myös ctime ( ) –funktio, jolle välitetään time_t-tyyppinen muuttuja. Funktio palauttaa ASCII-merkkijonon, jossa on kerrottu kellonaika ja päivämäärä. Jos tulostus pitää muotoilla tarkemmin, time_t-tyyppinen muuttuja voidaan välittää localtime()-funktiolle, joka palauttaa osoittimen tm-tyyppiseen struktuuriin.

#include <time.h>#include <iostream.h>

void main ( ){

time_t AikaNyt ;

// Kysytään ja tulostetaan aika nyt.time (&AikaNyt) ; // Otetaan kuluva aika talteen.cout << " Nyt on " << ctime (&AikaNyt) << endl ;

struct tm *ptm ;ptm = localtime (&AikaNyt) ;

cout << " Tanaan on " << ptm->tm_mday << "." ;cout << ((ptm->tm_mon)+1) << "." ;cout << ptm->tm_year + 1900 << endl ;

cout << " Kello on: " << ptm->tm_hour << ":" ;cout.width(2) ;cout.fill(‘0‘) ;

cout << ptm->tm_min << ":" ;cout << ptm->tm_sec ;

cout << "\n Valmis. \n\n" ;}

Kuva 36-1. Esimerkki eri aikafunktioiden käytöstä.

Kuva 36-2. Edellisen esimerkin tulostus.

Page 157: C++-KIELI - Oamkjjauhiai/opetus/olio/Olio-ohjelmointi-40.pdf · 2007. 1. 5. · C++-kieli Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved. 4 5.7.2 OSOITTIMET TIETUEESEEN.....33

C++-kieli

Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved.

156

37. TIEDOSTOT C++-kielessä fstream-kirjasto sisältää tiedostojen käsittelyssä käytettäviä luokkia ja metodeita. Tiedoston käsittely tapahtuu binääri- tai tekstimuodossa (ASCII). Tiedostoja käsitellään yleensä binäärimuotoisina, kun tiedot halutaan tallettaa ohjelman suorituskertojen välillä ja ladata uudelleen seuraavalla suorituskerralla. ASCII-muotoista talletusta käytetään lähinnä silloin, kun tiedostosta halutaan tuottaa selväkielisessä tekstimuodossa oleva tulostiedosto. Tekstimuodossa olevaa tietoa voidaan helposti käsitellä editorilla, kun taas binäärimuotoinen tieto on sisäisen esitystavan mukaista eikä ole näin luettavassa muodossa. Tietojen talletuksessa tekstimuotoon tapahtuu tietojen muunnos sisäisestä esitystavasta merkkimuotoiseksi. Esimerkiksi double-tyyppisten lukujen muunnoksessa voi tapahtua muunnos- ja pyöristysvirheitä, joita ei tapahdu binäärimuotoisessa talletuksessa. Tietojen talletus binäärimuotoon kuluttaa myös vähemmän aikaa ja tilaa kuin tiedon talletus tekstimuotoon. Fstream-kirjasto sisältää siis luokkia ja metodeita tiedostojen binääri- ja tekstimuotoiseen käsittelyyn. 37.1 Binäärimuotoinen tiedostojen käsittely Binäärimuotoisen tiedoston käsittely voi olla peräkkäiskäsittelyä tai hajakäsittelyä. Peräkkäiskäsittelyssä tiedostoa käsitellään joko syöttötiedostona, josta luetaan tietoja tai tulostiedostona, jonne kirjoitetaan tietoja. Hajakäsittelyssä voidaan tiedosto-osoitin siirtää haluttuun kohtaan tiedostoa lukematta tai kirjoittamatta järjestyksessä. Hajakäsittelyssä samaa tiedostoa käsitellään usein kaksisuuntaisesti: Sinne kirjoitetaan ja sieltä luetaan tietoja. Tiedostoja käsiteltäessä on ohjelmakoodiin sisällytettävä fstream-otsikkotiedosto (Aiemmin fstream.h) #include-komennolla. Tiedostojen käsittelyssä tarvitaan fstream-, ifstream- ja ofstream-luokkia, jotka periytyvät tietovirtoja käsittelevistä istream- ja ostream-luokista. Käytettävä luokka voidaan ymmärtää tiedostotyyppinä, joka ilmaisee tiedostonkäsittelytavan. 37.1.1 Tiedoston avaus open-metodilla Tiedostoja käsitellään ohjelmassa tiedosto-olion avulla. Tiedosto-olion luokka sisältää metodit, joiden avulla tiedostoja on mahdollista käsitellä. Tiedosto-olion luokka edustaa tiedostotyyppiä, joka määrää tiedostonkäsittelytavan. Tiedosto-olio voidaan luoda kolmeen eri luokkaan:

• fstream: Jos tiedostoa halutaan lukea ja sinne halutaan kirjoittaa avaamatta tiedostoa erikseen syöttö- ja tulostustiedostona. • ifstream: Jos tiedostoa halutaan lukea. • ofstream: Jos tiedostoon halutaan kirjoittaa.

Tiedosto-olio on eräänlainen suodatin, jonka kautta voidaan käsitellä levyllä olevaa tiedostoa. Yksi tiedosto-olio voidaan tarvittaessa liittää eri tiedostoihin eri aikoina. Tiedosto-olion luonti ja fyysisen tiedoston avaus ovat eri tapahtumia, jotka on mahdollista kirjoittaa ohjelmassa erikseen tai yhteen.

Tiedosto_olion_luokka Tiedosto ;Tiedosto.open (Tiedoston_nimi, Avaustapa) ;

Kuva 37-1. Tiedoston luonti ja avaus erikseen open-metodilla. Ensimmäisellä rivillä on pelkkä tiedosto-olion luonti ilman tiedoston avausta. Tiedosto_olion_luokka on jokin luokista fstream, ifstream tai ofstream. Tiedosto on ohjelmassa käytettävä nimi tiedosto-oliosta. Toisella rivillä

Page 158: C++-KIELI - Oamkjjauhiai/opetus/olio/Olio-ohjelmointi-40.pdf · 2007. 1. 5. · C++-kieli Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved. 4 5.7.2 OSOITTIMET TIETUEESEEN.....33

C++-kieli

Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved.

157

on tiedoston avaus open-metodilla. open-metodille on välitettävä kaksi parametria. Tiedoston_nimi on merkkijono, joka sisältää levyllä olevan tiedoston ulkoisen nimen (Käyttöjärjestelmässä näkyvä nimi.). Avaustapa on kokonaisluku, joka sisältää tiedon tiedoston avaustavasta.

Tiedosto_olion_luokka Tiedosto (Tiedoston_nimi, Avaustapa) ;

Kuva 37-2. Tiedoston luonti ja avaus yhdessä. Jos tiedosto-olion luonti ja tiedoston avaus kirjoitetaan yhteen, ei erillistä open-metodin kutsua tarvita. Tällöin Tiedoston_nimi ja Avaustapa kirjoitetaan tiedosto-olion nimen jälkeen sulkeisiin. Tiedoston nimi sisältää tiedoston ulkoisen nimen. Esimerkiksi DOS-järjestelmässä tämä voisi olla “Tdsto.txt”. Järjestelmä etsii tiedostoa yleensä samasta hakemistosta kuin missä ohjelma sijaitsee. Kääntäjän optioilla on mahdollista vaikuttaa tiedoston hakupolkuun. Myös ohjelmassa voidaan määrätä tiedoston tarkka sijainti, esim. “c:\\Alihak\\Tdsto.txt”. Hakemisto- ja tiedostonimien välissä on oltava kaksi kenoviivaa, koska kenoviivan ja kirjaimen yhdistelmä on ohjausmerkki, jolla on C++-kielessä tietty merkitys (Esim. ‘\t‘ on tabulointi.). Tiedoston avaustapa voidaan määritellä avaushetkellä avauslippuja käyttäen. Avauslippuja voidaan yhdistää |-merkillä kokonaislukukenttään.

TAULUKKO Tiedoston avaustavat ja avauksessa käytettävät avausliput eli avausbitit.

Avausbitti Merkitys ios_base::in Avaus tiedoston lukemista varten. Oletusarvo ifstream-tiedostoilla. Kuten C-kielessä “r”. ios_base::out Avaus tiedostoon kirjoittamista varten. Oletusarvo ofstream-tiedostoilla. Kuten C-kielessä “w”. ios_base::out | ios_base::app Tulostiedoston avaus vanhoja tietoja tuhoamatta, uusien tietojen kirjoittaminen tiedoston loppuun vanhojen tietojen perään. Kuten C-kielessä “a”. ios_base::out | ios_base::ate Tiedosto-osoitin siirtyy avauksen yhteydessä tiedoston loppumerkkiin. ios_base::out | ios_base::trunc Luo uuden tulostiedoston avattaessa (Tyhjentää tiedoston tiedot.). Oletusarvo, kun tiedosto on avattu tulostiedostoksi (ios_base::out). ios_base::in | ios_base::out Avaus lukemista ja kirjoittamista varten. Kuten C-kielen “r+”. ios_base::in | ios_base::out | Avaus lukemista ja kirjoittamista varten (Tyhjentää tiedoston.). Kuten C-kielen “w+”. ios_base::trunc Jokin_edellisistä | ios_base::binary Tiedoston käsittely binäärimuotoisena.

Jos kääntäjäympäristö ei tue ios_base-luokkaa, käytä vanhempaa ios-luokkaa. 37.1.2 Binääritiedoston avaus kirjoittamista varten Binääritiedosto voidaan avata pelkästään kirjoittamista varten tai kirjoittamista ja lukemista varten. Jos tiedosto avataan pelkästään kirjoittamista varten, voidaan tiedosto-olio luoda ofstream-luokkaan. Jos tiedostoa halutaan myös lukea, voidaan olio luoda fstream-luokkaan.

ofstream Tiedosto (Ulkoinen_nimi, ios_base::binary | Muut liput);

Kuva 37-3. Binääritiedoston avaus kirjoittamista varten. Tiedosto on tiedosto-olio, jota käytetään ohjelmassa tiedoston sisäisenä nimenä. Parametrina välitetään tiedoston Ulkoinen_nimi merkkijonona. Ofstream-luokkaan luotu tiedosto-olio avaa tiedoston automaattisesti ios_base::out-lipulla kirjoittamista varten. Myös ios_base::trunc-lippu on oletusarvoisesti päällä, ellei avauslipuksi ole välitetty ios_base::ate- tai ios_base::app-lippua.

Page 159: C++-KIELI - Oamkjjauhiai/opetus/olio/Olio-ohjelmointi-40.pdf · 2007. 1. 5. · C++-kieli Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved. 4 5.7.2 OSOITTIMET TIETUEESEEN.....33

C++-kieli

Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved.

158

#include <fstream>using namespace std ;

int main (){

ofstream Tulos (“Tulos.dat”, ios_base::binary | ios_base::app) ;…

}

Kuva 37-4. Tiedosto-olion luonti ja tiedoston avaus. main-ohjelmassa ohjelmassa on luotu tiedosto-olio Tulos. Tiedosto-olioon on liitetty fyysinen tiedosto Tulos.dat, joka on avattu binäärimuodossa kirjoittamista varten ja tuhoamatta sen aikaisempaa sisältöä.

ofstream Tiedosto ;Tiedosto.open (Ulkoinen_nimi, ios_base::binary | Muut liput) ;

Kuva 37-5. Tiedosto-olion luonti ja avaus erikseen. Ensimmäisellä rivillä on tiedosto-olion luonti. Toisella rivillä on tiedoston avaus open-metodilla. Parametrit vastaavat aiemmin selitettyjä parametreja.

#include <fstream>using namespace std ;

int main (){

ofstream Tulos ;Tulos.open(“Tulos.dat”, ios_base::binary | ios_base::app) ;…

}

Kuva 37-6. Tiedosto-olion luonti ja binääritiedoston avaus kirjoittamista varten. Binääritiedostoa käsittelevä olio voidaan luoda myös fstream-luokkaan. Tällöin on avausvaiheessa käytettävä ios_base::out-lippua tiedoston käsittelytavan ilmoittamiseksi.

#include <fstream>using namespace std ;

int main (){

fstream Tiedosto(“Tulos.dat”, ios_base::binary | ios_base::out) ;…

}

Kuva 37-7. Tiedosto-olion luonti fstream-luokkaan ja tiedoston avaus binäärimuotoisena kirjoittamista varten. Tiedoston avaus luo tiedoston uudelleen eli tuhoaa vanhan sisällön, jos sellainen oli olemassa. 37.1.3 Binääritiedoston avaus lukemista varten Binääritiedosto voidaan avata pelkästään lukemista varten tai kirjoittamista ja lukemista varten. Jos tiedosto avataan pelkästään lukemista varten, voidaan luoda tiedosto-olio ifstream.

ifstream Tiedosto (Ulkoinen_nimi, ios_base::binary | Muut liput) ;

Kuva 37-8. Binääritiedoston avaus lukemista varten.

Page 160: C++-KIELI - Oamkjjauhiai/opetus/olio/Olio-ohjelmointi-40.pdf · 2007. 1. 5. · C++-kieli Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved. 4 5.7.2 OSOITTIMET TIETUEESEEN.....33

C++-kieli

Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved.

159

#include <fstream>using namespace std ;

int main (){

ifstream Syotto(“Syotto.dat”, ios_base::binary) ;…

}

Kuva 37-9. Esimerkki tiedosto-olion luonti ja avaus binäärimuotoisena lukemista varten.

ifstream Tiedosto ;Tiedosto.open (Ulkoinen_nimi, ios_base::binary | Muut liput) ;

Kuva 37-10. Tiedosto-olion luonti ja avaus erikseen.

#include <fstream>using namespace std ;

int main (){

ifstream Syotto ;Syotto.open(“Syotto.dat”, ios_base::binary) ;…

}

Kuva 37-11. Esimerkki tiedosto-olion luonti ja avaus erikseen. Tiedosto-olio voidaan luoda myös fstream-luokkaan ja avata ios::base::in-lipun avulla. 37.1.4 Tiedoston avauksen onnistuminen Tiedoston avauksen jälkeen voidaan testata, onnistuiko tiedoston avaus.

if ( Tiedosto.is_open() ) …if ( Tiedosto.fail() ) …if ( Tiedosto.good() ) …

Kuva 37-12. Tiedoston avauksen onnistumisen testaus. Kaikkien edellisen kuvan ehtojen totuusarvo on tosi eli nollasta poikkeava, jos tiedoston avaus on onnistunut. Fail-metodia voidaan käyttää myös muiden tiedosto-operaatioiden yhteydessä, kun halutaan tarkistaa edellisen operaation onnistuminen. Vanhemmissa ympäristöissä riittää myös testi if (Tiedosto). fail- ja good-metodit tarkistavat ios_base-luokasta iostate-tietojäsenen sisällön. iostate sisältää päällä olevat tilabitit. fail tarkistaa seuraavat bitit: ios_base::failbit, ios_base::badbit, ios_base::eofbit. good-metodi palauttaa nollasta poikkeavan arvon, jos edellisiä bittejä ei ole asetettu päälle. Tilabitit ilmaisevat tiedostonkäsittelyssä tapahtuvat virheet.

#include <fstream>using namespace std ;

int main (){

ofstream Tulos ;Tulos.open(“Tulos.dat”, ios_base::binary | ios_base::app) ;

if ( ! Tulos.is_open() ){

cour << “\n Tiedoston avaus epäonnistui. “ ;

Page 161: C++-KIELI - Oamkjjauhiai/opetus/olio/Olio-ohjelmointi-40.pdf · 2007. 1. 5. · C++-kieli Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved. 4 5.7.2 OSOITTIMET TIETUEESEEN.....33

C++-kieli

Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved.

160

}…

}

Kuva 37-13. Tiedoston avauksen onnistumisen testaus. Testausehto on tosi, jos avaus epäonnistui. Huomaa negaatio-merkin käyttö testausehdossa. 37.1.5 Tiedoston sulkeminen close-metodilla Tiedosto suljetaan aina samalla tavalla riippumatta tiedosto-olion tyypistä. Tiedoston sulkeminen ei poista tiedosto-oliota. Samaan tiedosto-olioon voidaan myöhemmin liittää sama tai eri tiedosto open-metodilla. Tiedosto-olio katoaa, kun ohjelman suoritus päättyy.

Tiedosto.close() ;

Kuva 37-14. Tiedoston sulkeminen. 37.1.6 Binääritiedostoon kirjoittaminen write-metodilla Tietojen kirjoitus tiedostoon binäärimuotoisena tapahtuu writemetodilla. Kirjoitettaessa tiedoston on oltava avattu siten, että ios_base::out-lippu on päällä.

Tiedosto.write(Tieto, Tavujen lkm) ;

Kuva 37-15. Kirjoitus write-metodilla. Tiedostoon kirjoitettavan tiedon tyyppi voi olla mikä tahansa. write-metodin kutsussa Tieto on osoitin kirjoitettavaan tietoon. Osoittimen on oltava osoitin merkkijonoon eli parametrin tyypin on oltava char *. Jos kirjoitettava tieto ei ole merkkijono, on kirjoittamisen yhteydessä tehtävä tyyppimuunnos. write-metodin toinen parametri on kokonaisluku, joka ilmoittaa, kuinka monta tavua osoittimen kohdasta eteenpäin kirjoitetaan tiedostoon. Kirjoitettavien tavujen määrän selvittämisessä kannattaa käyttää sizeof-operaattoria. Sizeof-operaattori palauttaa oikean tavumäärän, vaikka varattujen tavujen määrä vaihtelisi järjestelmästä toiseen siirryttäessä.

int Luku1 = 1 ;int *Luku2 = new int ;*Luku2 = 2 ;ofstream Tdsto (“Tdsto.dat”, ios_base::binary) ;Tdsto.write ( (char *)&Luku1, sizeof(int) ) ;Tdsto.write ( (char *)Luku2, sizeof(int) ) ;

Kuva 37-16. Joitakin esimerkkejä. Jos tiedostoon on kirjoitettava kokonaisluku Luku1, on se muunnettava merkkijono-osoittimeksi. Ensin on siis selvitettävä Luku1-muuttujan osoite &Luku1, joka sitten muunnetaan tyyppimuunnoksella (char *) merkkijono-osoittimeksi. Luku2-osoittimen osoittamaa lukua tiedostoon kirjoitettaessa ei &-merkkiä tarvita, koska Luku2 on osoitin. Sen sijaan tyyppimuunnos tarvitaan, koska Luku2-osoittimen tyyppi on int * eikä char *. Seuraavassa esimerkissä ohjelma tallettaa kokonaislukutaulukossa olevat luvut binääritiedostoon.

Page 162: C++-KIELI - Oamkjjauhiai/opetus/olio/Olio-ohjelmointi-40.pdf · 2007. 1. 5. · C++-kieli Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved. 4 5.7.2 OSOITTIMET TIETUEESEEN.....33

C++-kieli

Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved.

161

#include <iostream>#include <fstream>using namespace std ;

int main (){

int Luvut [10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10} ;int ind ;int avausliput = ios_base::binary ;

ofstream tulos ("c:\\Luvut.dat", avausliput) ;if ( ! tulos.is_open() ){

cout << "Tiedostovirhe, talletusta ei tehdä" ;exit (-1) ;

}for (ind = 0; ind < 10; ind++){

tulos.write((char *)&Luvut[ind], sizeof(int)) ;}tulos.close() ;

return 0 ;}

Kuva 37-17. Kokonaislukujen kirjoittaminen binääritiedostoon. Ohjelman tuloksena syntyy binääritiedosto c:\Luvut.dat. Tiedoston sisältö ei ole selväkielisessä muodossa, joten sitä ei voi tutkia tulostamalla tai editorilla. Ohjelmassa on määritelty avausbittejä varten kokonaislukukenttä, johon on sijoitettu avausbitti ios_base::binary. Huomaa tiedoston ulkoisessa nimessä kaksi kenoviivaa C:\\Luvut.dat. Jos tiedoston avaus ei onnistu, ohjelma keskeyttää toimintansa exit-aliohjelmaa kutsumalla. Aliohjelmalle välitetään jokin kokonaisluku. Tämän kokonaisluvun ohjelma palauttaa ohjelmaa kutsuneelle ohjelmalle. writemetodin kutsussa kirjoitettava tieto on taulukon alkiossa Luvut[ind]. Koska write-metodissa parametrin tyypin on oltava osoitin merkkijonoon, on ensin selvitettävä luvun osoite &Luvut[ind], joka sitten muunnetaan oikeantyyppiseksi osoittimeksi (char *). Kirjoitettavien tavujen määrä on 2, koska int-tyyppinen tieto varaa neljä tavua (tai kaksi). Tämä on selvitetty sizeof-operaattorilla. Tiedostoon kirjoitettavan tiedon tyyppi voi olla mikä tahansa. Seuraavassa esimerkissä ohjelma kirjoittaa binääritiedostoon tiedoston nimen sisältävän merkkijonon ja kaksi PVM-tietuetta.

#include <iostream>using namespace std ;#include <fstream>#include "pvm.h"

int main (){

PVM alkuarvot = {1, 2, 99} ;PVM *pvm1 = new PVM (alkuarvot) ;int avausliput = ios_base::binary ;char nimi [15] = "c:\\pvm.dat" ;

ofstream tulos(nimi, avausliput) ;

if (tulos.is_open()){

tulos.write(nimi, sizeof nimi) ;tulos.write((char *)pvm1, sizeof(PVM)) ;tulos.write((char *)&alkuarvot, sizeof(PVM)) ;tulos.close() ;

}

return 0 ;}

Kuva 37-18. Merkkijonon ja tietueiden kirjoittaminen binääritiedostoon.

Page 163: C++-KIELI - Oamkjjauhiai/opetus/olio/Olio-ohjelmointi-40.pdf · 2007. 1. 5. · C++-kieli Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved. 4 5.7.2 OSOITTIMET TIETUEESEEN.....33

C++-kieli

Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved.

162

Ohjelman suorituksen tuloksena syntty binääritiedosto, johon tallettuvat tiedoston nimi ja kaksi päivämäärätietuetta. Ohjelmassa on kirjoitettu tiedostoon merkkijono (tulos.write(nimi, sizeof nimi);). Merkkijonon kirjoittamisen yhteydessä ei tyyppimuunnosta tarvita, koska merkkijonon nimi on suoraan osoitin merkkijonoon. Kirjoitettavien tavujen määrän selvittämisessä sizeof voidaan kirjoittaa ilman sulkeita, koska nimi ei ole tyyppi, vaan lauseke, josta sizeof laskee tavut. Ohjelma kirjoittaa tiedostoon päivämäärän pvm1-osoitinmuuttujan kautta (tulos.write((char*)pvm1, sizeof(PVM));). Pvm1-osoitinmuuttujan tyyppi on PVM *, se on siis muunnettava merkkijono-osoittimeksi. Ohjelma kirjoittaa tiedostoon alkuarvot-tiedoston sisällön (tulos.write((char*)&alkuarvot, sizeof(PVM));). 37.1.7 Binääritiedostosta lukeminen read-metodilla Tiedostojen lukeminen binäärimuotoisena tiedostosta tapahtuu read-metodilla. Luettaessa tiedoston on oltava avattu siten, että ios_base::in-lippu on päällä.

Tiedosto.read(Tieto, Tavujen määrä) ;

Kuva 37-19. Lukeminen read-metodilla. Luettava tieto sijoitetaan muuttujaan Tieto. Tieto-parametrin on oltava osoitin merkkijonoon eli parametrin tyypin on oltava char *. Jos luettava tieto ei ole merkkijono, on lukemisen yhteydessä tehtävä tyyppimuunnos. Tavujen määrä ilmoittaa tiedostosta luettavien tavujen lukumäärän. Tiedoston loppumisen testaaminen peek- ja eof-metodeilla Tiedoston loppumista voidaan testata peek- ja eof-metodeilla.

if ( Tiedosto.peek() == EOF ) …if ( Tiedosto.eof() ) …

Kuva 37-20. Tiedoston päättymisen testaus. peek-metodi palauttaa seuraavana lukemisvuorossa olevan merkin. Metodi ei kuitenkaan lue EOF-merkkiä. eof-metodi tutkii, onko tiedoston lopetusmerkki ohitettu tiedostossa. EOF on vakio, jota voidaan käyttää ohjelmassa sellaisenaan. Seuraavassa esimerkissä ohjelma lukee ja tulostaa aiemmassa esimerkissä talletetusta tiedostosta kokonaisluvut.

#include <iostream>using namespace std ;#include <fstream>

int main (){

int luku ;int avausliput = ios::binary ;

ifstream syotto("c:\\Luvut.dat", avausliput) ;if ( ! syotto.is_open() ){

cout<<"Tiedostoa ei ole olemassa, lukuja ei luettu" ;exit (-1) ;

}

while (syotto.peek() != EOF){

syotto.read( (char *)&luku, sizeof(int) ) ;cout << "\nLuettu: " << luku ;

}

Page 164: C++-KIELI - Oamkjjauhiai/opetus/olio/Olio-ohjelmointi-40.pdf · 2007. 1. 5. · C++-kieli Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved. 4 5.7.2 OSOITTIMET TIETUEESEEN.....33

C++-kieli

Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved.

163

syotto.close() ;

return 0 ;}

Kuva 37-21. Kokonaislukujen lukeminen binääritiedostosta.

Luettu: 1Luettu: 2Luettu: 3Luettu: 4Luettu: 5Luettu: 6Luettu: 7Luettu: 8Luettu: 9Luettu: 10

Kuva 37-22. Edellisen esimerkin tulostus. Ohjelmassa luodaan ifstream-tiedosto-olio. Ohjelma lukee ja tulostaa tiedostossa olevat luvut. Tiedostoa luetaan, kunnes seuraavaksi luettava merkki on tiedoston loppumerkki EOF. Seuraavassa esimerkissä ohjelma lukee ja tulostaa aiemmin tiedostoon talletetun merkkijonon ja kaksi päivämäärätietuetta.

#include <iostream>using namespace std ;

#include <fstream>#include <cstring>#include "pvm.h"

int main (){

PVM *pvm1 = new PVM ;PVM pvm2 ;char jono [15] ;int avausliput = ios_base::binary ;char nimi [15] = "c:\\pvm.dat" ;

ifstream syotto(nimi, avausliput) ;

if (!syotto){

cout << "Tiedostoa ei ole, lukua ei tehty" ;exit (-1) ;

}

syotto.read(jono, sizeof jono) ;cout << "Tiedot luettu tiedostosta: " << jono ;

syotto.read( (char *)pvm1, sizeof(PVM) ) ;cout << "\n1. pvm on: " << pvm1->pp << '/' << pvm1->kk ;

syotto.read( (char *)&pvm2, sizeof(PVM) ) ;cout << "\n2. pvm on: " << pvm2.pp << '/' << pvm2.kk ;

syotto.close() ;

return 0 ;}

Kuva 37-23. Merkkijonon ja päivämäärätietueiden lukeminen binääritiedostosta.

Page 165: C++-KIELI - Oamkjjauhiai/opetus/olio/Olio-ohjelmointi-40.pdf · 2007. 1. 5. · C++-kieli Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved. 4 5.7.2 OSOITTIMET TIETUEESEEN.....33

C++-kieli

Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved.

164

Tiedot luetaan tiedostosta: c:\\pvm.dat1. pvm on: 1 / 2 / 992. pvm on: 1 / 2 / 99

Kuva 37-24. Edellisen esimerkin tulostus. Ensimmäisessä read-operaatiossa ohjelma lukee tiedostoon ensimmäiseksi talletetun merkkijonon. Tyyppimuunnosta ei merkkijonolle tarvita. sizeof-operaattoria käytettäessä ei tarvita sulkeita, koska koko tarkistetaan muuttujan sisällöstä eikä tyypistä. Toisessa read-operaatiossa ohjelma lukee ensimmäisen tiedostoon talletetun päivämäärätietueen. Ohjelma lukee tietueen dynaamisesti varattuun tietueeseen pvm1. Kolmannessa read-operaatiossa ohjelma lukee toisen tiedostoon talletetun tietueen pvm2-tietueeseen. 37.2 Binääritiedoston hajakäsittely Hajakäsittelyssä tiedostossa olevia tietoja ei tarvitse käsitellä peräkkäin, vaan tietoja käsitellään tiedosto-osoittimen osoittamasta kohdasta alkaen eteenpäin. Hajakäsittelyssä tiedosto-osoitinta voidaan siirtää haluttuun paikkaan. C- ja C++-kielissä hajakäsittely perustuu suoraan tiedon fyysiseen sijaintikohtaan tiedostossa. Kieli ei sisällä valmiita mekanismeja fyysisen sijaintikohdan laskentaan minkään loogisen avaintiedon, esim. asiakasnumeron, perusteella.Hajakäsittely mahdollistaa olemassaolevien tiedostojen selailun ja muutoksen. Lisäys sen sijaan tapahtuu aina tiedoston loppuun ellei olemassaolevia tietoja haluta tuhota. Hajakäsittelyssä tiedostoa voidaan lukea ja tiedostoon voidaan kirjoittaa samassa ohjelmassa. Jos käsittely on kaksisuuntaista, on tiedosto-olio luotava fstream-luokkaan ja avattava avausbiteillä ios_base:in ja ios_base::out. Jos käsittely on yksisuuntaista, voidaan tiedosto-olio luoda joko ifstream- tai ofstream-luokkaan.

fstream tdsto (Tiedosto, ios_base::binary | ios_base::in | ios_base::out) ;

Kuva 37-25. Tiedosto-olion luonti fstream-luokkaan. Tiedosto-osoittimen siirtäminen tapahtuu seekg- tai seekp-metodeilla. seekg-metodia käytetään tiedoston lukemisen yhteydessä ja seekp-metodia tiedostoon kirjoittamisen yhteydessä. Kun tiedosto-olio on luotu fstream-luokkaan, voidaan käyttää kumpaa tahansa metodia. Tiedosto-osoittimen sijainti on mahdollista selvittää tellg- ja tellp-metodeilla. Jos tiedosto on luotu fstream-luokkaan, tuottavat metodit saman tuloksen. Metodit käyttävät eri osoittimia, jos tiedosto-oliot on luotu ifstream- ja ofstream-luokkiin.

tdsto.seekg(Sijainti) ;tdsto.seekg(Siirtymä, Paikka) ;

Kuva 37-26. Tiedosto-osoittimen siirto seekp- ja seekg-metodilla.

seekg- ja seekp-metodeita voidaan käyttää kahdella tavalla. Ensimmäisellä rivillä olevassa syntaksissa parametrina ilmoitetaan tiedosto-osoittimen tarkka uusi Sijainti. Ensimmäisellä rivillä olevaa muotoa voidaan käyttää myös tiedostoille, jotka eivät ole binäärimuotoisia. Toisella rivillä olevaa syntaksia käytetään, kun tiedosto-osoitinta halutaan siirtää eteen- tai taaksepäin tietystä paikasta binääritiedostossa. Siirtymä ilmoittaa montako tavua tiedosto-osoitin siirtyy eteenpäin tai taaksepäin. Paikka voi olla tiedosto-osoittimen aktiivinen paikka tietyllä hetkellä (ios_base::cur), tiedoston alku (ios_base::beg) tai tiedoston loppu (ios_base::end).

tdsto.seekg(0) ; // Tiedoston alku.tdsto.seekg(0, ios_base::end) ; // Tiedoston alku.tdsto.seekg(10, ios_base::cur) ; // 10 tavua eteenpäin.tdsto.seekg(-10, ios_base::cur) ; // 10 tavua taaksepäin.

Kuva 37-27. Joitakin kutsuesimerkkejä.

Page 166: C++-KIELI - Oamkjjauhiai/opetus/olio/Olio-ohjelmointi-40.pdf · 2007. 1. 5. · C++-kieli Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved. 4 5.7.2 OSOITTIMET TIETUEESEEN.....33

C++-kieli

Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved.

165

Kahdessa viimeisessä esimerkissä tiedosto-osoitinta on siirretty nykyisestä sijainnista laskien eteenpäin tai taaksepäin. Siirto voidaan tehdä myös yhtä parametria käyttäen, jos tiedosto-osoittimen aktiivinen paikka on tutkittu tellg-metodilla:

tdsto.seekg(tdsto.tellg() + 10) ;tdsto.seekg(tdsto.tellg() - 10) ;

Kun ohjelma käsittelee tiedostoa hajakäsittelynä, on mahdollista, että tiedostoa selattaessa tiedoston loppumerkki tulee ohitetuksi. Peräkkäiskäsittelyssä tämä yleensä merkitsee sitä, että tiedosto on käsitelty loppuun ja se voidaan sulkea. Hajakäsittelyssä tiedoston loppuminen saattaa olla merkkinä siitä, että on muutettava tiedoston käsittelysuuntaa. Kun tiedoston loppumerkki on luettu, tulee ios_base::eofbit-bitti asetetuksi päälle. Se alustuu uudelleen tiedoston avauksen yhteydessä tai, jos se otetaan pois päältä clear-metodin avulla. Tällä metodilla voidaan ottaa pois päältä myös failbit ja badbit.

tdsto.clear() ;

Kuva 37-28. Tiedoston virhebittien ottaminen pois päältä. Seuraavan esimerkin ohjelman avulla käyttäjä voi lisätä uusia XY-tietueita ja selata tietueita eteen- ja taaksepäin. XY-tietue sisältää pisteen x- ja y-arvot.

#include <iostream>using namespace std ;

#include <fstream>#include <cctype>

struct XY{

int x ;int y ;

};

int KysyValinta (){

int vastaus ;

cout << "VALIKKO" << endl ;cout << "1 Tiedoston luonti" << endl ;cout << "2 Tietojen syöttö tiedostoon" << endl ;cout << "3 Tietojen selaus alusta loppuun" << endl ;cout << "4 Tietojen selaus lopusta alkuun" << endl ;cout << "0 Lopetus" ;cin >> vastaus ;

return vastaus ;}

int main (){

XY piste = {0, 0} ;fstream tdsto ;int valinta ;tdsto.open("d:\\tdsto.dat", ios::in|ios::out|ios::binary) ;tdsto.seekg(0) ;streampos alku = tdsto.tellg() ;valinta = KysyValinta() ;

while (valinta){

switch(valinta){case 1 :

tdsto.open("d:\\tdsto.dat", ios::out|ios::binary) ;

Page 167: C++-KIELI - Oamkjjauhiai/opetus/olio/Olio-ohjelmointi-40.pdf · 2007. 1. 5. · C++-kieli Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved. 4 5.7.2 OSOITTIMET TIETUEESEEN.....33

C++-kieli

Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved.

166

tdsto.close() ;tdsto.open("d:\\tdsto.dat", ios::in|ios::out|ios::binary) ;alku = tdsto.tellg() ;break ;

case 2:if (!tdsto.is_open()){

cout << "Luo tiedosto ensin" << endl ;break ;

}tdsto.clear() ;tdsto.seekp(0, ios_base::end) ;cout << "Syötä uusia tietoja (n n) lopetus X: " ;

while (cin >> piste.x >> piste.y){

tdsto.write((char *)&piste, sizeof piste) ;}cin.clear() ;while (!isspace(cin.get())) ;break ;

case 3:if (!tdsto.is_open()){

cout << "Luo tiedosto ensin" << endl ;}tdsto.clear() ;tdsto.seekg(0) ;cout << "Sisältö alusta: " << endl ;while (tdsto.read((char *)&piste, sizeof piste) && !tdsto.eof()){

cout << piste.x << ", " << piste.y << endl ;}break ;

case 4:cout << "selataan taaksepäin" << endl ;tdsto.clear() ;tdsto.seekg(-(1 * sizeof piste), ios_base::end) ;while (!tdsto.tellg() == alku){

tdsto.read((char *)&piste, sizeof piste) ;cout << piste.x << ", " << piste.y << endl ;tdsto.seekg(-(2 * sizeof piste), ios_base::cur) ;

}tdsto.read((char *)&piste, sizeof piste) ;cout << piste.x << ", " << piste.y << endl ;break ;

}valinta = KysyValinta () ;

}tdsto.close() ;

return 0 ;}

Kuva 37-29. Esimerkki XY-tietueiden käsittely hajakäsittelynä. Aluksi on määritelty XY-tietuetyyppi. Case 1 rakenteessa on toteutettu tiedoston luonti. Binääritiedosto tulee avata ios_base::out-avaustapaa käyttäen, jolloin tiedosto tulee luoduksi. Luonnin jälkeen tiedosto voidaan avata sekä ios_base::in että ios_base::out-avaustapaa käyttäen. Tiedoston avauksen jälkeen tiedoston alkukohta otetaan talteen, jotta tiedostoa voidaan tarvittaessa selata lopusta alkuun. Case 2 rakenteessa on toteutettu tietojen syöttö tiedostoon. Tiedoston tilakoodit on alustettu tässä (clear). seekp-metodilla on tiedosto-osoitin siirretty tiedoston loppuun. Toistorakenteessa on luettu tietueen tietoja. Lukeminen ja while loppuu, kun käyttäjä syöttää jonkin muun kuin numeron. Lopuksi lopetusmerkit ohitetaan(while (!isspace(cin.get())) ;). Case 3 rakenteessa on toteutettu tietojen selaus alusta loppuun. Case 4 rakenteessa on toteutettu tietojen selaus lopusta alkuun. while-rakenteessa pyöritään niin kauan kuin ollaan tiedoston alussa. while-rakenteen jälkeen on tiedoston ensimmäinen tietue luettu.

Page 168: C++-KIELI - Oamkjjauhiai/opetus/olio/Olio-ohjelmointi-40.pdf · 2007. 1. 5. · C++-kieli Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved. 4 5.7.2 OSOITTIMET TIETUEESEEN.....33

C++-kieli

Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved.

167

37.3 Tekstitiedostojen käsittely Tekstimuotoista tietoa aisältävät tiedostot ovat ASCII-tiedostoja. Tälläisen tiedoston sisältöä on helppo tutkia editor-ohjelmalla tai vaikkapa TYPE-komennolla DOS-käyttöjärjestelmässä. Tiedot voidaan tallettaa tekstimuotoisena, jos ne halutaan esim. tulostaa ohjelman ajon jälkeen. Tekstimuotoisen tiedon käsittelyssä saattaa tulla reaalilukujen käsittelyssä pyöristysvirheitä, koska talletuksessa tapahtuu tyyppimuunnos tekstimuotoon.Tekstimuotoisen tiedoston avaus tapahtuu ilman ios_base::binary-avausbittiä. Muuten avaus vastaa aiemmin esitettyä syntaksia. Tiedoston lukemisessa ja kirjoittamisessa voidaan käyttää samoja metodeita kuin näytön käsittelyssä. Seuraava esimerkkiohjelma tulostaa käyttäjän syöttämät merkit suoraan tiedostoon. Ohjelman suoritus päättyy, kun käyttäjä syöttää näppäimistöltä tiedoston loppumerkkiä vastaavan merkin ctrl-z vastaa EOF-MERKKIÄ (End-of-file).

#include <iostream.h>#include <fstream.h>

int main (){

char merkki ;

ofstream Tdsto ("Teksti.txt");cout << "Kirjoita tekstiä, kun haluat lopettaa paina CTRL-Z \n" ;cin.get (merkki);

while (merkki != EOF){

Tdsto.put (merkki) ;cin.get (merkki) ;

}

Tdsto.close () ;

return 0 ;}

Tulos: Kirjoita tekstiä, kun haluat lopettaa paina CTRL-ZTämä teksti tallettuu tiedostoon Teksti.txt

Kuva 37-30. Esimerkki syotettyjen merkkien kirjoittaminen tekstitiedostoon. Kun tiedoston avauksen yhteydessä (ofstream Tdsto("Teksti.txt");) ei esiinny avausbittiä iso_base::binary, avautuu tiedosto tekstimuotoisena. Ohjelma lukee get-metodilla käyttäjän kirjoittamaa syötettä merkki kerrallaan. Ohjelma tallettaa kunkin merkin put-metodilla tiedostoon. Tiedoston sisältö on tutkittavissa selväkielisessä muodossa. Seuraavassa esimerkissä on muunnosohjelma, joka muuntaa aiemmin talletetusta binääritiedostosta Kuukausi-tietueiden tiedot tekstimuotoiseen tekstitiedostoon. Tiedoston alkuun ohjelma tulostaa otsikoksi vakiotekstin KUUKAUDET. Sen jälkeen tiedostoon tulee tekstimuotoisena kuukauden numero välilyönnillä erotettuna kuukauden nimestä. Kuukaudet erotellaan toisistaan rivinvaihdolla.

#include <iostream>using namespace std ;#include <fstream>

struct Kuukausi{

int nro ;char nimi [15] ;

};

Page 169: C++-KIELI - Oamkjjauhiai/opetus/olio/Olio-ohjelmointi-40.pdf · 2007. 1. 5. · C++-kieli Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved. 4 5.7.2 OSOITTIMET TIETUEESEEN.....33

C++-kieli

Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved.

168

int main (){

Kuukausi tietue ;ifstream syotto ("kk.dat", ios_base::binary) ;

if (syotto.is_open()){

ofstream tulos ("kk.txt") ;tulos << "KUUKAUDET \n" ;syotto.read((char *)&tietue, sizeof(Kuukausi)) ; // Luku

while (!syotto.eof()){

tulos << tietue.nro << ' ' << tietue.nimi << '\n' ; // Kirjoitussyotto.read((char *)&tietue, sizeof(Kuukausi)) ; // Luku

}

tulos.close() ;syotto.close() ;

}

return 0 ;}

Tulostiedoston sisältö: KUUKAUDET1 Tammikuu2 Helmikuu3 Maaliskuu4 Huhtikuu

Kuva 37-31. Esimerkki tietojen muunnos binäärimuodosta tekstimuotoon. Ohjelma tulostaa tiedot tiedostoon, jonka sisältö on luettavissa selväkielisessä muodossa. Ohjelma käsittelee kahta tiedostoa, syöttötiedostoa binäärimuodossa ja tulostiedostoa tekstimuodossa. Ohjelma voi lukea sijoittamatta niitä mihinkään muuttujaan. Tätä tarkoitusta varten on ignore-metodi.

Tdsto.ignore (Lkm, Lopetusmerkki);

Kuva 37-32. Tietojen muunnos binäärimuodosta tekstimuotoon. Lkm ilmoittaa kuinka monta merkkiä tiedostosta ohitetaan sijoittamatta mihinkään muuttujaan. Ohittaminen lopetetaan viimeistään Lopetusmerkkiin. ignore lukee myös lopetusmerkin. Seuraava ohjelma lukee edellisen ohjelman tallettanasta tiedostosta kuukausien numerot ja nimet. Tiedoston alussa oleva otsikko ohitetaan sijoittamatta sitä muuttujaan. Ohjelma lukee tiedot getline-metodilla. Myös kuukauden numero on luettu ko. metodilla apu-merkkijonoon, josta sitten on poimittu sscanf-metodilla numero oikeaan muuttujaan.

#include <iostream>using namespace std ;#include <fstream>#include <cstdio>

struct Kuukausi{

int nro ;char nimi [15] ;

};

int main (){

Kuukausi tietue ;char apu [80] ;

Page 170: C++-KIELI - Oamkjjauhiai/opetus/olio/Olio-ohjelmointi-40.pdf · 2007. 1. 5. · C++-kieli Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved. 4 5.7.2 OSOITTIMET TIETUEESEEN.....33

C++-kieli

Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved.

169

ifstream syotto ("kk.txt") ;if (syotto.is_open()){

syotto.ignore(9, '\n') ;

while (syotto.peek()!= EOF){

syotto.getline(apu, 80, ' ') ;sscanf (apu, "%i", &tietue.nro) ;syotto.getline (tietue.nimi, 80, '\n') ;cout << "\n" << tietue.nro << " " << tietue.nimi ;

}}syotto.close() ;

return 0 ;}

Kuva 37-33. Esimerkki tietojen lukeminen tekstitiedostosta.

1 Tammikuu2 Helmikuu3 Maaliskuu4 Huhtikuu

Kuva 37-34. Edellisen esimerkin tulostus. Tietojen lukemisen on tapahduttava samassa järjestyksessä kuin tallettaminen. Lukemisen yhteydessä on siis tunnettava talletusmuoto tarkoin välimerkkeineen.

Page 171: C++-KIELI - Oamkjjauhiai/opetus/olio/Olio-ohjelmointi-40.pdf · 2007. 1. 5. · C++-kieli Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved. 4 5.7.2 OSOITTIMET TIETUEESEEN.....33

C++-kieli

Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved.

170

38. NIMIAVARUUS (Namespace) Nimiavaruus määrittelee uuden esittelyalueen tunnuksille. Varattu sana namespace mahdollistaa rakennettavan ohjelmiston jakamisen osiin siten, että osat on toteutettu eri lähdetekstitiedostoihin ja siten, että eri lähdetekstitiedostoissa voi esiintyä samannimisiä globaaleita tunnuksia. Nimiavaruus siis ryhmittelee globaaleita tunnuksia. C-kieli ei tunne nimiavaruus-käsitettä. Nimiavaruus luokitellaan C++-kielen uusiin piirteisiin. Se on ollut standardiehdotuksessa mukana kuitenkin jo ennen vuotta 1994. Piirre ei välttämättä ole tuettu täydellisesti kaikissa ohjelmakehitysympäristöissä. C++-kielessä on yksi globaali nimiavaruus, jossa käytettävien tunnusten tulee olla yksilöllisiä. Suurten järjestelmien toteuttamisessa tunnusten samoista nimistä johtuva nimikonflikti voidaan poistaa nimiavaruuden määrittelyllä. Nimiavaruus määrittelee uuden esittelyalueen. Kun ohjelmasta joudutaan toteuttamaan osajärjestelmiä, joissa esiintyy samoja tunnusten nimiä, voidaan kullekin osajärjestelmälle määritellä yksilöllinen nimiavaruus ja esitellä osajärjestelmän tunnuksen ko. nimiavaruudessa. Samoista tunnusten nimistä tulee aina yksilöllisiä kun nimen edessä esiintyy yksilöllinen osajärjestelmän nimiavaruuden nimi. Nimiavaruudet voidaan ryhmitellä esim. seuraavasti:

• Paikallinen nimiavaruus, tunnukset tunnistetaan suoraan nimellä esim. Luku. • Globaali nimiavaruus

� Nimetön nimiavaruus: Käännösyksikön sisäinen globaali nimiavaruus, tunnukset tunnistetaan suoraan nimellä tai :: operaattorilla, esim. ::Luku.

� Nimetty nimiavaruus: Voidaan ottaa käyttöön eri käännösyksiköihin, tunnukset tunnistetaan nimiavaruuden nimellä esim. Avaruus::Luku tai suoraan nimellä liittämällä nimiavaruus paikalliseen nimiavaruuteen.

38.1 Nimiavaruuden määrittely

namespace Tunnus { Nimiavaruuden runko }

Kuva 38-1. Nimiavaruuden määritely. Tunnus on nimiavaruudesta käytettävä nimi. Nimiavaruuden tunnus on oltava yksilöllinen ja sen on oltava näkyvä kaikissa käännösyksikön osissa, joissa nimiavaruuden elementteihin halutaan viitata. Nimiavaruuden runko sisältää nimiavaruuden elementtien eli kaikkien sellaisten globaaleiden tunnusten määrittelyt, jotka kuuluvat määriteltävään nimiavaruuteen. Nimiavaruus tulee määritellä globaalilla alueella. Sitä ei voi määritellä paikalliseksi esim. main-ohjelman sisällä. Nimiavaruuden määrittely voi sijaita otsikkotiedostossa, jolloin käyttö helpottuu eri käännösyksiköiden välillä. Tunnukset voivat olla esim. muuttujia, tietotyyppejä, aliohjelmia. Aliohjelmia ei ole pakko toteuttaa nimiavaruuden rungossa, pelkkä esittely riittää. Jos toteutus erotetaan esittelystä, on toteutuksessa oltava aliohjelman nimen edessä nimiavaruuden nimi tyyliin: Nimiavaruus::Aliohjelma. Seuraavat Järjestelmä1-nimiavaruuden määrittelyt ovat siis identtisiä.

namespace Järjestelmä1{

void Ali () {}}

namespace Järjestelmä1{

void Ali () ;}

Page 172: C++-KIELI - Oamkjjauhiai/opetus/olio/Olio-ohjelmointi-40.pdf · 2007. 1. 5. · C++-kieli Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved. 4 5.7.2 OSOITTIMET TIETUEESEEN.....33

C++-kieli

Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved.

171

void Järjestelmä1::Ali(){}

Kuva 38-2. Toteutus esittelyssä ja toteutus erotettu esittelystä. Nimiavaruutta voidaan täydentää kirjoittamalla nimiavaruuden määrittely uudelleen ja sen sisään nimiavaruuteen lisättävät tunnukset. Samalla nimiavaruuden tunnuksella esiintyvät määrittelyt täydentävät (Eivät siis korvaa.) toisiaan. Nimiavaruudet voivat olla sisäkkäisiä. Nimiavaruuden tunnukseen voidaan viitata myös aliasnimellä. Tästä on hyötyä silloin kun nimiavaruuden tunnus on hyvin pitkä.

namespace Tunnus1{

Nimiavaruuden runkonamespace Tunnus2 { Nimiavaruuden runko }

}

Kuva 38-3. Sisäkkäisten nimiavaruuksien määrittely.

namespace Tunnus1 { Nimiavaruuden runko }namespace Aliasnimi = Tunnus1 ;

Kuva 38-4. Aliasnimen määrittely nimiavaruudelle. Tunnus1 on alkuperäinen nimiavaruuden nimi. Aliasnimi on tavallisesti lyhyempi nimi, jolla halutaan viitata nimiavaruuteen Tunnus1. Nimiavaruus voi olla myös nimetön. Kaikki saman käännösyksikön nimettömät nimiavaruudet jakavat saman nimiavaruuden. Nimettömän nimiavaruuden tunnukset ovat näkyviä vain siinä tiedostossa, jossa nimiavaruus on määritelty. Tämä on vaihtoehtoinen tapa toteuttaa static-esittely ilman varattua sanaa static.

namespace { Nimiavaruuden runko }

Kuva 38-5. Nimettömän nimiavaruuden määrittely. Nimettömän nimiavaruuden rungossa määritelty tunnus ei ole ulkoinen ja sitä voi käyttää vain ko. käännösyksikössä. Tunnus ei näy muihin käännösyksiköihin. Tilanne on sama kuin, että tunnus olisi määritelty ei-julkiseksi varatulla sanalla static. 38.2 Nimiavaruuden käyttöönotto Tietyn nimiavaruuden käyttöönotto tapahtuu varatulla sanalla using. Nimiavaruuden elementit voidaan ottaa käyttöön kolmella eri tavalla:

• Nimeämällä elementti ja sen nimiavaruus, • Valitsemalla tietty tunnus tietystä nimiavaruudesta using-esittelyllä tai • Ottamalla koko nimiavaruus käyttöön oletusnimiavaruudeksi using-ohjaimella.

Jos käytössä on useita nimiavaruuksia, joissa on samanniminen tunnus, voidaan tunnuksen nimeen viitata yksilöimällä nimiavaruus tunnuksen nimen yhteydessä.

Nimiavaruus::Tunnus

Kuva 38-6. Nimiavaruuden tunnukseen viittaus eksplisiittisesti.

Page 173: C++-KIELI - Oamkjjauhiai/opetus/olio/Olio-ohjelmointi-40.pdf · 2007. 1. 5. · C++-kieli Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved. 4 5.7.2 OSOITTIMET TIETUEESEEN.....33

C++-kieli

Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved.

172

using Nimiavaruus::Tunnus ;

Kuva 38-7. Tunnuksen liittäminen paikalliseen nimiavaruuteen. Kun edellä olevan esittelyn jälkeen using-esittelyn sisältävässä lohkossa käytetään Tunnus-nimeä ilman nimiavaruuden nimeä, tarkoittaa viittaus aina using-esittelyssä olevaa nimiavaruuden ko. tunnusta. Esittely lisää tunnuksen paikalliseen nimiavaruuteen. Paikallisesti voi olla ainoastaan yksi samanniminen muuttuja. Kääntäjä antaa siksi virheilmoituksen, jos nimiavaruuden tunnus on liitetty paikalliseen nimiavaruuteen ja sen jälkeen samassa käännösyksikössä on määritelty paikallisesti vastaavanniminen tunnus. Tunnus on paikallisessa nimiavaruudessa esittelyn sisältävän lohkon loppuun asti. Varattua sanaa using ei voida käyttää luokan sisällä ohjaimena. Sen sijaan esittelyssä se voi esiintyä luokan sisälläkin. Oletetaan, että Järjestelmä1-nimiavaruudessa olisi määritelty tunnus.

int main (){

using Jarjestelma1::Luku ; // Nimiavaruuden tunnus paikalliseen nimiavaruuteen.int Luku ; // Virhe, Paikallisessa nimiavaruudessa on jo Luku.…

}

Kuva 38-8. Esimerkki mahdollisesta virheestä.

using namespace Nimiavaruus ;

Kuva 38-9. Oletusnimiavaruuden valinta. Edellä oleva merkintä valitsee käyttöön oletusarvoisesti kaikki nimiavaruuden Nimiavaruus tunnukset. Kun nimiavaruuden nimeämisen jälkeen lähdetekstissä esiintyy viittaus tunnukseen (Ilman nimiavaruuden nimeä.) ja ko. tunnus löytyy nimetystä nimiavaruudesta, tarkoittaa viittaus valitun nimiavaruuden tunnusta. Viittaukset tiettyyn nimiavaruuteen ovat voimassa sen lohkon loppuun, jossa nimiavaruus on valittu käyttöön. Oletusnimiavaruuden valinta ei tuo nimiavaruuden tunnuksia paikalliseen nimiavaruuteen vaan globaaliin (nimettyyn) nimiavaruuteen. Paikallisesti siis voidaan määritellä samannimisiä tunnuksia kuin oletusnimiavaruudessa on. Tällöin paikallinen määrittely piilottaa oletusnimiavaruuden määrittelyn. Oletetaan, että Järjestelmä1-nimiavaruudessa olisi määritelty tunnus.

int main (){

using namespace Jarjestelma1 ;Luku = 2 ; // Nimiavaruuden Jarjestelma1 tunnus.int Luku ; // Paikallinen peittävä tunnus.cout << Jarjestelma1::Luku ; // Nimiavaruuden tunnus.cout << Luku ; // Paikallinen tunnus.…

}

Kuva 38-10. Esimerkki mahdollisesta virheestä. Using-määrettä käytettäessä ohjelmoijan on huolehdittava siitä, että ohjelmassa käytettävä tunnus viittaa yksiselitteisesti yhden nimiavaruuden tunnukseen. Oletusnimiavaruuden valinnan jälkeen on mahdollista kuitenkin määritellä paikallinen tunnus sellaisella nimellä, joka esiintyy oletusnimiavaruudessa. Tällöin paikallinen tunnus peittää nimiavaruudessa esiintyvän nimen. Kääntäjä ei anna peittämisestä virheilmoitusta tai varoitusta.

Page 174: C++-KIELI - Oamkjjauhiai/opetus/olio/Olio-ohjelmointi-40.pdf · 2007. 1. 5. · C++-kieli Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved. 4 5.7.2 OSOITTIMET TIETUEESEEN.....33

C++-kieli

Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved.

173

Esimerkki Esimerkki nimiavaruuden käytöstä. Tiedostoja LUOKKA.HPP ja FUNKTIO.CPP käytetään hyväksi nimiavaruuden määrittelyssä.

#include <iostream>using namespace std ;

#ifndef LUOKKAHPP#define LUOKKAHPP

int muuttuja ;

class Luokka{private:

int x ;public:

Luokka (int p_x) { x = p_x ; }void Nayta () { cout << "\nx on: " << x ; }

};

#endif

Kuva 38-11. Tiedosto LUOKKA.HPP.

#include <iostream>using namespace std ;

void Funktio (){

cout << "\n Osan 1 Funktio()" ;}

Kuva 38-12. Tiedosto FUNKTIO.CPP. Tiedosto sisältää Funktio-nimisen aliohjelman määrittelyn. Oletetaan, että ohjelmoija toteuttaa lähdetekstin NAMES.CPP. Ohjelmoija on käyttänyt toteutuksessa jo aiemmin toteutetuissa tiedostoissa esiintyviä tunnusten nimiä. Ohjelmoija haluaa käyttää hyväkseen myös aiemmin toteutettuja tiedostoja haluamatta muuttaa käyttämiään tunnusten nimiä. Seuraavassa lähdekoodissa on ongelma ratkaistu nimiavaruuksien avulla.

#include <iostream>using namespace std ;

namespace Osa1{#include "luokka.hpp"#include "funktio.cpp"}

namespace Osa2{

int muuttuja ;

void Funktio(){

cout << "\n Osan 2 Funktio()" ;}

}

Page 175: C++-KIELI - Oamkjjauhiai/opetus/olio/Olio-ohjelmointi-40.pdf · 2007. 1. 5. · C++-kieli Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved. 4 5.7.2 OSOITTIMET TIETUEESEEN.....33

C++-kieli

Copyrights © Markku Rahikainen 2000-2003. All Rights Reserved.

174

int main(){

cout << "\n VIITTAUKSET YKSILÖIMÄLLÄ NIMIAVARUUS:" ;Osa1::muuttuja = 1 ;Osa2::muuttuja = 2 ;Osa1::Luokka olio(3) ;olio.Nayta() ;Osa1::Funktio() ;

cout << "\n OLETUSNIMIAVARUUDEKSI OSA2" ;using namespace Osa2 ; // Osa2 on nyt oletuksena lohkon loppuun.Funktio() ;using Osa1::Funktio ; // using-määreellä otetaan tunnus Funktio käyttöönFunktio() ; // nimiavaruudesta Osa1.muuttuja = 5 ;cout << "\n Osan 1 muuttuja on: " << Osa1::muuttuja ;cout << "\n Osan 2 muuttuja on: " << Osa2::muuttuja ;cin.get() ;cin.get() ;

return 0 ;}

Kuva 38-13. Nimiavaruuden määrittely tiedostossa NAME.CPP.

VIITTAUKSET YKSILÖIMÄLLÄ NIMIAVARUUSx on: 3Osan 1 Funktio ()OLETUSNIMIAVARUUDEKSI OSA2Osan 2 Funktio ()Osan 1 Funktio ()Osan 1 muuttuja on: 1Osan 2 muuttuja on: 5

Kuva 38-14. Esimerkin tulostus.