Osa. Mitä ovat vakiot jäsenfunktiot Kuinka erotetaan luokan käyttöliittymä sen toteutuksesta



Samankaltaiset tiedostot
Osa III. Olioiden luominen vapaalle muistialueelle

Osa. Johdanto C++ - kieleen. Oppitunnit 6 Perusluokat 7 Lisää luokista 8 Kehittynyt ohjelman kulku

Osa III. Edelliset kolme lukua ovat käsitelleet viittausten ja osoittimien käyttöä. Tämän luvun aiheita ovat:

11. oppitunti III. Viittaukset. Osa. Mikä on viittaus?

Osa. Listaus 2.1. HELLO.CPP esittelee C++ -ohjelman osat. 14: #include <iostream.h> 15: 16: int main() 17: {

14. oppitunti. Operaattorin ylikuormitus. Osa. Operaattorin ylikuormittaminen

815338A Ohjelmointikielten periaatteet Harjoitus 5 Vastaukset

21. oppitunti. Esikäsittelijä. Osa. Esikäsittelijä ja kääntäjä

Osoitin ja viittaus C++:ssa

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

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

Osa. Erikoisaiheet. Oppitunnit 20 Erikoisluokat ja -funktiot 21 Esikäsittelijä

15. oppitunti. Taulukot. Osa. Mikä on taulukko?

Pong-peli, vaihe Aliohjelman tekeminen. Muilla kielillä: English Suomi. Tämä on Pong-pelin tutoriaalin osa 3/7. Tämän vaiheen aikana

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

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

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

1. Omat operaatiot 1.1

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

Apuja ohjelmointiin» Yleisiä virheitä

12 Mallit (Templates)

Harjoitus Olkoon olemassa luokat Lintu ja Pelikaani seuraavasti:

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

1 Tehtävän kuvaus ja analysointi

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

Ohjelmoinnin jatkokurssi, kurssikoe

Ohjelmassa henkilön etunimi ja sukunimi luetaan kahteen muuttujaan seuraavasti:

Harjoitustyö: virtuaalikone

Ohjelmoinnin perusteet Y Python

ITKP102 Ohjelmointi 1 (6 op)

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

Luokat. Luokat ja olio-ohjelmointi

24. oppitunti VII. Poikkeukset ja virheiden käsittely. Osa

Osa. Mikä on linkitetty lista Kuinka linkitetty lista luodaan Kuinka toiminnallisuus kapseloidaan periytymisen kautta

HARJOITUKSIA ios-ohjelmointiin LIITTYEN

ITKP102 Ohjelmointi 1 (6 op)

15. Ohjelmoinnin tekniikkaa 15.1

Osa VII. Mitä mallit ovat ja kuinka niitä käytetään Miksi mallit tarjoavat paremman vaihtoehdon makroille Kuinka luokkamalleja luodaan

Tietueet. Tietueiden määrittely

815338A Ohjelmointikielten periaatteet Harjoitus 3 vastaukset

5. HelloWorld-ohjelma 5.1

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

AS C-ohjelmoinnin peruskurssi 2013: C-kieli käytännössä ja erot Pythoniin

5. HelloWorld-ohjelma 5.1

Luokka Murtoluku uudelleen. Kirjoitetaan luokka Murtoluku uudelleen niin, että murtolukujen sieventäminen on mahdollista.

IDL - proseduurit. ATK tähtitieteessä. IDL - proseduurit

15. Ohjelmoinnin tekniikkaa 15.1

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

ATK tähtitieteessä. Osa 3 - IDL proseduurit ja rakenteet. 18. syyskuuta 2014

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

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

Mallit standardi mallikirjasto parametroitu tyyppi

Ohjelmoinnin perusteet Y Python

C++ Ohjelmoijan käsikirja. Johdanto

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

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

JAVA on ohjelmointikieli, mikä on kieliopiltaan hyvin samankaltainen, jopa identtinen mm. C++

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

Työ tehdään itsenäisesti yhden hengen ryhmissä. Ideoita voi vaihtaa koodia ei.

Javan perusteita. Janne Käki

Oliosuunnitteluesimerkki: Yrityksen palkanlaskentajärjestelmä

