12 Mallit (Templates)



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

Olio-ohjelmointi Syntaksikokoelma

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

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

Olio-ohjelmointi 2. välikoe HYV5SN

13 Operaattoreiden ylimäärittelyjä

815338A Ohjelmointikielten periaatteet Harjoitus 5 Vastaukset

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

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

Osoitin ja viittaus C++:ssa

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

15. Ohjelmoinnin tekniikkaa 15.1

15. Ohjelmoinnin tekniikkaa 15.1

Operaattoreiden uudelleenmäärittely

Ohjelmoinnin perusteet Y Python

Tietueet. Tietueiden määrittely

Ohjelmoinnin perusteet Y Python

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

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

Olio-ohjelmointi Geneerisyys. 1. Johdanto

812347A Olio-ohjelmointi, 2015 syksy 2. vsk. V Geneerisyys

Kääntäjän virheilmoituksia

ITKP102 Ohjelmointi 1 (6 op)

Alkuarvot ja tyyppimuunnokset (1/5) Alkuarvot ja tyyppimuunnokset (2/5) Alkuarvot ja tyyppimuunnokset (3/5)

Java-kielen perusteet

Javan perusteita. Janne Käki

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

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

Mallit standardi mallikirjasto parametroitu tyyppi

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

Ohjelmoinnin perusteet Y Python

Ohjelmointi 1 Taulukot ja merkkijonot

ITKP102 Ohjelmointi 1 (6 op)

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

Java-kielen perusteet

Taulukot. Jukka Harju, Jukka Juslin

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

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

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

14. oppitunti. Operaattorin ylikuormitus. Osa. Operaattorin ylikuormittaminen

Ohjelmoinnin peruskurssi Y1

Olio-ohjelmointi Javalla

ITKP102 Ohjelmointi 1 (6 op)

1. Olio-ohjelmointi 1.1

Pythonin alkeet Syksy 2010 Pythonin perusteet: Ohjelmointi, skriptaus ja Python

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

Virtuaalifunktiot ja polymorfismi

Demo 6 vastauksia. 1. tehtävä. #ifndef #define D6T1 H D6T1 H. #include <iostream> using std::ostream; using std::cout; using std::endl;

Luokkamallit Luokkamallin määritteleminen

Funktiomallit Funktiomallin määrittely

1. Omat operaatiot 1.1

Periytyminen. Luokat ja olio-ohjelmointi

Metodien tekeminen Javalla

Osa III. Olioiden luominen vapaalle muistialueelle

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

Koottu lause; { ja } -merkkien väliin kirjoitetut lauseet muodostavat lohkon, jonka sisällä lauseet suoritetaan peräkkäin.

Ohjelman virheet ja poikkeusten käsittely

C++11 lambdat: [](){} Matti Rintala

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

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

Harjoitus Olkoon olemassa luokat Lintu ja Pelikaani seuraavasti:

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

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

Loppukurssin järjestelyt C:n edistyneet piirteet

9. Periytyminen Javassa 9.1

ITKP102 Ohjelmointi 1 (6 op), arvosteluraportti

Taulukot. Taulukon määrittely ja käyttö. Taulukko metodin parametrina. Taulukon sisällön kopiointi toiseen taulukkoon. Taulukon lajittelu

815338A Ohjelmointikielten periaatteet Harjoitus 3 vastaukset

Ohjelmointiharjoituksia Arduino-ympäristössä

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

812336A C++ -kielen perusteet,

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

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

Loppukurssin järjestelyt

9. Periytyminen Javassa 9.1

Javan perusteet. Ohjelman tehtävät: tietojen syöttö, lukeminen prosessointi, halutun informaation tulostaminen tulostus tiedon varastointi

Mikä yhteyssuhde on?

etunimi, sukunimi ja opiskelijanumero ja näillä

Ohjelmoinnin peruskurssi Y1

Kielioppia: toisin kuin Javassa

Java-kielen perusteita

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

2. Lisää Java-ohjelmoinnin alkeita. Muuttuja ja viittausmuuttuja (1/4) Muuttuja ja viittausmuuttuja (2/4)

Tähtitieteen käytännön menetelmiä Kevät 2009 Luento 4: Ohjelmointi, skriptaus ja Python

ITKP102 Ohjelmointi 1 (6 op)


ITKP102 Ohjelmointi 1 (6 op), arvosteluraportti

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

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

Muuttujat ja kontrolli. Ville Sundberg

ITKP102 Ohjelmointi 1 (6 op), arvosteluraportti

Luokan operaatiot. Osoittimet ja viittaukset luokan olioihin

20. Javan omat luokat 20.1

