1 / 26

Olio-ohjelmoinnin perusteet luento 5

Olio-ohjelmoinnin perusteet luento 5. Päivi Ovaska LTY/Tietotekniikan osasto. Sisältö. Luokkakohtaiset tieto- ja aliohjelmajäsenet Monimuotoisuus Yleistä Virtuaalinen aliohjelma ja dynaaminen sidonta Operaattoreiden ylikuormitus. Luokkakohtaiset tiedot.

Download Presentation

Olio-ohjelmoinnin perusteet luento 5

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. Olio-ohjelmoinnin perusteetluento 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. Henkilo.hpp #ifndef HENKILOHPP #define HENKILOHPP class Henkilo { private: char etunimi[15]; char sukunimi[25]; char sotu[12]; static int lkm; static Henkilo *henkilot[10]; public: Henkilo(); ~Henkilo(); void Kysy(); void Nayta() const; static void Montako(); static int Lisaa(); static void TulostaKaikki(); static void TuhoaKaikki(); }; #endif Henkilo.cpp #include <iostream> using namespace std; #include <cstring> #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; } Esimerkki luokkakohtaisesta tiedosta

  5. 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<<henkilot[ind]->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++; } } Esimerkki jatkuu

  6. Pääohjelma #include <iostream> 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; } Esimerkki jatkuu

  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. 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 <iostream> 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; } Esimerkki virtuaalisesta aliohjelmasta ja dynaamisesta sitomisesta

  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 <iostream> 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: + - * / %  & |  ! = < > += -= *= /= %= = &= /= << >> >>= <<= == != <= >= && // ++ - ->* ,  () new delete

  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. #include <iostream.h> 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 Esimerkki ++

  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. #include <iostream> 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 Esimerkki +

  18. Unaarinen operaattori [] • Voidaan käyttää esimerkiksi merkkijonon tietyn merkin palauttamiseen • Operaattorin käyttö: olioparametri

  19. 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 < strlen(jono) && 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; } Esimerkki []

  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. 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 Esimerkki tyyppimuunnosoperaattorista

  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. Esimerkki jatkuu

More Related