Ohjelmointi 2. Jussi Pohjolainen. TAMK» Tieto- ja viestintäteknologia , Jussi Pohjolainen TAMPEREEN AMMATTIKORKEAKOULU

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

C-kielessä taulukko on joukko peräkkäisiä muistipaikkoja, jotka kaikki pystyvät tallettamaan samaa tyyppiä olevaa tietoa.

Sisältö. 22. Taulukot. Yleistä. Yleistä

13 Operaattoreiden ylimäärittelyjä

Muuttujien roolit Kiintoarvo cin >> r;

Kääntäjän virheilmoituksia

Ohjelmoinnin peruskurssi Y1

4. Lausekielinen ohjelmointi 4.1

9. Periytyminen Javassa 9.1

Racket ohjelmointia osa 1. Tiina Partanen Lielahden koulu 2014

Ohjelmointi 2 / 2010 Välikoe / 26.3

Ohjelmoinnin perusteet Y Python

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

Mikä yhteyssuhde on?

C-ohjelma. C-ohjelma. C-ohjelma. C-ohjelma. C-ohjelma. C-ohjelma. Operaatioiden suoritusjärjestys

Jypelin käyttöohjeet» Ruutukentän luominen

Ohjelmoinnin perusteet Y Python

Harjoitustyö 3 - Millosemeni

Sisältö. 2. Taulukot. Yleistä. Yleistä

812341A Olio-ohjelmointi Peruskäsitteet jatkoa

Pong-peli, vaihe Aliohjelmakutsu laskureita varten. 2. Laskurin luominen. Muilla kielillä: English Suomi

Tietorakenteet ja algoritmit

1. Kun käyttäjä antaa nollan, niin ei tulosteta enää tuloa 2. Hyväksy käyttäjältä luku vain joltain tietyltä väliltä (esim tai )

ITKP102 Ohjelmointi 1 (6 op)

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

Johdatus Ohjelmointiin

Olio-ohjelmointi Javalla

Osa. Toimintojen toteuttaminen ohjelmissa vaatii usein haarautumisia ja silmukoita. Tässä luvussa tutustummekin seuraaviin asioihin:

6. Harjoitusjakso II. Vinkkejä ja ohjeita

1. Olio-ohjelmointi 1.1

5.6. C-kielen perusteet, osa 6/8, Taulukko , pva, kuvat jma

Java-kielen perusteet

Alkuun HTML5 peliohjelmoinnissa

Jypelin käyttöohjeet» Miten voin liittää törmäyksiin tapahtumia?

Tehtävä 1. Tehtävä 2. Arvosteluperusteet Koherentti selitys Koherentti esimerkki

Harjoitus 3: Flash-komponenttiarkkitehtuuri ( )

Olio-ohjelmointi 2. välikoe HYV5SN

Datatähti alkukilpailu

Transkriptio:

Osa II 7. oppitunti Lisää luokista Aiemmassa luvussa opit luomaan uusia tietotyyppejä esittelemällä luokkia. Tässä luvussa opit hallitsemaan luokkia ja käyttämään kääntäjää auttamaan virheiden löytämisessä ja välttämisessä. Luvun aiheita ovat Mitä ovat vakiot jäsenfunktiot Kuinka erotetaan luokan käyttöliittymä sen toteutuksesta Vakiomuotoiset jäsenfunktiot Uusi käsite Jos esittelet jäsenfunktion vakiona, päätät samalla, ettei tuo jäsenfunktio muuta minkään luokan jäsenen arvoa. Vakiona esittely tapahtuu varatulla sanalla const, joka sijoitetaan sulkumerkkien jälkeen ennen puolipistettä. Tällainen funktio ei ota argumentteja ja palauttaa void-arvon. Se näyttää seuraavanlaiselta:

98 7. oppitunti void SomeFunction() const; Käyttöfunktiot esitellään usein vakioina const-lisämääreen avulla. Catluokalla on kaksi käyttöfunktiota: void SetAge(int anage); int getage(); SetAge() ei voi olla vakio, koska se muuttaa jäsenmuuttujaa itsage. Sen sijaan GetAge() voi ja sen pitäisi olla vakio, koska se ei muuta luokkaa lainkaan. Se vain palauttaa jäsenmuuttujan itsage nykyisen arvon. Siksi näiden funktioiden esittelyn tulisi olla seuraavanlainen: void SetAge(int anage); int GetAge() const; Jos funktio on esitelty vakiona ja toteutus yrittää muuttaa kohdetta (muuttamalla jäsenen arvoa), ilmoittaa kääntäjä virheestä. Jos kirjoitat esimerkiksi funktion GetAge() siten, että se laskee Cat-olion iän kysymisten määrän, antaisi kääntäjä virheilmoituksen. Se johtuu siitä, että tällöin Catoliota muutettaisiin metodia kutsuttaessa. Käytä const-avainsanaa aina kun se on mahdollista. Esittele jäsenfunktiot vakioina aina, kun niiden tarkoituksena ei ole muuttaa oliota. Tällöin kääntäjä auttaa virheiden löytämisessä, eikä virheitä tarvitse etsiä itse. On hyvä ohjelmointitapa esitellä niin monta metodia vakiona kuin mahdollista. Näin kääntäjä löytää hyvin virheet eikä virheitä tarvitse metsästää ajamalla ohjelmaa. Käyttöliittymä (rajapinta, esittely) ja toteutus (määrittely) Kuten olet oppinut, ovat asiakkaat sellaisia ohjelman osia, jotka luovat ja käyttävät luokan olioita. Voit ajatella luokan käyttöliittymän - luokan esittelyn - olevan ikään kuin sopimus noiden asiakkaiden kanssa. Sopimus kertoo, mitä tietoa on saatavilla ja kuinka luokka käyttäytyy. Esimerkiksi Cat-luokan kohdalla solmit sopimuksen, että jokaisella Catoliolla on jäsenmuuttuja itsage, joka voidaan alustaa muodostimessa SetAge()-käyttöfunktion avulla ja jonka arvo voidaan lukea GetAge()- funktiolla. Samalla lupaat, että jokainen Cat-olio osaa naukua funktiolla Meow().

Lisää luokista 99 Jos teet GetAge()-funktiosta vakiofunktion (kuten pitäisi tehdä), sopimus lupaa vielä, että GetAge() ei voi mitenkään muokata Cat-oliota. Miksi käyttää kääntäjää virheiden hakemisessa? Ohjelmoinnin karu totuus on se, ettei kukaan kirjoita täysin virheetöntä koodia. Ammattilaisen erottaa harrastelijasta - ei koodin virheettömyys - vaan se, että virheet löydetään ennen tuotteen jakelua, ei sen jälkeen. Kääntämisenaikaiset virheet ovat paljon parempia kuin ajonaikaiset virheet. Tämä johtuu siitä, että kääntämisenaikaiset virheet voidaan löytää paljon luotettavammin. Ohjelmaa on mahdollista ajaa useita kertoja ilman, että joudutaan tutkimaan jokainen koodipaikka. Sen sijaan ajonaikaisia virheitä on vaikea löytää. Kääntämisenaikaiset virheet löydetään kääntämisen yhteydessä, jolloin ne voidaan tunnistaa ja korjata. Tärkeimpiä ohjelman laatutavoitteita on taata, ettei ohjelmassa ole ajonaikaisia virheitä. Kääntämisen käyttäminen tähän on eräs yritys-ja-erehdys -menettelytapa, jolla pyritään löytämään virheet varhaisessa vaiheessa. Minne luokan esittelyt ja metodien määrittely sijoitetaan Jokaisella luokassa esitellyllä funktiolla tulee olla määrittelynsä. Määrittelyä kutsutaan myös funktion toteutukseksi. Kuten muillakin funktioilla, myös luokan metodeilla tulee määrittelyn sisältää funktion otsikko ja runko. Määrittelyn tulee olla tiedostossa, jonka kääntäjä löytää. Useimmat C++ - kääntäjät odottavat, että tiedoston tunnus on.c tai.cpp. Tässä kirjassa käytetään tunnusta.cpp, mutta tarkista oman kääntäjäsi toivoma tunnus. Monet kääntäjät olettavat, että C-loppuiset tiedostot ovat C-ohjelmia ja CPP-loppuiset taas C++ -ohjelmia. Voit käyttää jompaakumpaa tunnusta, mutta CPP-tunnuksen käyttäminen vähentää sekaannuksia. Sinun on lisättävä nuo.cpp-tiedostot projektiisi tai makefile-tiedostoosi. Lisäämistapa riippuu kääntäjästäsi. Jos käytät IDE-työkalua, käytä sellaista komentoa kuin "add files to project". Kaikki.CPP-tiedostot tulee lisätä projektiin, jotta se voidaan kääntää ja linkittää lopulliseksi suoritettavaksi tiedostoksi. Sijoita luokan esittelyt otsikkotiedostoihin Vaikka voitkin sijoittaa esittelyt samaan lähdekooditiedostoon, se ei ole hyvä ohjelmointimenettelytapa. Useimmat ohjelmoijat sijoittavat esittelyn niin sanottuun otsikkotiedostoon (header file) käyttäen samaa nimeä, mutta tunnusta.h,.hp tai.hpp. Tämä kirja käyttää tunnusta.hpp, mutta tarkista kääntäjäsi oletusarvo.