Sisällys. 20. Javan omat luokat. Java API. Pakkaukset. java\lang

Vertailulauseet. Ehtolausekkeet. Vertailulauseet. Vertailulauseet. if-lauseke. if-lauseke. Javan perusteet 2004

Rajapinta (interface)

Merkkijonon tutkiminen matches-metodilla

Esimerkki luokkahierarkiasta: C++-kielen IOstream-kirjasto

17. Javan omat luokat 17.1

Table of Contents. T Olio-ohjelmointi C/C++ perusteita Jukka Jauhiainen OAMK Tekniikan yksikkö 2010, 2011

Transkriptio:

12 Mallit (Templates) Malli on määrittely, jota käyttämällä voidaan luoda samankaltaisten aliohjelmien ja luokkien perheitä. Malli on ohje kääntäjälle luoda geneerisestä tyyppiriippumattomasta ohjelmakoodista 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. 12.1 Aliohjelmamalli Aina samanlaisena toistuva aliohjelmalogiikka voidaan kirjoittaa aliohjelmamalliksi (Function template), jota voidaan käyttää sopiville tietotyypeille. Ohjelmakoodia ei tarvitse kirjoittaa kuin kerran. 1

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. 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) ; //Prototyyppi int main () cout << " Luku1 + Luku2 = " << Summa(2,5) << endl ; cout << " Luku1 + Luku2 = " << Summa(2.2,10.1) << endl ; // Huom! A +! = b sillä (65 + 33 = 98). cout << " Merkki + Merkki = " << Summa ('A', '!' ) << endl ; 2

return 0 ; template <typename T> T Summa (T Luku1, T Luku2) return (Luku1 + Luku2) ; 12.2 Luokkamallit 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 ; 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ää 3

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> 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. Malliluokka <Parametri> Olio ; 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 4

private: string Nimi ; T Paino ; public: ; Malli_Kissa(string KissanNimi) ; ~Malli_Kissa() ; void AsetaPaino(T KissanPaino) ; void NaytaPaino() ; template <class T> Malli_Kissa<T>::Malli_Kissa(string KissanNimi) 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 << endl << Nimi << " painaa " << Paino << " kiloa." << endl ; 5

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 ; 6

13 Operaattorien ylikuormaus Operaattoreiden ylikuormaus tarkoittaa aliohjelman toteuttamista siten, että aliohjelman nimi on jokin operaattorimerkki. Aliohjelma voi kantaa nimenään mm. aritmeettista operaattoria tai vertailuoperaattoria. Kuormitetut operaattorit mahdollistavat jo aikaisemmin tällä kurssilla esillä olleen string-luokan, jossa merkkijonoja voitiin vertailla yhtäsuuruusoperaattorilla == eikä tarvittu C:n standardikirjaston strcmp-funktiota. Kukin operaattori kuormitetaan omassa aliohjelmassaan. Operaattorin kuormitusaliohjelman nimi on operator op missä op on jokin operaattorimerkki. C++ mahdollistaa seuraavien operaattorien ylikuormauksen luokkien yhteydessä: + - * / = < > += -= *= /= << >> <<= >>= ==!= <= >= ++ -- % & ^! ~ &= ^= = && %= [] () new delete 13.1 Sijoitusoperaattorin = ylikuormaus Kopiomuodostimella voitiin luoda uusi olio ja kopioida vanhan olion tiedot siihen. Jos ohjelmassa halutaan sijoittaa jo olemassa olevan olion tiedot johonkin toiseen olemassa olevaan olioon, voidaan määritellä sijoitusoperaattori = siten, että yhtäsuuruusmerkin oikealla puolella olevan olion tietojäsenten sisällöt kopioituvat vasemmalla puolella oleviin vastaaviin tietojäseniin. Esimerkiksi suorakulmioluokkaan voidaan määritellä olla sijoitusoperaattori = seuraavasti: 7

class suorakulmio private: double leveys,korkeus; public: // suorakulmio(double,double); suorakulmio() leveys=0; korkeus=0; // ; Luokan määrittelyosassa voidaan kirjoittaa: void operator = (const suorakulmio &); ja itse metodi on vastaavasti: void suorakulmio::operator = (const suorakulmio &s) this->korkeus=s.korkeus; this->leveys=s.leveys; Ylikuormattua metodia voidaan kutsua seuraavasti: int main() suorakulmio olio(1,2); suorakulmio tokaolio; //tokaolion leveys on 0 ja korkeus 0 tokaolio=olio; //tokaolion leveys on nyt 1 ja korkeus 2 return 0; 13.2 Vertailuoperaattorin == ylikuormaus Suorakulmioluokkaan voitaisiin lisätä vertailu, joka vertaa kahden suorakulmio-olion yhtäsuuruutta: Lisätään luokan määrittelyyn: bool operator==(const suorakulmio &); Vertailuoperaattori == palauttaa bool-tyyppisen totuusarvon, joka on tosi eli 1, jos kahden olion kaikki 8

