Olio-ohjelmoinnin perusteet luento 2
description
Transcript of Olio-ohjelmoinnin perusteet luento 2
Olio-ohjelmoinnin perusteetluento 2
Päivi OvaskaLTKK/Tietotekniikan osasto
Sisältö
Yleistä olio-ohjelmoinnista Olio-ohjelmoinnin osat Luokat ja kapselointi Luokkien muodostaminen Luokkien tuhoaminen
Yleistä olio-ohjelmoinnista Olio-ohjelmointi tapa ajatella ja suunnitella ohjelma, ei
vain oliokielen kayttamista Oliokieli ei takaa olioajattelua Olio-ohjelmointi mahdollista muulla kuin oliokielella
(Yksi) ero ”perinteiseen ohjelmointiin”: Perinteinen: painopiste tietorakenteissa ja
algoritmeissa Oliot: painopiste ongelman jakamisessa
osakokonaisuuksiin, joilla omat vastuunsa ja jotka kommunikoivat keskenään
Sopii hyvin sekä top-down että bottom-up -suunnitteluun
Olennaista suunniteltavan järjestelmän käyttäytymisen ymmärtäminen
Suurten ohjelmistokokonaisuuksien hallinta Ongelman jakaminen yhden ihmisen hallittaviin
paloihin ja yksinkertaistaminen abstrahoimalla Abstraktio: Ajatustoiminta, jonka avulla jostakin
käsitteestä saadaan yleisempi käsite vähentämällä siitä tiettyjä ominaisuuksia. Myös valikointi, jossa jokin ominaisuus tai ominaisuusryhmä erotetaan muista yhteyksistään tarkastelun kohteeksi
Abstrahoida: Suorittaa abstraktio, erottaa mielessään olennainen muusta yhteydestä
Abstrakti: Abstrahoimalla saatu, puhtaasti ajatuksellinen, käsitteellinen
Esimerkki abstraktiosta
“Tiedon tallentaminen massamuistilaitteelle” Sovellusohjelmoijan ei tarvitse tuntea
kiintolevyn valmistajan käyttämää laitteen ohjauksen protokollaa, koodausta, ajoitusta ja bittien järjestystä, vaan hän voi käyttää erikseen määriteltyjä korkeamman(abstraktio) tason operaatioita (open, write, close)
Oliopohjainen logiikka Ohjelmiston ylimmän tason logiikka voidaan määritellä
olioiden rajapintojen ja olioiden välisen kommunikaation avulla
Esimerkki: Shakkinappulaolio pyytää shakkilautaa mallintavalta oliolta tietoa siitä, voiko se siirtyä
määrättyyn ruutuun. Kyselyn seurauksena lautaolio voi taas vuorostaan kysyä muilta nappuloilta niiden nykyisiä paikkoja jne.
Shakkilaudan logiikka UML sekvenssikaaviona
: s h a kkin a p p u la : s h a kkila u ta
v o iko -s iirty ä -ru u tu u n X
:n a p p u la
o le tko ru u d u s s a X
Oliot ja luokat Olio on itse vastuussa omien tietojensa käsittelystä
omien toimenpiteidensä avulla Oliot ryhmitellään luokkiin Luokka määrittelee, mitä tietoja olioilla on ja mitä
toimintoja luokan oliot osaavat Oliot suorittavat näitä toimintoja saadessaan toisilta
olioilta palvelupyyntöjä Tietojen ja toimintojen yhdistämisellä pyritään
helpottamaan ohjelmiston osien ylläpidettävyyttä ja uudelleenkäytettävyyttä
Luokat ovat uudelleenkäytettäviä komponentteja
Olio-ohjelmoinnin näkökulmat valmiiden luokkien hyödyntäminen
Valmiiden luokkien hyödyntäminen tarkoittaa luokkakirjaston käyttöä. Valmiita luokkia käyttäessään ohjelmoija voi luoda olioita luokkiin ja käyttää olioita pyytämällä niiltä palvelua. Ohjelmoijan on siis tunnettava luokkakirjaston luokkarakenne ja kunkin luokan vastuulla oleva palvelut.
uudelleenkäytettävien luokkien tuottaminen Uudelleenkäytettävien luokkien tuottaminen
tarkoittaa luokkakirjaston rakentamista ja täydentämistä. Tällöin olemassaolevia komponentteja voidaan koota valmiista testatuista komponenteista tuottamalla mahdollisimman vähän uutta ohjelmakoodia.
Oliot ja komponentit Oliokeskeinen ohjelmisto on toistensa kanssa
vuorovaikutuksessa toimivien komponenttien kokoelma.
Esim. Kokoonpanoteollisuus (autot, mikrot, viihde-elektroniikka): Tehdas ostaa komponentit ja kokoaa tuotteen valmiista komponenteista. Komponentteja hyödyntäviltä kokoajilta vaaditaan komponenttien liittämistaito ja komponentteja valmistavilta vaaditaan yksityiskohtaista tietoutta komponenttien valmistamisesta
Olio-ohjelmointia voisi kutsua tällä perusteella kokoonpano-ohjelmoinniksi!
Mitä on olio-ohjelmointi? Oliot ja niiden kommunikointi
(Objects and communication) Luokat (Classes) Kapselointi (Encapsulation) Periytyminen (Inheritance) Monimuotoisuus (Polymorfism) Geneeriset/parametrisoidut tyypit (generic or parameterized types)
Oliot ja niiden kommunikointi Olio (object) on tietojen ja palvelujen kokonaisuus. Olio on
ohjelman toteutuksen kannalta ajonaikainen keskusmuistista tehty tilanvaraus.
Viesti (message) on oliolle lähetetty pyyntö suorittaa jonkin olion vastuulla oleva palvelu.
Viesti on olioiden kommunikointitapa. Ohjelman toteutuksen kannalta viesti on olion kautta tapahtuva luokan aliohjelman kutsu.
Palvelu (service) on olion asiakasolioilleen tarjoama ja olion vastuulla oleva tehtävä. Toteutuksen kannalta palvelu on luokan aliohjelman esittely
Olio voi olla jokin tietty yritys, tuote, päivämäärä, käyttäjä, kokonaisluku jne. Oliot voivat olla siis eri abstraktiotasolla. Yhteistä olioille on se, että kullakin oliolla on vastuullaan omat tietonsa ja niiden käsittelyyn tarvittavat palvelut.
Tiedon piilotus Oliolähestysmistavassa eräs keskeinen periaate on
tiedon piilotuksen (information hiding) periaate Tämä tarkoittaa sitä, että vain olio itse voi käsitellä
omia tietojansa. Olio ei siis näe toisen olion tietoja eikä kykene niitä käsittelemään.
Tiedon piilotus mahdollistaa olion käytön komponenttina, joka on mahdollista liittää muihin komponentteihin tietämättä sen sisältöä. Ainoastaan komponentin käyttötarkoitus ja ulkoinen rajapinta on tiedettävä, jotta oliota voisi käyttää
Ulkoinen rajapinta sisältää olion palvelut.
Luokat tai tyypit Luokka (class) on olioiden tyyppi. Joissakin oliokielissä
sitä kutsutaankin tyypiksi (type) . Jokainen olio kuuluu luokkaan. Olio on luokkansa ilmentymä. Toteutuksen kannalta luokka on ohjelmoijan määrittelemä tyyppi
Attribuutti (attribute) on luokassa määriteltävä luokan olion ominaisuutta kuvaileva tieto. Toteutuksen kannalta attribuutti on luokassa määriteltävä tieto. C++ vastine tietojäsen (data member)
Palvelu (service) on luokassa esitelty luokan olioiden vastuulla oleva tehtävä. Toteutuksen kannalta palvelu on luokkaan liitetyn aliohjelman esittely.
Metodi (method) on palvelun toteutustapa. Toteutuksen kannalta metodi on luokkaan liittetty aliohjelma. C++ vastine aliohjelmajäsen (function member)
Kapselointi (Encapsulation) Kapseloinnissa yhdistetään tietotyyppin
tietorakenne ja sen toiminnot. Samalla kätketään tietotyypin sisäinen rakenne ja toimintojen toteutus.
Kapseloinnilla pakotetaan ohjelmoija käyttämän olion käsittelyssä vain sen tyyppiin kuuluvia menetelmiä.
Kapseloinnilla pienennetään muutos- ja ylläpitokustannuksia
Esimerkki tietotyypin vs. luokan käyttö Tietotyypin käyttö:Kokonaisluku muuttuja; muuttujan tilanvarausmuuttuja = 2; tyyppiin liitetyn
toimenpiteen käyttö
cout<< “Luku on: “ <<luku ; muuttujan sisältöön viittaus
Luokan käyttöPäivämäärä päivä; päivä-olion
tilanvarauspäivä = 1.1.1997; luokkaan liitetyn
palvelun käyttöpäivä.Näytä; luokkaan liitetyn
palvelun käyttö
Erilaisia olioita Kohdeoliot liittyvät kohdealueen liiketoiminnan
ilmiöihin, esim. asiakas ja tilaus Liittymäoliot huolehtivat eri järjestelmien välisestä
kommunikoinnista, esim. käyttöliittymäoliosta ikkuna ja painike
Perustieto-oliot, joita käytetään muiden luokkien koostamisessa, esim. päivämäärä
Tekniset oliot voivat olla toteutusvälineen tarjoamia apuvälineitä tai vaikkapa ajonaikaisia muiden olioiden keskusmuistiosoitteista kirjaa pitäviä tietorakenneolioita
Tietovarasto-oliot huolehtivat tietoja sisältävien pysyvien olioiden talletuksesta tietovarastoon
Ohjausoliot liittyvät tiettyyn tehtävään ja liittävät yhteen ko. tehtävässä tarvittavia olioita
Luokka Luokka (class) on ohjelmoijan määrittelemä tyyppi,
jonka avulla kapselointi toteutetaan Luokka on abstraktin tietotyypin (ADT, Abstract
data type) toteutus liittää tyyppiin kuuluvat attribuutit (tietojäsen,
data member) ja attribuutteja käsittelevät metodit (aliohjelmajäsen, function member) yhteen
Luokkien käyttöön liittyvät aiheet ovat: luokkatyypin määrittely luokkatyypin aliohjelmien toteutus luokkatyypin palveluiden käyttö olioiden avulla olioiden luonti eli tilanvaraus ja tuhoaminen eli
tilanvapautus viestin välitys oliolle
Esimerkki struct luokasta#include <iostream>using namespace std;struct Luku{
int luku;};int main(){
Luku tietue;cout<<"\nSyötä luku: ";cin>>tietue.luku;cout<<"Syöttämäsi luku on: "<<tietue.luku;return 0;
} struct-määreellä määritellyn luokan jäsenet ovat julkisia
Esimerkki class luokasta#include <iostream.h>class Luku{
int luku; //yksityinen jäsenpublic: //public määreen jäljessä on luokan julkiset palvelut
void kysy();void nayta();
};void Luku::kysy() //luokan aliohjelmajäsen, joka käsittelee
//luokan tietojäseniä{
cout<<"\nSyötä luku: ";cin>>luku;
}void Luku::nayta() //luokan aliohjelmajäsen, joka käsittelee
//luokan tietojäseniä{
cout<<"\nSyöttämäsi luku on: "<<luku;}int main(void){
Luku Olio;Olio.kysy(); Olio.nayta();return 0;
} class-määreellä määritellyn luokan jäsenet ovat oletusarvoisesti yksityisiä eli ne näkyvät vain luokan omissa
aliohjelmissa
Luku- luokkaUML luokkakaaviona
C la s s Lu k u
lu ku :in t
ky s y ():v o idn a y ta ():v o id
Luokka Luokan julkiset palvelut muodostavat luokan liittymän
(interface) luokan asiakkaisiin Luokkatyypin määrittely tarkoittaa luokan tietojäsenten ja
aliohjelmajäsenten esittelyä. Ei varaa muistia olion talletusta varten
Luokan määrittely muotoa:luokan_tyyppi luokan_nimi{tietojäsenten esittelyaliohjelmajäsenten esittely};
luokan_tyyppi class, struct, union tietojäsenet voivat olla mitä tahansa tyyppiä olevia
tietoja tai olioita aliohjelmajäsenet ovat tietojäseniä käsittelevien
aliohjelmien esittelyitä
Luokan jäsenten näkyvyys
Luokan jäsenten näkyvyyteen voidaan vaikuttaa luokkatyyppien struct ja class yhteydessä varatuilla sanoilla private, protected ja public (=saantimääreitä, access specifiers)private=yksityinenpublic=julkinen protected=suojattu, liittyy periytymiseen,
tiedot näkyvät myös aliluokissa
Luokkien nimeämiskäytännöstä Nimeämisellä huomattava vaikutus luokkien käytettävyyteen Luokan nimi: aloitetaan suurella kirjaimella Luokan tietojäsenen nimi: aloitetaan pienellä kirjaimella, jos tietojäsen on tavallinen
muuttuja ja suurella kirjaimella, jos tietojäsen edustaa oliota Luokan aliohjelman nimi: aloitetaan pienellä kirjaimella Luokan aliohjelman nimen tulisi muistuttaa aliohjelman tarjoamasta palvelusta Luokan julkiset palvelut muodostavat luokan “julkisivun”, liittymän olisi oltava
mahdollisimman edustava ja selkeä Luokan määrittely toimii samalla luokan esittelynä, mutta joskus on tarpeen esitellä
luokka ilman tietojäsenten ja aliohjelmajäsenten esittelyä (kun kaksi luokkaa sisältävät viittauksia ristikkäin toisiinsa)
class Auto;class Omistaja{
Auto* Auto_olio;char omistajannimi20;...
};class Auto{
Omistaja* Omistaja_olio;char rekisteri8;...
};
Luokan metodit ja viestit Luokan aliohjelman toteutus eli metodi:
tyyppi luokan_nimi::aliohjelman_nimi (parametrit){
aliohjelman runko}
Viestin lähettäminen luokkaan luodulle oliolle on luokan aliohjelman kutsu. Aliohjelma käsittelee sen olion tietojäseniä, jolle viesti on saapunut. Eri kutsukerroilla sama aliohjelma siis käsittelee eri olioiden tietojäseniä. Mistä aliohjelma tietää, minkä olion tietoja se käsittelee, kun aliohjelmassa viitataan tietojäseniin ilman erityistä olion tunnusta?
C++-kielessä this-osoitin sisältää viestin saaneen olion keskusmuistiosoitteen. This-osoitinta voidaan käyttää luokkaan kuuluvissa aliohjelmissa.
this-osoitin on valmiiksi esitelty:
Luokan_nimi* const this; //this-osoitin on vakio-osoitin
this-osoitin esimerkkiclass X{
int m;public:
int readm() {return this->m;} //ei välttämätöntä, return m myös ok.
Käytetään yleensä aliohjelmissa, joissa käytetään osoittimia suoraanclass dlink{
dlink* pre; //edellinendlink* suc; //seuraava
public:void append(dlink*);
.....}void dlink::append(dlink* p){
p->suc = suc;p->pre = this;suc->pre =p;suc = p;
}
Luokan käyttäminen olioiden kautta Asiakasolio lähettää palvelupyynnön eli viestin
palvelinoliolle, joka sitten suorittaa palveluun liittyvän metodin ja/tai delegoi edelleen palvelupyynnön jollekin toiselle oliolle
Asiakasoliolla on oltava tiedossaan palvelinolion tunnus, jonka se voidaan saada haltuunsa:
Palvelinolion tunnus näkyy oliolle globaalisti tai nimiarvaruutensa perusteella
palvelinolion tunnus on talletettu tietojäsenen sisällöksi
asiakasolio luo uuden palvelinolion asiakasolion aliohjelma saa palvelinolion
tunnuksen parametrina oma asiakasolioltaan (palvelupyynnön delegointi)
Esimerkki delegoinnista Henkilö-luokan olio delegoin tehtävän parametrina saadulle Osasto-oliolle#include <iostream>using namespace std;class Osasto{...public:
void Nayta();};class Henkilo{...public:
void KysyOsastolta(Osasto &);};
void Henkilo::KysysOsastolta(Osasto& Olio_osasto){ .. Olio_osasto.Nayta();
}
...int main(){
Henkilo Eka; Osasto Olio_osasto; ... Eka.KysyOsastolta(Olio_osasto);
Viestinvälityksen suunnittelu käyttäen UML sekvenssikaaviota
Esim. herätyskellon sekvenssikaavio
: O h ja u s : S o it to y ks ikko
:Us e r
p a in a _ h a ly ty s ()
lo p e ta _ s o it to ()
a lo it a _ s o it to ()
main-ohjelman rooli luokkien käyttäjänä
#include <iostream.h>#include “sovellus.hpp” int main(){
Sovellus Sovellusolio; //olion tilanvarausSovelluolio.aja(); //olion palvelupyyntöreturn 0;
}
Luokan jäsenet
class luokan_nimi{
tyypit: enum, struct, class, typedeftiedot: staticaliohjelmat: static, inline, const, virtualystävät: friend
}; Luokassa esiteltävät tietojäsenet voivat olla
oliokohtaisia tai luokkakohtaisia
Luokan oliokohtaiset tietojäsenet Olion muistinvarausluokan mukaiset tietojäsenet Käyttö: olion tilatiedot, pakolliset koostumussuhteet Elinikä: samanikäisiä kuin olion tunnus
#include <iostream>class Merkkijono{
char jono25;...
};int main(void){
Merkkijono Automaattinen;Merkkijono *Dynaaminen=new Merkkijono;...
delete Dynaaminen;return 0;
}
Luokan dynaamiset tietojäsenet Käyttö: olion tilatiedot, ehdolliset tai pakolliset koostumus- ja yhteyssuhteet Toteutustapa: osoittimet Elinikä: ohjelmoija päättää tilanvarauksen ja -vapautuksen ajankohdan
#include <iostream>class Merkkijono{
char* jono;...
};int main(void){
Merkkijono Automaattinen;Merkkijono *Dynaaminen=new Merkkijono;...delete Dynaaminen;return 0;
} Kun oliolle vartaan tila, tulee automaattisesti varatuksi osoitinmuuttujan tarvitsema
tila, mutta ei merkkijonon vaatimaa muistitilaa. Ohjelmoijan on itse tehtävätilanvaraus ja -vapautus olion dynaamisille tietojäsenille luokan aliohjelmissa. Kun olion tila vapautuu, häviää osoitinmuuttujan jono tilanvaraus automaattisesti, mutta ei jono-osoittimen osoittaman muistialueen tilanvaraus
Luokan luokkakohtaiset tiedot Käyttö: luokkaa kuvailevat tiedot, kaikki oliot voivat käyttää Elinikä: staattinen, ei riipu luokan olioiden eliniästä Toteutustapa: esittely varatulla sanalla static
#include <iostream>class Merkkijono{
char jono25;static int lkm;...
};int main(void){
Merkkijono Automaattinen;Merkkijono *Dynaaminen=new Merkkijono;...delete Dynaaminen;return 0;
}
Luokan aliohjelmajäsenet Oliokohtaisia tietoja käsittelevät aliohjelmat
muodostimet (constructor): olion alustus ja kopiointi olion tilanvarauksen yhteydessä
hajotin (destructor): olion tyhjennys ja tilanvapautus sijoitusoperaattori=: alustus tilanvarauksen jälkeen muut ohjelmoijan määrittelemät aliohjelmat inline, const, virtual
Luokkakohtaisia tietoja käsittelevät aliohjelmat: static, voidaan käyttää lisämääreitä inline ja const
class Luokka{tyyppi aliohjelma1() {...} // inline-aliohjelman runko
toteutettu suoraan esittelyn
yhteyteeninline tyyppi Luokka::aliohjelma2() //runko toteutettu
//erikseen{...}
Vakioaliohjelma ei voi muuttaa olion tietojatyyppi aliohjelma(parametrit) const;
Vakio-oliot Vakio-olion parametrina saanut aliohjelma ei voi
kutsua vakio-olion kautta muita kuin luokan vakioaliohjelmia
#include <iostream>class Henkilo...public:
char* etunimi() const; void vaihdaEtunimi(const char*);
};void aliohjelma(Henkilo& Olio1, const Henkilo& Olio2){
Olio1.vaihdaEtunimi(“Maija”);cout<<Olio2.etunimi();
}
Olion luonti eli tilanvaraus
Olion esittely liittää tunnuksen nimen olion tyyppiin eli luokkaan
Olion määrittely luo olion eli määrittely varaa keskusmuistitilan olion tiedoille
Olioiden muistinvarausluokat: Automaattinen olio on paikallinen lohkossa järjestelmä varaa oliolle keskusmuistitilan olion määrittelyn
yhteydessä pinosta järjestelmä vapauttaa oliolle varatun keskusmuistitilan
automaattisesti lohkon loppuessa esittely ja määrittely:
Luokan_nimi Olion_tunnusHenkilo Hlo_olio;
Ovat olemassa tietyn palveluketjun tai metodin suorituksen ajan
Käytetään väliaikaisina työolioina, kun käsiteltävien olioiden lukumäärä on tiedossa ohjelman kirjoitusvaiheessa ja kun olion ei tarvitse olla olemassa sen luoneen ohjelmalohkon loputtua
Olioiden muistinvarausluokat: Dynaaminen ohjelmoija varaa oliolle keskusmuistitilan new-
operaattorilla vapaasta muistista eli keosta ohjelmoija vapauttaa tilan delete-operaattorilla olioiden tilanvaraus ei häviä automaattisesti, vaan
ohjelmoijan on vapautettava tila Esittely ja määrittely erikseen:
Luokan_nimi* Olion_tunnus; //osoitinmuuttujan esittelyOlion_tunnus = new Luokan_nimi ///tilanvarausHenkilo * Hlo_olio;Hlo_olio = new Henkilo;
Esittely ja määrittely yhtäaikaisesti:Luokan_nimi* Olion_tunnus = new Luokan_nimiHenkilo* Hlo_olio=new Henkilo;
Hlo_olio on osoitinmuuttuja, joka sisältää osoitteen oliolle varatun keskusmuistialueen alkuun
tarvitaan osoittimia ja dynaamista muistinhallintaa
Olioiden muistinvarausluokat: Dynaaminen Olion tilanvapautus:
delete Olion_tunnus;void aliohjelma(void){
Henkilo Hlo_olio1;Henkilo* Hlo_olio2 = new Henkilo;static Henkilo Hlo_olio;....delete Hlo_olio2;
} Oliotaulukon vapautus:
delete Oliot;Henkilo* Oliot = new Henkilo5;...delete Oliot;
Olioiden muistinvarausluokat:Staattinen olio voi olla globaali tai static-määreellä esitelty paikallinen olio järjestelmä varaa oliolle keskusmuistitilan pääohjelman käynnistyksen
yhteydessä järjestelmä vapauttaa oliolle varatun keskusmuistitilan pääohjelman
loppuessa Esittely ja määrittely:
static Luokan_nimi Olion_tunnus;static Luokan_nimi* Olion_tunnus = new Luokan_nimi;{
static Henkilo Hlo_olio1;static Henkilo* Hlo_olio2; Hlo_olio2=new Henkilo;
} Staattiset oliot ovat olemassa koko sovelluksen käyttöajan Staattiset oliot sisältävät usein sovellukseen, palveluketjuun tai
luokkaan liitttyvää kirjanpito- tms. tietoa, jonka tulee olla käytettävissä aina
Viestin välitys oliolle Viesti on luokan aliohjelman kutsu Viestin välitys automaattiselle oliolle:
Olion_tunnus.Aliohjelman_nimi(); Viestin välitys dynaamiselle oliolle:
if (Olion_tunnus)Olion_tunnus->aliohjelman_nimi();
Henkilo Olio1;Henkilo* Olio2=new Henkilo;Olio1.kysy();Olio1.nayta();if (Olio2) Olio2->kysy();if (Olio2) Olio2->nayta();delete Olio2;
Olioiden luonti Olion luontiin liittyvät vaiheet:
olion tilanvaraus olion alustus
Olion alustus tapahtuu tilanvarauksen yhteydessä Alustus muodostin (constructor) -aliohjelmassa Muodostimia kolmenlaisia:
oletusmuodostin (default constructor) olion tietojäsenten alustus oletusarvoilla kopiointimuodostin (copy constructor) olion tietojäsenten alustus toisesta oliosta kopioimalla parametrilliset muodostimet
olion tietojäsenten alustus ohjelmoijan tapauskohtaisesti määräämillä alkuarvoilla
Luokkaan määritellään muodostimia, jotta voitaisiin varmistaa, että olion tietojäsenet ovat alustettuja ja että ohjelma ei keskeydy ajonaikaiseen virheeseen tietojäsenen sisältöön viitattaessa
Järjestelmä kutsuu muodostinta automaattisesti olion tilanvarauksen yhteydessä
Oletusmuodostin (default constructor) Järjestelmä kutsuu oletusmuodostina automaattisesti olion tilanvarauksen yhteydessä
Luokka Olio; //automaattinen muodostimen kutsuLuokka Olio = Luokka(); //ohjelmoijan mudostimen kutsuLuokka *Olio=new Luokka;LUOkka *Olio=new Luokka();
Oletusmuodostimen esittelyclass Luokka{...public:
Luokka(); //oletusmuodostin};
Oletusmuodostimen määrittely eli toteutus:Luokka::Luokka(): tietojäsenten alustukset //joko näin{
tietojäsenten alustukset //tai näinmuodostimen runko
} Tietojäsenten alustus muodostimen 1. rivillä
Luokka::Luokka(): tieto(lauseke), tieto(lauseke),...{}
tieto:alustettava tietojäsenlauseke: muuttuja, vakio tai jokin muu lauseke, jonka arvolla tietojäsen alustuu
jos alustuslauseke yksinkertainen jos alustettava tietojäsen esitelty vakioksi const jos alustettava tietojäsen on viittausmuuttuja
Esimerkki oletusmuodostimesta#include <iostream>Using namespace std;class Pvm{
int pp, kk, vv;public:
Pvm();void nayta() const;
};Pvm::Pvm() : pp(1), kk(2), vv(96){}void Pvm::nayta() const{
cout<<pp<<'/'<<kk<<'/'<<vv;}int main(void){
Pvm Paiva;Paiva.nayta();return 0;
}
2. esimerkki oletusmuodostimesta Tietojäsenten alustus muodostimen rungossa:
Luokka::Luokka(){
tieto = lauseke;...
}#include <iostream>#include <time>class Pvm{
int pp, kk, vv;public:
Pvm();void nayta() const;
};Pvm::Pvm(){
time_t sek;tm *paiva;time(&sek);paiva = localtime(&sek);pp = paiva->tm_mday;kk = paiva->tm_mon + 1;vv = paiva->tm_year;
}void Pvm::nayta() const{
cout<<pp<<'/'<<kk<<'/'<<vv;}int main(void){
Pvm Paiva;Paiva.nayta();return 0;
}
Parametrillinen muodostin Jos ohjelmoija haluaa alustaa oliot tilanvarauksen
yhteydessä tapauskohtaisilla alkuarvoilla Parametrillinen muodostin on aina ohjelmoijan
kirjoittama Samat säännöt kuin oletusmuodostimella Poikkeuksia: Parametrillisen muodostimen parametreihin voidaan
määritellä tarvittaessa myös oletusarvot Luokka voi sisältää useita erilaisilla parametreilla
varustettuja muodostimia Kääntäjä ei generoi oletusmuodostimia, jos
ohjelmoija on määritellyt luokkaan parametrillisen muodostimen
Parametrillinen muodostin esimerkki 1
#include <iostream>#include <time>class Pvm{
int pp, kk, vv;public:
Pvm(const int, const int, const int); //parametrillinen muodostinvoid nayta()const;
};Pvm::Pvm(const int p_pp, const int p_kk, const int p_vv): pp(p_pp), kk(p_kk), vv(p_vv){}void Pvm::nayta() const{
cout<<pp<<'/'<<kk<<'/'<<vv;}int main(void){
Pvm Paiva(3, 3, 96); //Paiva-olion luonti ja alustusPaiva.nayta();return 0;
}
Parametrillinen muodostin esimerkki 2
#include <iostream>class Pvm{
int pp, kk, vv;public:
Pvm(const int, const int, const int = 96);void nayta() const;
};Pvm::Pvm(const int p_pp, const int p_kk, const int p_vv){
pp = p_pp;kk = p_kk;vv = p_vv;
}void Pvm::nayta() const{
cout<<pp<<'/'<<kk<<'/'<<vv;}int main(void){
Pvm Paiva1(1, 2);Pvm Paiva2(3, 3, 97);cout<<"Päivä1: ";Paiva1 Paiva2.nayta();return 0;
Paiva2.Nayta();cout<<"\nPäivä2: ";
}
Kopiomuodostin (copy constructor) alustaa olion tietojäsenet saman luokan olemassa olevan olion tiedoilla Automaattisen olion tilanvaraus ja kopiointimuodostimen kutsu:
Luokka Uusi_olio(Vanha_olio); //Vanha_olio automaattinenLuokka Uusi_olio = Vanha_olio; // “Luokka Uusi_olio(*Vanha_olio); // Vanha_olio dynaa,omemLuokka Uusi_olio = *Vanha_olio // “
Dynaamisen olion tilanvaraus ja kopiontimuodostimen kutsu:Luokka* Uusi_olio;Uusi_olio=new Luokka (Vanha_olio);//Vanha_olio automaattinenUusi_olio=new Luokka (*Vanha_olio); //Vanha_olio dynaaminen
Pvm Paiva1(1,2,96); Pvm Paiva2(Paiva1);Pvm* Paiva3=new Pvm(Paiva1);Pvm* Paiva4=new Pbm(*Paiva3);Pvm Paiva5(*Paiva3);Pvm Paiva6=Paiva5;
Ohjelmoija voi määritellä itse kopiointimuodostimen Kopiointimuodostimen esittelytavat:
Luokka (const Luokka &);Luokka (const Luokka &, parametri = alkuarvo, …);
Kopiomuodostin (copy constructor)
#include <iostream>#include <time>class Pvm{
int pp, kk, vv;public:
Pvm(const int, const int);Pvm(const Pvm &, const int = 96);//kopiomuodostimen esittelyvoid nayta() const;
};Pvm::Pvm(const int p_pp, const int p_kk) :
pp(p_pp), kk(p_kk) {
time_t sek;tm *paiva;time(&sek);paiva = localtime(&sek);vv = paiva->tm_year;
}
}Pvm::Pvm(const Pvm &p_pvm, const int p_vv) :
pp(p_pvm.pp), kk(p_pvm.kk){
vv = p_vv;}void Pvm::nayta() const{
cout<<pp<<'/'<<kk<<'/'<<vv;}int main(void){
Pvm Paiva1(1, 2);Pvm Paiva2(Paiva1);//olion luonti kopiomuodostinta käyttäenPvm Paiva3(Paiva1, 97);cout<<"Päivä1: ";Paiva1.nayta();cout<<"\nPäivä2: ";Paiva2.nayta();cout<<"\nPäivä3: ";Paiva3.nayta();return 0;
}
Sijoitus olioon sijoitusoperaattorilla Sijoitus toimi samalla tavalla kuin kopiointimuodostin:
sijoitettavan olion tietojäsenten sisällöt kopioituvat vastaanottavan olion tietojäsenten sisällöksiPaiva1 = Paiva2;Paiva1 = *Paiva2;*Paiva1 = Paiva2;*Paiva1 = *Paiva2;Paiva3 = *Paiva2 = Paiva1;
Sijoitettavien olioiden on oltava samaa tyyppiä Kääntäjä generoi sijoitusta varten sijoitusaliohjelman Ohjelmoija voi kirjoittaa sijoitusaliohjelman itse (=
operaattorin ylikuormitus)
Sijoitusoperaattorin esittely ja sijoitusaliohjelman toteutus Sijoitusaliohjelman esittely:
class Luokka{...public:
Luokka &operator=(Luokka&);};
Sijoitusoperaattorin toteutus:Luokka &Luokka::operator=(Luokka& p_olio){sijoitukset tietojäseniin...return (*this);}
Sijoitusoperaattori esimerkki#include <iostream.h>#include <time.h>class Pvm{
int pp, kk, vv;public:
Pvm(const int, const int);Pvm(const Pvm &, const int = 96);Pvm &Pvm::operator=(const Pvm &);void Nayta() const;
};Pvm::Pvm(const int p_pp, const int p_kk) :
pp(p_pp), kk(p_kk){
time_t sek;tm *paiva;time(&sek);paiva = localtime(&sek);vv = paiva->tm_year;
}Pvm::Pvm(const Pvm &p_pvm, const int p_vv) :
pp(p_pvm.pp), kk(p_pvm.kk){
vv = p_vv;}
Pvm &Pvm::operator=(const Pvm &p_pvm){
pp = p_pvm.pp;kk = p_pvm.kk;vv = p_pvm.vv;return (*this);
}void Pvm::Nayta() const{
cout<<pp<<'/'<<kk<<'/'<<vv;}int main(void){
Pvm Paiva1(1, 2);Pvm Paiva2(1, 3);Pvm Paiva3(1, 4);Paiva3 = Paiva2 = Paiva1;cout<<"Päivä1: ";Paiva1.Nayta();cout<<"\nPäivä2: ";Paiva2.Nayta();cout<<"\nPäivä3: ";Paiva3.Nayta();return 0;
}
Sijoituksen ja kopioinnin eroista
Pvm Olio1=Pvm(1,2); //parametrillinen muodostin
Pvm Olio2; //oletusmuodostimen kutsu
Olio2=Pvm(1,2); //parametrillinen muodostin ja sijoitus
Kääntäjäympäristöt eroavat toisistaanmuodostimien kutsuissa
Olion tietojäsenten tyhjennys ja hajoitin Olion tuhoamiseen littyvät vaiheet:
olion tyhjennys olion tilanvapautus
Hajottimen tarkoituksena on tyhjentää olion tietojäsenet ja vapauttaa olion sisäiset rakenteet
Järjestelmä kutsuu hajotinta olion tilanvapautuksen yhteydessä automaattisesti
voidaan kutsua ohjelmallisesti myös ennen tilanvapautusta, kun olio halutaan väliaiakaisesti tyhjentää
Hajotin Hajottimen nimi on ~Luokan_nimi Hajotin ei saa parametreja Hajottimella ei ole tyyppiä, ei saa palauttaa mitään arvoa Esittelyssä ei saa esiintyä varattuja sanoja const, volatile tai static Hajotin voi olla virtuaalinen (liittyy periytymiseen) Hajottimen kutsu:
Olio.Luokka:: ~Luokka();Olio->Luokka:: ~Luokka();
Hajottimen esittely:class Luokka...public:
~Luokka();};
Hajottimen määrittely:Luokka:: ~Luokka(){
tietojäsenten tyhjennys}
Hajotin esimerkki#include <iostream.h>#include <time.h>class Pvm{
int pp, kk, vv;public:
Pvm(const int, const int);Pvm(const Pvm &, const int = 96);Pvm &Pvm::operator=(const Pvm &);~Pvm();void Nayta() const;
};Pvm::Pvm(const int p_pp, const int p_kk) : pp(p_pp),
kk(p_kk){
time_t sek;tm *paiva;time(&sek);paiva = localtime(&sek);vv = paiva->tm_year;
}Pvm::Pvm(const Pvm &p_pvm, const int p_vv) :
pp(p_pvm.pp), kk(p_pvm.kk){
vv = p_vv;}Pvm &Pvm::operator=(const Pvm &p_pvm){
pp = p_pvm.pp;kk = p_pvm.kk;vv = p_pvm.vv;return (*this);
}
Pvm::~Pvm(){
pp = 0;kk = 0;vv = 0;
}void Pvm::nayta() const{
cout<<pp<<'/'<<kk<<'/'<<vv;}int main(void){
cout<<"Päivä1: ";Pvm Paiva1(1, 2);Paiva1.Pvm::~Pvm();Paiva1.nayta();
cout<<"\nPäivä2: ";Pvm *Paiva2 = new Pvm(2, 2);Paiva2->Pvm::~Pvm();Paiva2->nayta();delete Paiva2;return 0;
}