100 7. oppitunti Voit laittaa esimerkiksi Cat-luokan esittelyn tiedostoon nimeltä CAT.HPP ja luokan metodien määrittelyt tiedostoon nimeltä CAT.CPP. Sitten yhdistän otsikkotiedoston CPP-tiedostoon #include-säännöllä: #include Cat.hpp Rivi kertoo kääntäjälle, että sen tulee lukea tiedosto CAT.HPP kooditiedostoon aivan kuin olisin kirjoittanut sisällön sinne itse. Miksi sitten kannattaa erottaa tiedot eri tiedostoihin? Useimmin eivät luokan asiakkaat välitä toteutuksen yksityiskohdista. Otsikkotiedoston lukeminen kertoo niille kaiken tarvittavan ja ne voivat ohittaa toteutustiedostot. Luokan esittely kertoo kääntäjälle, mikä luokka on; millaista tietoa siihen voidaan tallentaa ja mitä funktioita se sisältää. Luokan esittelyä kutsutaan liittymäksi, koska se kertoo, kuinka luokan kanssa ollaan vuorovaikutuksessa. Tuo käyttöliittymä tallennetaan yleensä.hpptiedostoon eli otsikkotiedostoon. Funktion määrittely kertoo kääntäjälle, kuinka funktio toimii. Määrittelyä kutsutaan luokan metodin toteutukseksi ja se pidetään.cpp-tiedostossa. Vain luokan kirjoittaja tuntee toteutuksen yksityiskohdat. Luokan asiakkaat - ne ohjelman osat, jotka käyttävät luokkaa - eivät välitä tietää (eikä niiden tarvitse tietää), kuinka funktiot on toteutettu. Inline-toteutus Kääntäjää voidaan pyytää tekemään tavallisesta funktiosta inline-funktio ja sama voidaan toteuttaa myös metodien kohdalla. Esimerkiksi funktion GetWeight() inline-toteutus olisi seuraavanlainen: inline int Cat::GetWeight() { return itsweight; //palauttaa Weight-arvon } Voit sijoittaa myöskin funktion määrittelyn luokan esittelyyn, mikä tekee funktiosta automaattisesti inline-funktion: class Cat { public: int GetWeight() { return itsweight; } void SetWeight(int aweight); }; //inline Huomaa GetWeight()-funktion määrittelyn syntaksi. Inline-funktion runko alkaa heti luokan metodin esittelyn jälkeen eikä aaltosulkujen jälkeen ole

