Lataa esitys
Esittely latautuu. Ole hyvä ja odota
JulkaistuTopi Jääskeläinen Muutettu yli 9 vuotta sitten
1
Olio-ohjelmoinnin perusteet luento 5 Päivi Ovaska LTY/Tietotekniikan osasto
2
Sisältö Luokkakohtaiset tieto- ja aliohjelmajäsenet Monimuotoisuus Yleistä Virtuaalinen aliohjelma ja dynaaminen sidonta Operaattoreiden ylikuormitus
3
Luokkakohtaiset tiedot Luokkakohtaiset tietojäsenet (static data members) sisältävät luokkaa kuvailevia tietoja Tiedot luokan kaikkien olioiden käytettävissä luokan metodeissa Luokkakohtaisesta tiedosta on luokassa vain yksi ilmentymä Luokkakohtainen tieto on ikään kuin globaali tieto luokan sisällä Luokkakohtainen tieto on muistinvarausluokaltaan staattinen, joten järjestelmä varaa sille tilan globaalien muuttujien tilanvarauksen yhteydessä
4
Esimerkki luokkakohtaisesta tiedosta Henkilo.hpp #ifndef HENKILOHPP #define HENKILOHPP class Henkilo { private: char etunimi[15]; char sukunimi[25]; charsotu[12]; static int lkm; static Henkilo *henkilot[10]; public: Henkilo(); ~Henkilo(); voidKysy(); voidNayta() const; static void Montako(); static int Lisaa(); static void TulostaKaikki(); static void TuhoaKaikki(); }; #endif Henkilo.cpp #include using namespace std; #include #include "henkilo.hpp" int Henkilo::lkm = 0; //luokkakohtaisen tiedon //määrittely ja alustus Henkilo *Henkilo::henkilot[10] = {NULL}; Henkilo::Henkilo() { strcpy(etunimi, " "); strcpy(sukunimi, " "); strcpy(sotu, " "); lkm++; } Henkilo::~Henkilo() { strcpy(etunimi, " "); strcpy(sukunimi, " "); strcpy(sotu, " "); } void Henkilo::Kysy() { cout<<"\nSYÖTÄ HENKILÖN TIEDOT\n"; cout<<"\nEtunimi:............"; cin>>ws>>etunimi; cout<<"Sukunimi:..........."; cin>>ws>>sukunimi; cout<<"Sosiaaliturvatunnus: "; cin>>ws>>sotu; }
5
Esimerkki jatkuu void Henkilo::Nayta() const { cout<<"\n\nHENKILÖN TIEDOT\n"; cout<<"\nNimi: "<<etunimi<<" "<<sukunimi; cout<<"\nSosiaaliturvatunnus: "<<sotu; } void Henkilo::Montako() { cout<<"\nHenkilöitä on yhteensä: "<<lkm; } int Henkilo::Lisaa() { int ind = 0; while (ind < 10 && henkilot[ind] != NULL) ind++; if (ind < 10) { henkilot[ind] = new Henkilo; henkilot[ind]->Kysy(); cout<<"\nLisätty henkilö: "; cout sukunimi; return 1; } else return 0; } void Henkilo::TulostaKaikki() { int ind = 0; while (ind < 10 && henkilot[ind] != NULL) { henkilot[ind]->Nayta(); ind++; } void Henkilo::TuhoaKaikki() { int ind = 0; while (ind < 10 && henkilot[ind] != NULL) { delete henkilot[ind]; henkilot[ind] = NULL; lkm--; ind++; }
6
Esimerkki jatkuu Pääohjelma #include using namespace std; #include "henkilo.hpp" int KysyValinta(); int main() { int vastaus, ok; vastaus = KysyValinta(); while (vastaus != 0) { switch(vastaus) { case 1: ok = Henkilo::Lisaa(); if (ok == 0) cout<<"\nTietorakenne täyttyi, henkilöä ei lisätty"; break; case 2: Henkilo::TulostaKaikki(); break; default: cout<<"\nKo. toimintoa ei ole"; } vastaus = KysyValinta(); } Henkilo::TuhoaKaikki(); return 0; } int KysyValinta() { int vastaus; cout<<"\nVALIKKO"; cout<<"\n1) Henkilötietojen lisäys"; cout<<"\n2) Henkilöiden tietojen tulostus"; cout<<"\n0) Lopetus\n"; cin>>ws>>vastaus; return vastaus; }
7
Monimuotoisuus Monimuotoisuus (polymorphism) tarkoittaa eri olioiden kykyä vastata samaan viestiin eri tuloksella olion käyttäytymistavan määrää olion määrittelyluokkaan toteutettu metodi ajonaikainen eli dynaaminen sidonta Monimuotoisuus toteutetaan seuraavilla C++ mekanismeilla: Virtuaalinen aliohjelma ja dynaaminen sidonta (korvaaminen,overriding) Aliohjelmien ja operaattoreiden ylikuormitus (overloading) ja staattinen sidonta
8
Esimerkki virtuaalisesta aliohjelmasta ja dynaamisesta sitomisesta Staattinen sidonta ja tavalliset metodit using namespace std; class Henkilo { public: void LuokanNimi() {cout<<"\nHenkilo";} }; class Tyontekija : public Henkilo { public: void LuokanNimi() {cout<<"\nTyontekija";} }; class Osakas : public Henkilo { public: void LuokanNimi() {cout<<"\nOsakas";} }; int main() { Henkilo *olio1 = new Henkilo; Tyontekija *olio2 = new Tyontekija; Osakas *olio3 = new Osakas; olio1->LuokanNimi(); olio2->LuokanNimi(); olio3->LuokanNimi(); return 0; } Dynaaminen sidonta ja virtuaalimetodit #include using namespace std; class Henkilo { public: virtual void LuokanNimi() {cout<<"\nHenkilo";} }; class Tyontekija : public Henkilo { public: void LuokanNimi() {cout<<"\nTyontekija";} }; class Osakas : public Henkilo { public: void LuokanNimi() {cout<<"\nOsakas";} }; int main() { Henkilo *oliot[5]; oliot[0] = new Henkilo; oliot[1] = new Tyontekija; oliot[2] = new Osakas; for (int ind = 0; ind < 3; ind++) oliot[ind]->LuokanNimi(); return 0; }
9
Aliohjelmien kuormitus Aliohjelmien kuormitus (overloading) eli ylimäärittely tarkoittaa samannimisen aliohjelman esittelyä ja määrittelyä useaan kertaan Käytetään, kun aliohjelman nimi halutaan standardoida tiettyyn tarkoitukseen riippumatta käsiteltävän tiedon tyypistä ja käsittelyn logiikasta Kuormitetut aliohjelmat poikkeavat toisistaan tyyppien ja/tai lukumäärien perusteella Kääntäjä tarkistaa käännösaikana, mikä aliohjelma sopii käytettyyn aliohjelmakutsuun parhaiten (staattinen sidonta) Sopivuuden ratkaiseminen suora sopivuus sopivuus standardikonversion jälkeen sopivuus käyttäjän määrittämän tyyppimuunnoksen jälkeen
10
Esimerkki kuormitetusta aliohjelmasta #include using namespace std; void KerroTyyppi(int); void KerroTyyppi(int, int); void KerroTyyppi(double); int main() { KerroTyyppi(5); KerroTyyppi(2, 4); KerroTyyppi(2.5); return 0; } void KerroTyyppi(int luku) { cout<<"\nParametri on int "<<luku; } void KerroTyyppi(int luku1, int luku2) { cout<<"\n1. parametri on int "<<luku1; cout<<"\n2. parametri on int "<<luku2; } void KerroTyyppi(double luku) { cout<<"\nParametri on double "<<luku; }
11
Operaattoreiden ylikuormitus Aliohjelman toteuttamista siten, että aliohjelman nimi on jokin operaattorimerkki Ylikuormitusohjelman nimi on operatorop (op=operaattorimerkki) Ylikuormitettavia operaattoreita: +-*/% &| ! =<>+=-=*=/=%= = &= /= >>>= =&& //++-->*, ()newdelete
12
Operaattoreiden ylikuormituksen rajoituksia merkkien suoritusjärjestystä ei ole mahdollista muuttaa alkuperäistä syntaksia ei voi muuttaa % ja ! ei ole mahdollista määritellä uusia merkkejä ei voi määritellä sizeof..* :: ?: ei voi ylikuormittaa Seuraavia operattoreita voidaan ylikuormittaa ainoastaan luokkien aliohjelmajäsenillä: =, (),[],-> operaattoreita ei voi ylikuormittaa static- aliohjelmassa Jos yliluokkaan on määritelty jokin ylikuormitettu operaattori, se periytyy aliluokille tavallisten aliohjelmien tapaan (poikkeus: sijoitusoperaattori =)
13
Esimerkkejä operaattoreiden ylikuormituksesta kaksioperandisen operaattorialiohjelman kutsu esim. luku1 + luku2; tulkintatavat: luku1.operator+(luku2); //luokka1 operator+ -viesti operator+(luku1,luku2); //luokkaan kuulumattoma operator+-aliohjelman kutsu, toteutetaan ystäväaliohjelmina, ei kuulu kurssin sisältöön yksioperandisen operaattorin kutsu prefix- muodossa ++luku1; yksioperandisen operaattorin kutsu postfix- muodossa luku1++;
14
Operaattoreiden esittelyt Esittelyt: Luokka operator++(); // prefix-kutsumuoto Luokka operator++(int); //postfix- kutsumuoto
15
Esimerkki ++ #include class Luku { private: int x; public: Luku(const int p_x) {x = p_x;} Luku operator++(); //prefix Luku operator++(int); //postfix void Nayta() {cout<<x;} }; Luku Luku::operator++() { x++; return (*this); } Luku Luku::operator++(int) { Luku apu = *this; x++; return apu; } int main(void) { Luku Luku1(2); Luku Luku2 = Luku1++; cout<<"Luku2 on: "; Luku2.Nayta(); cout<<"\nLuku2 on muutettuna: "; Luku1.Nayta(); Luku Luku3 = ++Luku1; cout<<"\nLuku3 on: "; Luku3.Nayta(); return 0; } Tulos: Luku2 on: 2 Luku2 on muutettuna: 3 Luku3 on : 4
16
Binäärinen lisäysoperaattori + käsittelee kahta operandia Luokka olio1, olio2, olio3; olio3 = olio1 + olio2; Kutsu voidaan purkaa: olio3.operator=(olio1.operator+(olio2));
17
Esimerkki + #include class Luku { private: int x; public: Luku() {x = 0;} Luku(const int p_x) {x = p_x;} Luku operator+(Luku &); Luku operator+(int); void Nayta() {cout<<x;} }; Luku Luku::operator+(Luku &p_olio) { Luku apu = *this; apu.x = apu.x + p_olio.x; return apu; } Luku Luku::operator+(int p_x) { Luku apu = *this; apu.x = apu.x + p_x; return apu; } int main(void) { Luku Luku1(2); Luku Luku2(3); Luku Luku3 = Luku1 + Luku2; //Luku1.operator+(Luku2) Luku3 = Luku3 + 2; //Luku3.operator+(2); cout<<"\nLuku3 on: "; Luku3.Nayta(); return 0; } tulos: Luku3 on:7
18
Unaarinen operaattori [] Voidaan käyttää esimerkiksi merkkijonon tietyn merkin palauttamiseen Operaattorin käyttö: olioparametri
19
Esimerkki [] class Merkkijono { char *jono; public: Merkkijono() { jono = NULL;} Merkkijono(const char []); Merkkijono(const Merkkijono &); Merkkijono &operator=(const Merkkijono &); ~Merkkijono(); void Nayta() const {if (jono) cout<<jono;} Merkkijono operator+(const Merkkijono &); char operator[](const int); }; Merkkijono Merkkijono::operator+(const Merkkijono &P_jono) { Merkkijono apu; apu.jono = new char[strlen(jono) + strlen(P_jono.jono) + 1]; strcpy(apu.jono, jono); strcat(apu.jono, P_jono.jono); return apu; } char Merkkijono::operator[](const int p_ind) { if (p_ind -1) return jono[p_ind]; else return 0; } Merkkijono::Merkkijono(const char p_jono[]) { int pituus = strlen(p_jono) + 1; jono = new char[pituus]; strcpy(jono, p_jono); } Merkkijono::Merkkijono(const Merkkijono &P_jono) { int pituus = strlen(P_jono.jono) + 1; jono = new char[pituus]; strcpy(jono, P_jono.jono); } Merkkijono &Merkkijono::operator=(const Merkkijono &P_jono) { int pituus = strlen(P_jono.jono) + 1; if (jono) delete [] jono; jono = new char[pituus]; strcpy(jono, P_jono.jono); return (*this); } Merkkijono::~Merkkijono() { if (jono) { delete [] jono; jono = NULL; } int main(void) { Merkkijono olio1("Alku"); Merkkijono olio2("Loppu"); Merkkijono uusi = olio1 + olio2; uusi.Nayta(); cout<<"\n4. merkki on: "<<uusi[3]; return 0; }
20
Tyyppimuunnosoperaattorit tieto voidaan muuntaa luokan olioksi yksiparametrisen muodostimen avulla Luokka(tietotyyppi); Luokka olio =2; olio=Luokka(2); //järjestelmä tulkitsee sijoituksena Olio voidaan muuntaa muuntyyppiseksi tiedoksi tyyppimuunnosoperaattorin avulla operator tyyppi(); tyyppimuunnosoperattori on toteutettava luokan metodina, ei paluuttyyppiä eikä parametreja
21
Esimerkki tyyppimuunnosoperaattorista class Luku { private: int x; public: Luku() {x = 0;} Luku(const int p_x) {x = p_x;} Luku(const double p_x) {x = (int)p_x;} operator int() {return x;} Luku operator+(Luku &); Luku operator+(int); void Nayta() {cout<<x;} }; Luku Luku::operator+(Luku &p_olio) { Luku apu = *this; apu.x = apu.x + p_olio.x; return apu; } Luku Luku::operator+(int p_x) { Luku apu = *this; apu.x = apu.x + p_x; return apu; } int main(void) { Luku Luku1; Luku1 = 2; Luku Luku2; Luku2 = 4.5; cout<<"Luku1: "; Luku1.Nayta(); cout<<"\nLuku2: "; Luku2.Nayta(); cout<<"\nMuunnettuna kokonaisluvuksi: "; int numero = (int)Luku2; cout<<numero; return 0; } tulos: Luku1:2 Luku2:4 Muunnettuna kokonaisluvuksi: 4
22
Myöhäisen sidonnan käyttötapoja Käsitteellinen erikoistus/yleistys- hierarkkia uudelleenkäyttö rajapinta, jolla on useita toteutuksia abstrakti rajapinta voidaan määritellä oma luokkanaan (pelkästään operaatiot avoimina virtuaaalioperaatioina), joka toteutuksen tarjoava luokka perii
23
Rajapintaluokat
24
Esimerkki rajapintaluokasta
25
Esimerkki jatkuu
Samankaltaiset esitykset
© 2024 SlidePlayer.fi Inc.
All rights reserved.