Olio-ohjelmoinnin perusteetluento 3
Päivi Ovaska
LTY/Tietotekniikan osasto
Sisältö
C++-kielen näkymistä
Olioiden ja luokkien välistenyhteyksien toteuttaminen
Johdanto periytymiseen
Näkymät (scope)
C++-kielessä kolmenlaisia näkymiä:
Tiedostonäkymä eli globaali määrittelyalue
Tunnus näkyy kaikkialla käännösyksikössä
paikallinen näkymä eli aliohjelma tai lohko
tunnus näkyy vain paikallisesti lohkossa taialiohjelmassa
luokkanäkymä
tunnus näkyy luokan määrittelyssä esiintyviennäkyvyyssääntöjen mukaisesti
nimiavaruus
tunnus näkyy kaikialla, missä nimiavaruus onotettu käyttöön
Luokkanäkymä
Jokainen luokka on oma paikallinen näkymänsä
Luokka, joka sisältää muita luokkia on samassa näkymässä
Jäsenfunktiot ovat luokan näkymässä
Jäsenfunktion ylläpitävät myös omaa paikallista näkymäänsä
int height;//global height
Class Screen{
public:
Screen(){height=::height;}
private:
short height;
};
Screen: badPractice()
{
int hi=height; //Screen::height
int height=height;  //hides Screen::height
Screen:bdPrac()
{
int height=Screen::height;
}
Screen::badPractice()
{
int height= (Screen::height > ::height) ? ::height: Screen::height;
}
Paikallinen luokka
Paikallisen luokan jäsenfunktiot onmääriteltävä luokan rungossa
Paikallinen luokka on funktion näkymässä,mutta funktiossa määritellyt muuttujateivät ole luokan jäsenfunktioidennäkymässä
int doString (char *s)
{
class String{...};
String str(s);
}
String str(“gravity”);  //virhe, String ei näkymässä
Paikallinen luokka (jatkuu)
Paikallisen luokan määrittely antaa ohjelmoijallemahdollisuuden rajoittaa luokan näkyvyyttä kyseessäolevalle funktiolle
const int bufsize = 1024;
void func()
{
const int bufSize = 512;
char *ps = new char[bufSize];  //512
class String{
public:
String()
{
   str = new char [bufSize];  //1024!
}
Olioiden ja luokkien välistenyhteyksien toteuttaminen
Olioilla toisiinsa nähden kolmenlaisia suhteita:koostumussuhteita, yhteyssuhteita ja riippuvuussuhteita
Suhteet toteutetaan määrittelemällä olio luokanjäseneksi
Esimerkkejä luokkien välisistäkoostumussuhteista
Koostumussuhde (aggregation)
Olio voi koostua muista olioista
Koosteolio ja osaolio
Koosteolion luokka muodostaa koosterakenteen (aggregate),jossa tietojäseninä voi olla olioita
Koosteolio omistaa osaolionsa ja on vastuussa niidenkäsittelystä
Koosteolion asiakkaat eivät tunne koosteolion rakennetta,vaan käsittelevät koosteoliota kokonaisuutena
Koosteolio ei välttämättä sisällä syntyhetkellä kaikkiaosaolioita, vaan osaolio voi syntyä myöhemmin koosteolionolemassaolon aikana
Joidenkin koosteolioiden sisältämä osaolio on mahdollistavaihtaa toiseen osaolioon
UML määrittelee kaksi koostetyyppiä:
kokoonpanollinen kooste (muodostuminen, composite aggregate)
jaettu kooeste (koostuminen, shared aggregate)
Esimerkkejä koostumussuhteista
Tilaus sisältää tilausrivioilioita, joitavoidaan lisätä tilausolioon senolemassaolon aikana
Tietokone koostuu näytöstä,keskusyksiköstä ja muistaoheislaitteista. Tietokoneen näyttö onmahdollista vaihtaa toiseentarvittaessa
Koostumussuhteen toteuttaminen
Koostumussuhde voidaan toteuttaakolmella eri tavalla:
Koosteluokassa suora viittaus osaolioon(muodostuminen)
Koosteluokassa osoitinviittaus osaolioon
Koosteluokassa viittaus osaolioon
Koosteluokan aliohjelmat käsittelevätosaolioita lähettämällä viestejä osaolioille
Koosteluokassa suora viittausosaolioon
osaolio syntyy automaattisesti koosteoliontilanvarauksen yhteydessä
osaolio häviää automaattisesti koosteoliontilanvapautuksen yhteydessä
koosteolion on aina pakko sisältää osaolio
class Osa
{
...
};
class Kooste
{
Osa Osa1;
}
Koosteluokassa osoitinviittausosaolioon
osaolio saattaa syntyä aiemmin tai myöhemmin kuinkoosteolio
osaolio on liitettävä koosteolioon koosteluokanmuodostimessa tai muussa aliohjelmassa
osaolio on tuhottava koosteolion tilanvapautuksenyhteydessä
koosteolio ei välttämättä sisällä osaoliota, koosteolionsisältämä osaolio voi vaihtua
class Kooste
{
Osa* Osa2;
}
Koosteluokassa viittaus osaolioon
osaolio syntyy aikaisemmin kuin koosteolio
osaolio on liitettävä koosteolioonkoosteolion muodostimessa
osaolio on tuhottava koosteoliontilanvapautuksen yhteydessä
koosteolio ei välttämättä sisällä osooliota,koosteolion sisältämä osaolio ei voi vaihtua
class Kooste
{
Osa& Osa3;
}
Muodostimet koosteluokassa
Oletusmuodostin
Kooste::Kooste()
{
Osa2 = new Osa;
}
Kooste::Kooste():Osa3(*(new Osa)) //aiheuttaa//Osa-luokan//kopiomuodostimen kutsun
{
}
Parametrillinen muodostin
Kooste::Kooste(Osa& Eka, Osa& Toka)
: Osa2(&Eka), Osa3(Toka)
{
//Osa2=&Eka;
}
Hajotin
Kooste::~Kooste()
{
delete Osa2;
delete &Osa3;
}
Esimerkki koosteluokista:Tietokone
#include <iostream>
using namespace std;
#include <cstring>
class Naytto
{
char koko[10];
public:
Naytto(const char p_koko[]) {strcpy(koko, p_koko);}
~Naytto() {strcpy(koko, " ");}
void Nayta() const {cout<<"\nNäytön koko: "<<koko;}
};
class Keskusyksikko
{
char muistia[10];
public:
Keskusyksikko(const char p_muisti[]) {strcpy(muistia,p_muisti);}
~Keskusyksikko() {strcpy(muistia, " ");}
void Nayta() const {cout<<"\nKeskusmuistia:"<<muistia;}
};
class Tietokone
{
char merkki[25];
Keskusyksikko &CPU;
Naytto *naytto;
public:
Tietokone(const char [], const char [], const char []);
Tietokone(const Tietokone &);
~Tietokone();
Tietokone &operator=(const Tietokone &);
void Nayta() const;
Naytto *IrrotaNaytto();
void LiitaNaytto(Naytto *);
};
Tietokone::Tietokone(const char p_merkki[], const charp_cpu[], const char p_naytto[]):
CPU(*(new Keskusyksikko(p_cpu)))
{
strcpy(merkki, p_merkki);
naytto = new Naytto(p_naytto);
}
Tietokone::Tietokone(const Tietokone &P_kone)
: CPU(*(new Keskusyksikko(P_kone.CPU)))
{
strcpy(merkki, P_kone.merkki);
if (P_kone.naytto)
naytto = new Naytto(*(P_kone.naytto));
else
naytto = NULL;
}
Tietokone &Tietokone::operator=(const Tietokone &P_kone)
{
if (this == &P_kone) return (*this);
strcpy(merkki, P_kone.merkki);
CPU = P_kone.CPU;
if (!P_kone.naytto)
naytto = new Naytto(*(P_kone.naytto));
else
*naytto = *P_kone.naytto;
return (*this);
}
Esimerkki koosteluokista jatkuu
Tietokone::~Tietokone()
{
delete &CPU;
if (naytto) delete naytto;
}
Naytto *Tietokone::IrrotaNaytto()
{
Naytto *apu;
apu = naytto;
naytto = NULL;
return apu;
}
void Tietokone::LiitaNaytto(Naytto *p_naytto)
{
naytto = p_naytto;
}
void Tietokone::Nayta() const
{
cout<<"\nTietokoneen merkki: "<<merkki;
CPU.Nayta();
if (naytto)
naytto->Nayta();
else
cout<<"\nNäyttö on irrotettutietokoneesta";
}
int main()
{
Tietokone kone1("Compaq",  "16 MB", "15tuumaa");
kone1.Nayta();
Naytto *apu = kone1.IrrotaNaytto();
cout<<"\nKoneesta irrotettu näyttö: ";
apu->Nayta();
kone1.Nayta();
Tietokone kone2(kone1);
kone2.Nayta();
delete apu;
return 0;
}
Yhteyssuhteen toteuttaminen
Olioiden välillä voi olla väliaikaisiayhteyssuhteita (association)
Yhteyssuhde toteutetaanosoitinmuuttujien tai viittaustenavulla tai erilliselläyhteyssuhdeluokalla
Opiskelijan ja suorituksen välinen
yhteyssuhde
Erillinen yhteyssuhdeluokka, joka
sisältää osoittimet olioihin
Esimerkkejä yhteyssuhteesta
#include <iostream>
using namespace std;
#include "henkilo.hpp"
class Avioliitto
{
Henkilo *mies;
Henkilo *vaimo;
public:
Avioliitto(const Henkilo *, const Henkilo *);
void Nayta();
~Avioliitto();
};
Avioliitto::Avioliitto(const Henkilo *p_mies, const Henkilo*p_vaimo)
{
mies = p_mies;
vaimo = p_vaimo;
}
void Avioliitto::Nayta()
{
mies->Nayta();
vaimo->Nayta();
}
Avioliitto::~Avioliitto()
{
mies = NULL;
vaimo = NULL;
}
int main()
{
Henkilo nainen("Maija", "Meikäläinen", 1, 3, 70);
Henkilo mies("Tatu", "Teikäläinen", 2, 4, 68);
Avioliitto liitto(&mies, &nainen);
liitto.Nayta();
return 0;
}
include <iostream>
using namespace std;
#include "henkilo.hpp"
class Avioliitto
{
Henkilo &mies;
Henkilo &vaimo;
public:
Avioliitto(const Henkilo &, const Henkilo &);
void Nayta();
~Avioliitto();
};
Avioliitto::Avioliitto(const Henkilo &p_mies, const Henkilo&p_vaimo)
: mies(p_mies), vaimo(p_vaimo)  //huom! tietojäsenten alustus
{    //viittauksia käytettäessä
}
void Avioliitto::Nayta()
{
mies.Nayta();
vaimo.Nayta();
}
Avioliitto::~Avioliitto()
{
}
int main()
{
Henkilo nainen("Maija", "Meikäläinen", 1, 3, 70);
Henkilo mies("Tatu", "Teikäläinen", 2, 4, 68);
Avioliitto *liitto = new Avioliitto(mies, nainen);
liitto->Nayta();
delete liitto;
nainen.Nayta();
   mies.Nayta();
return 0;
}
Kooste vai assosiaatio?
Jos luokka tarvitsee tiukasti kokoelinkaarensa ajan luokkaa B,kyseessä on kooste, muutoinassosiaatio
Assosiaatiossa olioilla on omaoikeutuksensa olemassaoloon myösyksinään
Riippuvuussuhde (dependency)
Heikko yhteys: Luokka A tarvitseeluokan B olioita (esim. luokan Bolioita tarvitaan vain parametreina)
luokka Heippa vaatii, että luokan java.awt.Graphics olio on sen
käytettävissä
Yleistä periytymisestä
Asioiden luokittelu ja kategorisointiluonnollista ihmiselle
 Käytetty laajalti tieteissä, kielissä jne.
 Olio-ohjelmointi:
Ryhmittely yhteisten rajapintojen perusteella
Ryhmittely yhteisen toteutuksen perusteella
 Useimmissa kielissä molemmat samamekanismi: periytyminen (inheritance)
Luokkahierarkkia
Luokkahierarkkiat
Erilaisia luokkien rooleja:
Abstraktit kantaluokat
Rajapintaluokat
Konkreettiset luokat
 Hierarkian yläosan luokat
”Yläkäsitteitä”
Määräävät alempien luokkien rajapintaa
Luokkiin viittaaminen ”yhteisellä nimellä”(polymorfismi)
 Hierarkian alaosan luokat
 Palveluiden toteutus (dynaaminen sitominen)
Erikoistaminen (specialization)
Periytyminen ja uudelleenkäyttö
Usein luokilla yhteisiä ominaisuuksia
 Yleistys (generalization):
Yhteiset osat omaan luokkaansa
Osat periyttämällä mukaan varsinaisiinluokkiin
 Ohjelmakoodin uudelleenkäyttö
 Ei koodin toistoa
Periytyminen (inheritance)
Ohjelmoija voi uudelleenkäyttää aiemmin kirjoitetun luokan määrityksiäuutta luokkaa määritellessään
Aliluokka (subclass,derived class) on yliluokasta (superclass, baseclass) johdettu uusi luokka
Aliluokka sisältää (perii) kaikki sen yliluokan (kantaluokan) ominaisuudet(attribuutit ja rajapinnan)
Aliluokkaan voidaan liittää uusia ominaisuuksia , ja kantaluokanominaisuuksia voidaan tarvittaessa muuttaa
Periytyminen on yksiperiytymistä (single inheritance), kun luokka periiyhden yliluokan ja moniperiytymistä (multiple inheritance), kunluokka perii monta yliluokkaa
Liittymän periytymistä (interface inheritance) tai toteutustavanperiytymistä (implementation inheritance)
class Yliluokka
{
//toteutustavan periytyminen
public:
void Ali(); //liittymän periytyminen
};
Periytyminen ja sen käyttötilanteet
Lähellä koostumussuhteen toteuttamista:
An employee is a personperiytyminen
A forest has treeskoostumus
Periytettävät ominaisuudet on valittavakahden eri näkökulman perusteella:aliluokan asiakkaiden näkökulma jaaliluokan toteuttajan näkökulma
Palveluliittymän laajentaminenaliluokan asiakkaille
Yliluokan palveluliittymän ja mahdollisestitoteutusratkaisun (aliohjelmien) periyttäminenaliluokalle
Aliluokan olion asiakas voi pyytää oliolta myös yliluokanpalveluliittymässä esiteltyjä palveluita ja kutsuayliluokassa toteutettuja aliohjelmia:
periytymistapa public
luetaan: aliluokka on yliluokka
työntekijä on henkilö
Palveluliittymän laajentaminenaliluokan kehittäjille
Yliluokan palveluliittymän ja aliohjelmien periyttäminenaliluokalle
Aliluokan aliohjelmat voivat kutsua yliluokassa esiteltyjäja toteutettuja aliohjelmia
periytymistavat protected
luetaan: aliluokka on kuten yliluokka
aliluokka perii sekä liittymän että
toteutustavan, mutta
piilottaa periytymisen
luokkahierarkkian sisään
Toteutustavan periyttäminenaliluokkaan
Yliluokan palvelujen toteutustavan eli aliohjelmien jaattribuuttien toteutustavan periyttäminen
Aliluokan olion palveluliittymä piilottaa yliluokanpalveluliittymän
Aliluokka kontrolloi yliluokan aliohjelmienkäyttötilanteita
periytymistavat private
luetaan: aliluokka toteutetaan kuten yliluokka
Pino on toteutettu Taulukolla
Yliluokan määrittely
class Yliluokka
{
private:
//vain yliluokassa näkyvät jäsenet
protected:
//myös aliluokassa näkyvät jäsenet
public:
//kaikkialla näkyvät jäsenet
};
Perittävä yliluokka voi olla konkreettinen tai abstraktiluokka
Abstrakteja luokkia
käytetään luokkahierarkkian
palveluliittymän standardointiin
UML esimerkki periytymisestä
Erilaisia aliohjelmia
Tavalliset aliohjelmat
Aliohjelmaa käytetään kaikille luokkahierarkian olioille
Aliluokka voi peittää (hide) yliluokan aliohjelman, eikuitenkaan suositella
Mahdollisesti korvattavat aliohjelmat
Yliluokka sisältää oletustoteutukset, mutta siitä voi olla useitatoteutuksia luokkahierarkkiassa
Aliluokka voi korvata (override) yliluokan aliohjelmanoletustoteutuksen tarvittaessa
Toteutustapa: Virtuaaliset aliohjelmat (virtual functions)
Aina korvattavat aliohjelmat
Eri aliluokkien olioille käytetään eri ohjelmakoodia, aliluokkaanon toteutettava aliohjelma aina määrätyllä nimellä
Toteutustapa: puhtaat virtuaaliset aliohjelmat (pure virtualfunctions) ja abstrakti luokka
Erilaisten aliohjelmien esittely
class Yliluokka
{
...
public:
void Aliohjelma1();
virtual void Aliohjelma2(){...}
virtual void Aliohjelma3() =0;
};
Periytymisen syntaksi
class A
2 {
// Luokan A ominaisuudet
4 };
class B : public A
6 {
// Luokan B A:han lisäämätt ominaisuudet
8 };
class C : public A
10 {
11 // Luokan C A:han lisäämät ominaisuudet
12 };
13 class D : public C
14 {
15 // Luokan D C:hen lisäämät ominaisuudet
...
Näkyvyyssääntöjen japeriytymistavan yhteisvaikutus
Aliluokan metodien suunnittelu
Aliohjelman peittäminen
samannimisen aliohjelman toteuttaminen aliluokassa
aliluokan olioita ei ole mahdollista käyttää kaikissa niissä tilanteissamissä yliluokan olioita voidaan käyttää
kun aliluokan olioita käytetään yliluokan tunnuksen avulla
Aliohjelman korvaaminen
Virtuaalisen aliohjelman toteuttaminen aliluokassa
nimen ja parametrien vastaavuus
Periytymättömät aliohjelmat
yliluokassa esiteltyjä aliohjelmia, joita ei voi suoraan kutsualähettämällä viestiä aliluokkaan luodulle oliolle
tulee esitellä ja toteuttaa aina tarvittaessa jokaiselle luokalle erikseen
muodostimet
hajotin
sijoitusaliohjelma (operator=)
ystäväaliohjelma (friend)
Aliluokan esittely ja määrittely
Esitelyluokka on olion tunnuksen luokka
voi olla määrittelyluokka tai jokin määrittelyluokan aliluokka
Määrittelyluokka on luokka, jonka mukaan olion tietojäsententilanvaraus tapahtuu
Aliluokan olion määrittelyluokka on aina aliluokka
Aliluokan oliolle varattavan tilan koko on yliluokka ja aliluokkayhteensä
Automaattisella oliolla esittely- ja määrittelyluokat ovat samat
Aliluokka olio;
Dynaamisella oliolla esittely- ja määrittelyluokat voivat olla eri
Aliluokka *olio = new Aliluokka;
Yliluokka *olio = new Aliluokka;
Aliluokka &olio = aliluokan olio;
Yliluokka &olio = aliluokan olio;
Muodostinten ja hajotintensuoritusjärjestys C++ perinnässä
Järjestelmä kutsuu yliluokan muodostimiaja hajottimia automaattisesti aliluokanolion tilanvarauksen ja tilanvapautuksenyhteydessä
Järjestelmä kutsuu olion määrittelyluokanmuodostinta ja järjestys on ensin yliluokanmuodostin ja sitten aliluokan muodostin.Hajotinten suoritusjärjestys päinvastainen
Kutsutun aliohjelman etsintäluokkahierarkkiassa
Staattinen sidonta (Static binding)
Ajettavan aliohjelman valinta ja sitominen tapahtuu ohjelmankäännöksen aikana
Dynaaminen sidonta (Dynamic binding)
Ajettavan aliohjelman valinta ja sitominen tapahtuu ohjelman ajonaikana
Sidontatapaan vaikuttavat tekijät:
Olion esittely- ja määrittelyluokka
staattinen sidonta olion tunnuksen esittelyluokan perusteella
dynaaminen sidonta olion määrittelyluokan perusteella, mahdollistavain dynaamisilla olioilla
Kutsutun aliohjelman laji
staattinen sidonta tavallinen aliohjelma
dynaaminen sidonta virtuaalinen aliohjelma
Virtuaalisten metodien dynaaminen sidonta ja osoittimien käyttötoteuttavat C++ kielessä monimuotoisuuden (polymorphism),josta enemmän lisää seuraavalla luennolla
eri olioiden kykyä reagoida samaan viestiin eri tuloksella
Periytyminen vai kooste?
Periytyminen ja koostaminen samantapaisiaasioita
 Niiden välillä valitseminen joskus vaikeaa
 Nyrkkisääntöjä:
Periytä luokka B luokasta A vain silloin kunpystyt perustelemaan, että luokanB oliotvoidaan nähdä aina myös luokan A olioina.
Älä käytä periytymistä jos periytymisellä saatuolion rakenne voi muuttua ohjelman ajoaikana(käytä tällöin koostetta).
Periytyminen vai kooste?