Lisää luokista 101 puolipistettä. Määrittely alkaa aloittavalla aaltosululla kuten normaalisti ja päättyy lopettavaan aaltosulkuun. Välilyönneillä ei ole merkitystä ja esittely olisi voitu kirjoittaa myös näin: class Cat { public: int GetWeight() { return itsweight; } //inline void SetWeight(int aweight); }; Listauksissa 7.1 ja 7.2 luodaan Cat-luokka uudelleen, mutta esittely sijoitetaan tiedostoon CAT.HPP ja funktioiden toteutus tiedostoon CAT.CPP. Listauksessa 7.1 muutetaan sekä käsittelyfunktiot että Meow() inlinetyyppisiksi. Listaus 7.1. Cat-luokan esittely tiedostossa CAT.HPP. 1: #include <iostream.h> 2: class Cat 3: { 4: public: 5: Cat (int initialage); 6: ~Cat(); 7: int GetAge() { return itsage;} // inline! 8: void SetAge (int age) { itsage = age;} // inline! 9: void Meow() { cout << "Meow.\n";} // inline! 10: private: 11: int itsage; 12: }; Listaus 7.2. Cat-luokan toteutus tiedostossa CAT.CPP. 1: // inline 2: // ja include 3: 4: include "cat.hpp" // Cat-esittely mukaan! 5: 6: 7: Cat::Cat(int initialage) // Muodostin 8: { 9: itsage = initialage; 10: } 11: 12: Cat::~Cat() 13: { 14: } 15: 16: // Luodaan Cat, asetetaan Age 17: // ja käytetään Meow-metodia 18: int main() 19: { 20: Cat Frisky(5);

102 7. oppitunti 21: Frisky.Meow(); 22: cout << "Frisky is a cat who is "; 23: cout << Frisky.GetAge() << "years old. \n"; 24: Frisky.Meow(); 25: Frisky.SetAge(7); 26: cout << "Now Frisky is "; 27: cout << Frisky.GetAge() << "years old.\n"; 28: return 0; 29: } Tulostus Meow. Frisky is a cat who is 5 years old. Meow. Now Frisky is 7 years old. Analyysi Listauksessa 7.1 esitellään rivillä 7 funktio GetAge() ja sen inline-toteutus on mukana. Riveillä 8 ja 9 on lisää inline-funktioita, mutta näiden funktioiden toimintaa ei ole muutettu aiemmista ulkoisista toteutuksista. Listauksen 7.2 rivillä 4 on lause #include "cat.hpp", joka tuo koodiin CAT.HPP-listauksen. Samalla lailla sisällytetään tiedostoon myös IOSTREAM.H, joka antaa käyttöön cout-olion. Luokat, joiden jäsentietoina on muita luokkia On aivan normaalia luoda monimutkaisia luokkia, joiden esittelyihin sijoitetaan yksinkertaisempia luokkia. Voimme esitellä esimerkiksi Wheelluokan, Motor-luokan, Transmission-luokan jne (pyörä, moottori, voimansiirto) ja yhdistää ne Car-luokkaan. Tällöin syntyy sisältymissuhde: autossa on moottori, pyörät ja voimansiirto. Ajattele toista esimerkkiä. Suorakaide koostuu viivoista. Viiva määritellään kahdella pisteellä. Piste määritellään koordinaatein x ja y. Listaus 7.3 sisältää kokonaisen Rectangle-luokan esittelyn sellaisena kuin se esiintyisi tiedostossa RECTANGLE.HPP. Koska suorakaide määritellään neljällä suoralla viivalla, jotka yhdistävät neljä pistettä, jotka pisteet esitetään koordinaatteina, esitellään ensin Point-luokka, joka sisältää kunkin pisteen x- ja y-koordinaatit. Listaus 7.4 sisältää molempien luokkien esittelyt. Listaus 7.3. Kokonaisen luokan esittely. 1: // Aloitetaan Rect.hpp 2: #include <iostream.h> 3: class Point // holds x,y coordinates 4: {