vastaavat tietojäsenet ovat yhtäsuuria, ja arvon epätosi eli 0, jos yksikin on erisuuri. Itse ylikuormauksen tekevä metodi näyttää seuraavalta: bool suorakulmio::operator ==(const suorakulmio &s) if (this->leveys == s.leveys && this->korkeus == s.korkeus) else return true; return false; Saattaa vaikuttaa vähän monimutkaiselta, mutta suomennetaan: this-osoitin osoittaa yhtäsuuruusmerkin vasemmalla puolella olevaan olioon. Sen tietojäseniin viitataan nuolioperaattorilla, koska kyseessä on osoitin. Vertailuoperaatiolle viedään viittausparametrin välityksellä toinen vertailtava olio s, johon viitataan tavalliseen tapaan pisteoperaattorilla. 13.3 Aritmeettisten operaattoreiden ylikuormaus Tehdään seuraavaksi operaattori +, joka laskee yhteen kaksi oliota siten, että olioiden korkeudet ja leveydet lasketaan erikseen yhteen. Luokan määrittelyssä: Metodi: suorakulmio operator + (const suorakulmio &); suorakulmio suorakulmio::operator + (const suorakulmio &s) suorakulmio temp; temp.leveys=this->leveys+s.leveys; temp.korkeus=this->korkeus+s.korkeus; return temp; 9

13.4 Syöttö- ja tulostusoperaattorien ylikuormaus. Luokan ystävät Perustietotyyppien syötön ja tulostuksen yhteydessä olemme tutustuneet << ja >> operaattoreihin. Ne on kuormitettu iostream-kirjaston luokkiin. Ne ovat valmiita luokkia, joihin ohjelmoija ei voi lisätä uusia aliohjelmia. Jos << tai >> operaattoreita halutaa käyttää omien luokkien olioiden syöttöön tai tulostukseen, ne on määriteltävä kullekin ohjelmoijan määrittelemälle tyypille. Suorakulmioluokan tapauksessa olisi aika viileetä, jos luku saataisiin tulostettua suoraan vanhalla tutulla tavalla suorakulmio sk(1,1); cout << sk << endl; Tämähän ei onnistu suoraan, koska cout osaa tulostaa vain tavallisen tietotyypin, eli yksittäisen luvun tai merkkijonon. Tulostusoperaattori ei siis kuulu suorakulmioluokkaan. Se ei siis periaatteessa pysty tulostamaan suoraan luokan yksityisiä tietojäseniä. Tähän asti on koko ajan korostettu sitä, että ainoastaan luokan omat metodit voivat käsitellä yksityisiä tietojäseniä. Tähän löytyy kuitenkin ratkaisu. On nimittäin mahdollista määritellä tulostusoperaattori luokan ystäväksi (friend). Avainsanaa friend käyttämällä voidaan jollekin toiselle luokalle antaa oikeus käsitellä luokan yksityisiä tietojäseniä. Ystäväksi voidaan määritellä yksittäinen luokan ulkopuolinen funktio tai kokonainen toinen luokka. Avainsanoilla private ja public ei ole mitään vaikutusta ystäväfunktioon tai luokkaan. Tarkastellaan seuraavaksi, miten suorakulmio tulostus voidaan tehdä <<-operaattoria ylikuormittamalla. Syöttö- ja tulostusoperaattorien ylikuormauksen yleinen muoto on: ostream& operator << (ostream&, const Class &); Ostream on C++:n yleinen tulostusvirta (output stream), joka on määritelty iostream-kirjastossa. Meidän riittää tietää, että juuri se ohjaa merkit näytölle. Ylikuormattu <<-operaattori siis palauttaa viittauksen tulostusvirtaan ostream. Se ottaa kaksi viittausparametria, viittauksen ostreamiin ja vakioviittauksen käyttäjän määrittelemään luokkaan. Suorakulmioluokalle toteutus näyttää seuraavalta: Luokan määrittelyssä: friend ostream &operator<<(ostream &,const suorakulmio &); Varsinainen metodi näyttää seuraavalta: 10

ostream &operator << (ostream &os, const suorakulmio &s) os << s.leveys << " " << s.korkeus << endl; return os; Viittausmuuttuja os on tulostusvirta, joka tässä korvaa coutin. Kutsuvalle ohjelmalle palautetaan viittaus tulostusvirtaan mahdollista tulostusten ketjutusta varten. 11