Esittely latautuu. Ole hyvä ja odota

Esittely latautuu. Ole hyvä ja odota

Olio-ohjelmoinnin perusteet luento 5 Päivi Ovaska LTY/Tietotekniikan osasto.

Samankaltaiset esitykset


Esitys aiheesta: "Olio-ohjelmoinnin perusteet luento 5 Päivi Ovaska LTY/Tietotekniikan osasto."— Esityksen transkriptio:

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ö: olioparametri

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

26


Lataa ppt "Olio-ohjelmoinnin perusteet luento 5 Päivi Ovaska LTY/Tietotekniikan osasto."

Samankaltaiset esitykset


Iklan oleh Google