Lisää luokista 103 5: // ei muodostinta, käytetään oletusmuodostinta 6: public: 7: void SetX(int x) { itsx = x; } 8: void SetY(int y) { itsy = y; } 9: int GetX()const { return itsx;} 10: int GetY()const { return itsy;} 11: private: 12: int itsx; 13: int itsy; 14: }; // end of Point class declaration 15: 16: 17: class Rectangle 18: { 19: public: 20: Rectangle (int top, int left, int bottom, int right); 21: ~Rectangle () {} 22: 23: int GetTop() const { return itstop; } 24: int GetLeft() const { return itsleft; } 25: int GetBottom() const { return itsbottom; } 26: int GetRight() const { return itsright; } 27: 28: Point GetUpperLeft() const { return itsupperleft; } 29: Point GetLowerLeft() const { return itslowerleft; } 30: Point GetUpperRight() const { return itsupperright; } 31: Point GetLowerRight() const { return itslowerright; } 32: 33: void SetUpperLeft(Point Location) {itsupperleft = Location;} 34: void SetLowerLeft(Point Location) {itslowerleft = Location;} 35: void SetUpperRight(Point Location) {itsupperright = Location;} 36: void SetLowerRight(Point Location) {itslowerright = Location;} 37: 38: void SetTop(int top) { itstop = top; } 39: void SetLeft (int left) { itsleft = left; } 40: void SetBottom (int bottom) { itsbottom = bottom; } 41: void SetRight (int right) { itsright = right; } 42: 43: int GetArea() const; 44: 45: private: 46: Point itsupperleft; 47: Point itsupperright; 48: Point itslowerleft; 49: Point itslowerright; 50: int itstop; 51: int itsleft; 52: int itsbottom; 53: int itsright; 54: }; 55: // LOPPU Rect.hpp Listaus 7.4. RECT.CPP. 1: // Aloitetaan rect.cpp 2: #include "rect.hpp" 3: Rectangle::Rectangle(int top, int left, int bottom, int right) 4: { 5: itstop = top; 6: itsleft = left; 7: itsbottom = bottom;

104 7. oppitunti 8: itsright = right; 9: 10: itsupperleft.setx(left); 11: itsupperleft.sety(top); 12: 13: itsupperright.setx(right); 14: itsupperright.sety(top); 15: 16: itslowerleft.setx(left); 17: itslowerleft.sety(bottom); 18: 19: itslowerright.setx(right); 20: itslowerright.sety(bottom); 21: } 22: 23: 24: // lasketaan suorakaiteen ala hakemalla kulmat, 25: // lasketaan leveys ja korkeus ja kerrotaan 26: int Rectangle::GetArea() const 27: { 28: int Width = itsright - itsleft; 29: int Height = itstop - itsbottom; 30: return(width * Height); 31: } 32: 33: int main() 34: { 35: // alustetaan paikallinen Rectangle-muuttuja 36: Rectangle MyRectangle(100, 20, 50, 80); 37: 38: int Area = MyRectangle.GetArea(); 39: 40: cout << "Area: " << Area << "\n"; 41: cout << Upper Left X Coordinate: "; 42: cout << MyRectangle.GetUpperLeft().GetX(); 43: return 0; 44: } Tulostus Area: 3000 Upper Left X Coordinate: 20 Analyysi Listauksen 7.3 rivit 3-14 esittelevät luokan Point, joka sisältää pisteen x- ja y-koordinaatit. Tämä ohjelma ei hyödynnä Points-olioita paljoakaan. Kuitenkin muut piirtomenetelmät vaativat Points-olioita. Point-luokassa esitellään kaksi jäsenmuuttujaa, itsx ja itsy, riveillä 12 ja 13. Nämä muuttujat tallentavat koordinaattiarvot. Kun x-koordinaatti kasvaa, siirrytään koordinaatistossa oikealle. Kun y-koordinaatti kasvaa, siirrytään ylöspäin. Muut graafit voivat käyttää muunlaista systeemiä. Esimerkiksi joissakin ikkunointiohjelmissa kasvatetaan y-koordinaattia siirryttäessä ikkunassa alaspäin.

Lisää luokista 105 Point-luokka käyttää inline-tyyppisiä funktioita hakemaan tai asettamaan x- ja y-pisteitä. Points käyttää oletusmuodostinta ja tuhoajaa ja siksi niiden koordinaatit on asetettava ulkoisesti. Rivi 17 aloittaa Rectangle-luokan esittelyn. Se koostuu neljästä pisteestä, jotka edustavat suorakaiteen nurkkia. Rectangle-luokan muodostin (rivi 20) käyttää neljää kokonaislukua, top, left, bottom ja right. Nuo parametrit kopioidaan neljään jäsenmuuttujaan, jolloin toteutetaan neljä pistettä. Rectangle-luokassa on myös funktio nimeltä GetArea(), joka esitellään rivillä 43. Tämä funktio laskee alan riveillä 27-29 laskemalla ensin suorakaiteen leveyden ja korkeuden ja kertomalla nuo luvut keskenään. Vasemman ylänurkan x-koordinaatti saadaan UpperLeft-pisteen X-arvosta. Koska GetUpperLeft() on Rectangle-luokan metodi, se voi käsitellä suoraan Rectangle-luokan yksityistä tietoa mukaan lukien itsupperleft. Koska itsupperleft on Point ja Pointin itsx on yksityinen arvo, ei GetUpperLeft() voi käsitellä tätä tietoa suoraan. Pikemminkin sen täytyy käyttää julkista käsittelyfunktiota getx() saadakseen tuon arvon. Listauksen 7.4 rivi 32 on todellisen ohjelman rungon alku. Vasta rivillä 35 varataan muistia. Sitä ennen kerrotaan kääntäjälle, kuinka Point ja Rectangle toteutetaan. Rivillä 36 määritellään Rectangle viemällä sille top-, left-, bottom- ja rightarvot. Rivillä 38 määritellään paikallinen int-muuttuja, Area, johon tallennetaan suorakaiteen ala. Area alustetaan Rectangle-luokan GetArea()-funktion palauttamalla arvolla. Rectangle-luokan asiakas voisi luoda Rectangle-olion ja saada sen alan etsimättä koskaan GetArea()-funktion toteutusta. Tutkimalla otsikkotiedostoa ohjelmoija näkee, että GetArea() palauttaa kokonaisluvun, mutta Rectangle-luokan asiakkaan ei tarvitse huolehtia siitä, kuinka GetArea() toimii. Itse asiassa Rectangle-luokan kirjoittaja voisi muuttaa GetArea()-funktiota vaikuttamatta muutoksilla ohjelmiin, jotka käyttävät Rectangle-luokkaa.

106 7. oppitunti Yhteenveto Tässä luvussa opit lisää luokkien luomisesta. Opit luomaan vakioita jäsenfunktioita ja tuntemaan luokan metodien esittelyn ja toteutuksen erot. On hyvä ohjelmointitapa eristää luokan esittely omaan otsikkotiedostoonsa. Yleensä tuon tiedoston tunnuksena on.hpp. Luokan metodien toteutukset koodataan tiedostoon, jonka tunnus on.cpp. Kysymyksiä ja Vastauksia K Jos const-tyyppisen funktion käyttäminen luokan muuttamiseen aiheuttaa kääntäjän virheen, miksi en voisi jättää pois tuota const-sanaa virheiden välttämiseksi? V Jos jäsenfunktion ei pitäisi muuttaa luokkaa, voidaan const-avainsanalla estää typerien virheiden tekeminen. Jos vaikkapa GetAge()-funktion ei tulisi muuttaa luokan tietoja, mutta toteutuksessasi on kuitenkin seuraava lause: if (itsage = 100) cout << "Hey! You're 100 years old\n"; Aiheuttaisi const-avainsana virheen. Tarkoituksesi oli tietenkin testata, onko itsage yhtä suuri kuin 100, mutta sen sijaan aiheuttaa kirjoitusvirhe sijoitusoperaation ja sijoittaminen sotii const-avainsanaa vastaan. Nyt kääntäjä kuitenkin havaitsee virheen, jos olet käyttänyt const-avainsanaa. Juuri tuollaiset virheet ovat vaikeita havaita, koska silmä näkee usein sen, mitä odotetaan nähtävän. Lisäksi ohjelmaa voidaan ajaa, vaikka itsage on saanut erikoisen arvon, mikä taas voi aiheuttaa virheitä myöhemmin. K Onko C++ -ohjelmassa koskaan syytä käyttää tietue-rakennetta? V Monet C++ -ohjelmoijat varaavat struct-avainsanan sellaisten luokkien käyttöön, joissa ei ole funktioita. Tämä on jäänne vanhoista C-tietueista, joissa ei voitu käyttää funktioita. Minusta kyseessä on huono ohjelmointitapa. Nykyiset funktiottomat tietueet saattavat tarvita funktioita tulevaisuudessa. Tällöin ohjelmoijan on muutettava tyyppi class-tyypiksi tai rikottava sääntöjään vastaan ja päädyttävä tietueisiin, joissa on metodeita.