Olio ohjelmoinnin perusteet luento 5 rajapinnoista perinn n huomioon ottamisesesta
Download
1 / 96

- PowerPoint PPT Presentation


  • 88 Views
  • Uploaded on

Olio-ohjelmoinnin perusteet luento 5: Rajapinnoista, perinnän huomioon ottamisesesta. Sami Jantunen LTY/Tietotekniikan osasto. Sisältö. Rajapinnoista Esimerkki Abstrakti luokka Puhdas virtuaalinen funktio Rajapinnan käytöstä Komponentteihin jaottelusta

loader
I am the owner, or an agent authorized to act on behalf of the owner, of the copyrighted work described.
capcha
Download Presentation

PowerPoint Slideshow about '' - karlyn


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.While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server.


- - - - - - - - - - - - - - - - - - - - - - - - - - E N D - - - - - - - - - - - - - - - - - - - - - - - - - -
Presentation Transcript
Olio ohjelmoinnin perusteet luento 5 rajapinnoista perinn n huomioon ottamisesesta

Olio-ohjelmoinnin perusteetluento 5: Rajapinnoista, perinnän huomioon ottamisesesta

Sami Jantunen

LTY/Tietotekniikan osasto


Sis lt
Sisältö

  • Rajapinnoista

    • Esimerkki

    • Abstrakti luokka

    • Puhdas virtuaalinen funktio

    • Rajapinnan käytöstä

    • Komponentteihin jaottelusta

  • Perinnän vaikutus olion luontiin ja tuhoamiseen

    • Rakentajat ja perintä

    • Purkajat ja perintä

  • Perityn luokan eri tyypit

    • Aliluokan ja kantaluokan suhde

    • Tyyppimuunnokset

  • Olioiden sijoitus ja kopiointi

    • Olioiden kopiointi

    • Olioiden sijoitus

  • Yhteenveto

    • Puhdasoppinen luokka

    • Kertaus


Tarina
Tarina…

  • Kauan aikaa sitten työskentelin erään palvelimen parissa

  • Palvelimen oli tarkoitus pystyä kommunikoimaan lukuisten erilaisten asiakasohjelmien kanssa


Tarina jatkuu
Tarina jatkuu….

  • Palvelimen ja asiakasohjelmien väliseksi kommunikointitavaksi valittiin 2-suuntainen putki


Tarina jatkuu1
Tarina jatkuu….

  • Pian huomasin, että 2-suuntaisen putken käyttö ei ollut ihan helppoa

    • 2-suuntaisen liikenteen hallinta vaati synkronointitaitoja

    • Putkesta “tipoittain” lukeminen tukkeutti putken

    • Putkia piti tarjota sitä mukaan kun asiakasohjelmat ottivat palvelimeen yhteyttä Säikeistyksen hallinta

    • Kaikki asiakasohjelmat eivät olleet tiedossa ja niitä tehtiin muiden henkilöiden voimin.kommunikointimekanismi ei saa olla sen käyttäjälle vaikeaa!


Tarina jatkuu2
Tarina jatkuu…

  • Niinpä ajattelin soveltaa yhtä olioajattelun perusajatuksista: Tiedon piilottamista

    Loin kirjaston, joka piilotti putken monimutkaisuuden (synkronointi, säikeiden hallinta, viestien puskurointi, ym.)


Tarina jatkuu3
Tarina jatkuu….

  • Ja sen putken käyttö oli niin mukavaa…

    • Viis hankalista hallinnoitiasioista.

    • Riitti kun avaa ja lähettää….

PipeServer

create()

send()

disconnect()

getNumberOfClients()

PipeClient

open()

send()

disconnect()


Tarina jatkuu4
Tarina jatkuu…

  • Entäpä viestin vastaanottaminen?

    • Olisipa mukavaa kun putki osaisi itse kutsua asiakkaan messageArrived –funktiota kun viesti on saapunut

    • Ainoa asia mitä asiakkaan tarvitsisi tehdä on toteuttaa messageArrived funktio, mihin määriteltäisiin viestin saapumisesta aiheutuva toimintalogiikka.


Ja sitten tarinan kysymys
Ja sitten tarinan kysymys!

Mistä putkikirjasto voi tietää ketä kutsua kun viesti saapuu???


Ratkaisu
Ratkaisu?

  • Mitä jos kukin putkea käyttävä olio esittelee itsensä ja antaa osoittimen itseensä.

    • Putki voisi sitten jatkossa vain käyttää osoitinta ja kutsua sen avulla käyttäjäolion messageArrived-funktiota


Taustatietoa
Taustatietoa

  • Jokaisella oliolla on olemassa osoitinmuuttuja this, mikä osoittaa itseensä

  • this –osoitin on aina samaa tyyppiä kun siihen liittyvä osoitinkin aivan kun this olisi määritelty luokassa tyyliin: MyClass *this;

This


L hdet n ratkaisemaan ongelmaa
Lähdetään ratkaisemaan ongelmaa

  • Oletetaan että putkea käyttävä olio identifioi itsensä kun se avaa putken:

    PipeClient _myPipe;

    _myPipe.open(this);

  • Nyt putki tietää sitä käyttävän olion osoitteen.

    Ratkaisiko tämä meidän ongelman?


Viel ongelmia
Vielä ongelmia

  • Okei, nyt sitten tiedetään putkea käyttävän olion osoite. Se ei kuitenkaan riitä

  • Mistä ihmeestä putkikirjasto tietää minkä tyyppinen annettu osoitin on?

    • Eihän se muuten voi kutsua annettua oliota


Heureka
Heureka!

  • Mitäs jos vaadittaisiin, että kaikki putken käyttäjäluokat periytyvät MessageReader-luokasta

    • Silloinhan tiedettäisiin, että asiakkaat ovat aina myös tyyppiä MessageReader!

    • putkikirjastoon voitaisiin siis kirjoittaa seuraava koodipätkä:

      //Luokan määrittelyssäMessageReader *_addressOfClient;...//Putkea avattaessaPipeClient::open(MessageReader *client){ _addressOfClient=client;}...//jossain päin missä luetaan putkea_addressOfClient->messageArrived();


Mit taas tuli tehty
Mitä taas tuli tehtyä?

  • Loimme luokan (MessageReader), joka ei itse tee yhtään mitään.

  • Tämähän on ihan selvä rajapintaluokka!

  • Ne luokat jotka haluavat tarjota rajapintaluokan määrittelemiä palveluita perivät itsensä rajapintaluokasta

MessageReader

virtual void messageArrived(CArchive *message) = 0;

PipeUser

PipeClient *myPipe


Rajapintaluokista
Rajapintaluokista

  • Rajapintaluokat ovat yleensä abstrakteja luokkia

    • Eivät sisällä mitään muuta kuin rajapinnan määrittelyjä

    • Ei siis jäsenmuuttujia eikä jäsenfunktioiden toteutuksia

  • Jossain oliokielissä (kuten Java) tällaisille puhtaille rajapinnoille on oma syntaksinsa eikä niitä silloin varsinaisesti laskeata edes luokiksi


Abstrakti luokka
Abstrakti luokka

  • Mikä hyvänsä luokka, jossa on yksi tai useampi puhdas virtuaalifunktio, on abstrakti luokka eikä sen tyyppisiä olioita voi käyttää.

  • Puhdas virtuaalifunktio kertoo luokan käyttäjälle kaksi asiaa:

    • Luokan tyyppistä oliota ei voida luoda vaan siitä pitää periyttää aliluokkia

    • Jokainen puhdas virtuaalifunktio pitää korvata uudella funktiolla abstraktista luokasta periytetyssä luokassa


Puhdas virtuaalifunktio
Puhdas virtuaalifunktio

  • Abstrakti luokka tehdään käyttämällä puhtaita virtuaalifunktioita (pure virtual function)

    • Virtuaalifunktio on puhdas, jos se alustetaan nollalla, esimerkiksi:virtual void Piirra () = 0;


Puhtaan virtuaalifunktion ohjelmointi
Puhtaan virtuaalifunktion ohjelmointi

  • Yleensä abstraktissa kantaluokassa olevalle puhtaalle virtuaalifunktiolle ei kirjoiteta funktion määrittelyä

    • Koska luokan tyyppisiä olioita ei voida koskaan luoda, niin ei ole mitään syytä ohjelmoida luokkan mitään toiminnallisuuttakaan.

    • Abstrakti luokka on siitä periytetyille luokille yhteinen käyttörajapinta

  • On toki mahdollista tehdä kantaluokkaan puhtaalle virtuaalifunktiolle toteutus

    • Sitä kutsutaan silloin lapsiluokista käsin.

    • Esim. se toiminnallisuus, joka on yhteistä kaikille lapsille siirretään kantaluokkaan.


Milloin kannattaa k ytt abstrakteja luokkia
Milloin kannattaa käyttää abstrakteja luokkia?

  • Ei yksiselitteistä vastausta

  • Päätös tehtävä sen perusteella onko luokan abstraktisuudesta jotain hyötyä

    • Esimerkki: Eläin-luokka kannattaa olla abstrakti, mutta Koira-luokka ei, jotta ohjelmassa voidaan käyttää koira-olioita

    • Toisaalta: Jos ohjelmassa simuloidaan kenneliä, koira-luokka kannattaa jättää abstraktista ja periyttää siitä erirotuisia koiria.

      Käytettävä abstraktiotaso määräytyy sen mukaan, kuinka hienojakoisesti ohjelman luokat pitää erotella toisistaan


Muistatko viel moniperint k ytt kohteita
Muistatko viel?Moniperintä -käyttökohteita

  • Rajapintojen yhdistäminen.

    • Halutaan oman luokan toteuttavan useiden eri rajapintojen toiminnallisuus

  • Luokkien yhdistäminen.

    • Halutaan esimerkiksi käyttää hyväksi muutamaa yleiskäyttöistä luokkaa oman luokan kehitystyössä.

  • Luokkien koostaminen valmiista ominaisuuskokoelmista. Esimerkki:

    • Kaikki lainaamiseen liittyvät toiminnot on kirjoitettu Lainattava-luokkaan.

    • Vastaavasti kaikki tuotteen myymiseen liittyvät aisat ovat luokassa Myytävät.

    • Voimme luoda KirjastonKirja –luokan perimällä sen Kirja-kantaluokasta ja maustamalla sen Lainattava-luokasta saaduilla ominaisuuksilla

    • Voimme yhtä lailla luoda KaupallinenCD-ROM-luokan perimällä sen CD-ROM kantaluokasta ja ottaa käyttöön ominaisuudet Myytävä-luokasta


Rajapintaluokat ja moniperiytyminen
Rajapintaluokat ja moniperiytyminen

  • Jos abstraktit kantaluokat sisältävät ainoastaan puhtaita virtuaalifunktioita

    • Moniperiytymisen käytöstä ei aiheudu yleensä ongelmia.

  • Jos moniperiytymisessä kantaluokat sen sijaan sisältävät myös rajapintojen toteutuksia ja jäsenmuuttujia

    • Moniperiytyminen aiheuttaa yleensä enemmän ongelmia kuin ratkaisee.


Rajapinnoista
Rajapinnoista

  • Rajapintojen käyttö ja toteutuksen kätkentä on yksi ehkä tärkeimmistä ohjelmistotuotannon perusperiaatteista

    • Tästä huolimatta sen tärkeyden perustelu uraansa aloittelevalle ohjelmistoammattilaiselle on vaikeaa

    • Merkityksen tajuaa yleensä itsestäänselvyytenä sen jälkeen, kun on osallistunut tekemään niin isoa ohjelmistoa, ettei sen sisäistä toteutusta pysty kerralla hallitsemaan ja ymmärtämään yksikään ihminen.


Komponentteihin jaottelusta
Komponentteihin jaottelusta

  • Isoissa ohjelmissa komponenttijako helpottaa huomattavasti kehitystyötä.

    • Yksittäinen ohjelmoijan ei enää tarvitse jatkuvasti hahmottaa kokonaisuutta

    • Kehittäjä voi enemmän keskittyä oman komponenttiensa vastuiden toteutukseen.


Miss menn n
Missä mennään?

  • Rajapinnoista

    • Esimerkki

    • Abstrakti luokka

    • Puhdas virtuaalinen funktio

    • Rajapinnan käytöstä

    • Komponentteihin jaottelusta

  • Perinnän vaikutus olion luontiin ja tuhoamiseen

    • Rakentajat ja perintä

    • Purkajat ja perintä

  • Perityn luokan eri tyypit

    • Aliluokan ja kantaluokan suhde

    • Tyyppimuunnokset

  • Olioiden sijoitus ja kopiointi

    • Olioiden kopiointi

    • Olioiden sijoitus

  • Yhteenveto

    • Puhdasoppinen luokka

    • Kertaus


S muistatko viel rakentajien k ytt perinn n yhteydess
Sä muistatko viel? Rakentajien käyttö perinnän yhteydessä

Isäluokan rakentajaa kutsutaan aina!*

CPoodle.cpp

CPoodle::CPoodle(int x, char y[ ]) : CDog (x,y)

{

cout << “Tuli muuten tehtyä puudeli" << endl;

}

Normaalia rakentaja tavaraa

Luokkia perittäessä on rakentajien ja purkajien käytössä on paljon huomioitavaa


Periytyminen ja rakentajat
Periytyminen ja rakentajat

  • Jokainen aliluokan olio koostuu kantaluokkaosasta (tai osista) sekä aliluokan lisäämistä laajennuksista

     Aliluokalla on oltava oma rakentajansa.

    • Mutta miten pitäisi hoitaa kantaluokkien alustus?

Mammal

int weight

giveBirth( )

Land-Mammal

int numLegs

Dog

boolean rabid

SheepDog


Periytyminen ja rakentajat vastuut
Periytyminen ja rakentajatVastuut

  • Aliluokan vastuulla on:

    • Aliluokan mukanaan tuomien uusien jäsenmuuttujien ja muiden tietorakenteiden alustaminen.

    • Em. vastuita varten aliluokkiin toteutetaan oma(t) rakentaja(t)

  • Kantaluokan vastuulla on:

    • Pitää huoli siitä, että aliluokan olion kantaluokkaosa tulee alustetuksei oikein, aivan kun se olisi irrallinen kantaluokan olio

    • Tämän alustuksen hoitavat aivan normaalit kantaluokan rakentajat


Periytyminen ja rakentajat parametrit
Periytyminen ja rakentajatParametrit?

  • Miten taataan että kaikki rakentajat saavat tarvitsemansa parametrit?

    • Päivänselvää aliluokalle. Sitä luodessahan kutsutaan aliluokan itse määrittelemiä rakentajia

    • Kantaluokan parametrien saannin takaamiseksi C++:n tarjoama ratkaisu on, että aliluokan rakentajan alustuslistassa kutsutaan kantaluokan rakentajaa ja välitetään sille tarvittavat parametrit

CPoodle.cpp

CPoodle::CPoodle(int x, char y[ ]) : CDog (x,y)

{

cout << “Tuli muuten tehtyä puudeli" << endl;

}


Ent jos
Entä jos?

  • Jos aliluokan rakentajan alustuslistassa ei kutsuta mitään kantaluokan rakentajaa:

    • Kääntäjä kutsuu automaattisesti kantaluokan oletusrakentajaa (joka ei siis tarvitse parametreja)

    • Tällainen ratkaisu harvemmin johtaa toivottuun tulokseen

      Muista siis kutsua aliluokan rakentajassa kantaluokan rakentajaa itse!


Rakentajien suoritusj rjestys
Rakentajien suoritusjärjestys

  • Huipusta alaspäin

  • Olio ikäänkuin rakentuu vähitellen laajemmaksi ja laajemmaksi.

  • Näin taataan se, että aliluokan rakentaja voi jo turvallisesti käyttää kantaluokan jäsenfunktioita.


Periytyminen ja purkajat
Periytyminen ja purkajat

  • Alustamisen tapaan myös olion siivoustoimenpiteet vaativat erikoiskohtelua luokan “kerrosrakenteen” vuoksi

    • Purkajien vastuut jaettu samalla lailla kuin rakentajienkin

    • Kantaluokan tehtävänä on siivota kantaluokkaolio sellaiseen kuntoon, että se voi rauhassa tuhoutua

    • Aliluokat puolestaan siivoavat periytymisessä lisätyt laajennusosat tuhoamiskuntoon


Purkajien suoritusj rjestys
Purkajien suoritusjärjestys

  • Purkajia kutsutaan päinvastaisessa järjestyksessä kuin rakentajia

    • Ensin kutsutaan aliluokan purkajia ja siitä siirrytään perintähierakiassa ylöspäin

    • Näin varmistetaan se, että aliluokan purkajassa voidaan vielä kutsua kantaluokkien toiminnallisuutta


Esimerkki
Esimerkki

Jotain pahasti pielessä!

-Mitä?

  • Mammal *myMammal;

  • myMammal = new SheepDog();

  • ...

  • //koodia missä käytetään SheepDog-luokkaa

  • ...

  • delete myMammal;

Mammal

int weight

giveBirth( )

Land-Mammal

int numLegs

Dog

boolean rabid

SheepDog


Esimerkki1
Esimerkki

  • Vain kantaluokka tuhoutuu!

    Kuinka korjata tilanne?

  • Mammal *myMammal;

  • myMammal = new SheepDog();

  • ...

  • //koodia missä käytetään SheepDog-luokkaa

  • ...

  • delete myMammal;

Mammal

int weight

giveBirth( )

Land-Mammal

int numLegs

Dog

boolean rabid

SheepDog


Virtuaalipurkaja
Virtuaalipurkaja

  • Jos luokasta peritään muita luokkia, muista aina määritellä purkaja virtuaaliseksi!

  • Ei haittaa vaikka purkaja on eri niminen lapsiluokassa.


Miss menn n1
Missä mennään?

  • Rajapinnoista

    • Esimerkki

    • Abstrakti luokka

    • Puhdas virtuaalinen funktio

    • Rajapinnan käytöstä

    • Komponentteihin jaottelusta

  • Perinnän vaikutus olion luontiin ja tuhoamiseen

    • Rakentajat ja perintä

    • Purkajat ja perintä

  • Perityn luokan eri tyypit

    • Aliluokan ja kantaluokan suhde

    • Tyyppimuunnokset

  • Olioiden sijoitus ja kopiointi

    • Olioiden kopiointi

    • Olioiden sijoitus

  • Yhteenveto

    • Puhdasoppinen luokka

    • Kertaus


Aliluokan ja kantaluokan suhde
Aliluokan ja kantaluokan suhde

  • Aliluokka tarjoaa kaikki ne palvelut mitä kantaluokkakin (+ vähän lisää omia ominaisuuksia)

    • Periytymisessähän vaan lisätään ominaisuuksia

    • Aliluokkaa voi siis käyttää kantaluokan sijasta missä päin hyvänsä koodia


Aliluokan ja kantaluokan suhde1
Aliluokan ja kantaluokan suhde

  • Voidaan siis ajatella, että aliluokan olio on tyypiltään myös kantaluokan olio!

  • Aliluokan oliot kuuluvat ikään kuin useaan luokaaan:

    • Aliluokkaan itseensä

    • Kantaluokkaan

    • Kantaluokan kantaluokkaan, jne

  • Tämä is-a suhde tulisi pitää mielessä aina kun periytymistä käytetään!

  • Jos aliluokka on muuttunut vastuualueeltaan niin paljon, että se ei enää ole kantaluokan mukainen, periytymistä on ilmeisesti käytetty väärin


Aliluokan ja kantaluokan suhde2
Aliluokan ja kantaluokan suhde

  • C++:ssa aliluokan olio kelpaa kaikkialle minne kantaluokan oliokin.

  • Kantaluokan osoittimen tai viitteen voi laittaa osoittamaan myös aliluokan olioon:

    class Kantaluokka {…};

    class Aliluokka : public Kantaluokka {…};

    void funktio (Kantaluokka& kantaolio);

    Kantaluokka *k_p =0;

    Aliluokka aliolio;

    k_p = &aliolio;

    funktio(aliolio);


Olion tyypin ajonaikainen tarkastaminen
Olion tyypin ajonaikainen tarkastaminen

  • Kantaluokkaosoittimen päässä olevalle oliolle voi kutsua vain kantaluokan rajapinnassa olevia funktioita

    • Ei auta vaikka osoittimen päässä todellisuudessa olisikin aliluokan olio.

    • Normaalisti kantaluokan rajapinnan käyttö onkin aivan riittävää

    • Joskus tulee kuitenkin tarve päästä käsiksi aliluokan rajanpintaan.


Olion tyypin ajonaikainen tarkastaminen1
Olion tyypin ajonaikainen tarkastaminen

  • Jos aliluokan olio on kantaluokkaosoittimen päässä ei aliluokan rajapinta ole siis näkyvissä

    • Ainoa vaihtoehto on luoda uusi osoitin aliluokkaan ja laittaa se osoittamaan kantaluokkaosoittimen päässä olevaan olioon


Tyyppimuunnokset type cast
Tyyppimuunnokset (type cast)

  • Tyyppimuunnos on operaatio, jota ohjelmoinnissa tarvitaan, kun käsiteltävä tieto ei ole jotain operaatiota varten oikean tyyppistä

  • Tyyppimuunnos on terminä hieman harhaanjohtava

    • tyyppiä ei oikeastaan muuteta vaan luodaan pikemminkin uusi arvo haluttua tyyppiä, joka vastaa vanhaa arvoa

    • Tyyppimuunnos muistuttaa tässä suhteessa suuresti kopiointia. Erona on vaan se, että uusi ja vanha olio on kopioinnista poiketen eri tyyppiä


C tyyppimuunnosoperaattorit
C++ tyyppimuunnosoperaattorit

  • Vanha C-kielinen tyyppimuunnos:(uusiTyyppi)vanhaArvo

    • sulkujen sijainti hieman epälooginen

  • C++ kielessä mahdollista myös: uusiTyyppi(vanhaArvo)


Ongelmia tyyppimuunnosten kanssa
Ongelmia tyyppimuunnosten kanssa

  • Tyyppimuunnoksia voidaan käyttää suorittamaan kaikenlaisia muunnoksia. Esim:

    • kokonasiluvuista liukuluvuiksi

    • olio-osoittimista kokonaisluvuiksi

  • Kaikki tyyppimuunnokset eivät ole järkeviä!

  • Kääntäjä ei tarkista tyyppimuunnosten järkevyyttä

    • Kääntäjä luottaa täysin ohjelmoijan omaan harkintaan

  • Tyyppimuunnoksiin jää helposti kirjoitusvirheitä

  • Tyyppimuunnosvirheitä on vaikea löytää


Parannellut tyyppimuunnosoperaattorit
Parannellut tyyppimuunnosoperaattorit

  • Parannellut tyyppimuunnosoperaattorit ovat:

    • static_cast<uusiTyyppi>(vanhaArvo)

    • const_cast<uusiTyyppi>(vanhaArvo)

    • dynamic_cast<uusiTyyppi>(vanhaArvo)

    • reinterpret_cast<uusiTyyppi>(vanhaArvo)

  • Yhteensopivia mallien käyttämän syntaksin kanssa (malleista puhutaan myöhemmin)

  • Kukin operaattoreista on tarkoitettu vain tietynlaisen mielekkään muunnoksen tekemiseen

    • kääntäjä antaa virheilmoituksen jos niitä yritetään käyttää väärin.

  • Vanhat tavat tehdä tyyppimuunnokset ovat yhteensopivuuden takia edelleen käytettävissä

    • vältä niiden käyttöä ja suosi uusia operaattoreita


Static cast
static_cast

  • Suorittaa tyyppimuunnoksia, joiden mielekkyydestä kääntäjä voi varmistua jo käännösaikana.

  • Esimerkkejä:

    • muunnokset eri kokonaislukutyyppien välillä

    • muunnokset enum-luettelotyypeistä kokonaisluvuiksi ja takaisin

    • muunnokset kokonaislukutyyppien ja likulukutyyppien välillä

  • Käyttöesimerkki. Lasketaan kahden kokonaisluvun keskiarvo liukulukuna:double ka = (static_cast<double>(i1) + static_cast<double>(i2))/ 2.0;


Static cast1
static_cast

  • static_cast ei suostu suorittamaan sellaisia muunnoksia, jotka ei ole mielekkäitä. Esimerkki:Paivays* pvmp = new Paivays();int* ip = static_cast<int*>(pvmp); //KÄÄNNÖSVIRHE!

  • static_cast:ia voidaan käyttää myös osoittimen tyyppimuutokseen

    • muunnoksen mielekkyyttä ei tällaisessa tapauksessa testata ajon aikana

    • Pitää olla itse varma, että kantaluokkaosoittimen päässä on varmasti aliluokan olio

    • dynamic_cast:n käytto olisi turvallisempaa!

    • static_cast on nopeampi kuin dynamic_cast


Const cast
const_cast

  • joskus const-sanan käyttö tuo ongelmia

  • const_cast tarjoaa mahdollisuuden poistaa const-sanan vaikutuksen

    • voi tehdä vakio-osoittimesta ja –viitteestä ei-vakio-osoittimen tai –viitteen

  • const_cast-muunnoksen käyttö rikkoo C++ “vakiota ei voi muuttaa” periaatetta vastaan.

    • sen käyttö osoittaa että jokin osa ohjelmasta on suunniteltu huonosti

    • Pyri pikemminkin korjaamaan varsinainen ongelma kuin käyttämään const_cast:ia


Dynamic cast
dynamic_cast

  • Muunnos kantaluokkaosoittimesta aliluokkaosoittimeksi onnistuuu tyyppimuunnoksella:dynamic_cast<Aliluokka*>(kluokkaosoitin)

  • Muunnoksen toiminta on kaksivaiheinen:

    • Ensin tarkastetaan, että kantaluokkaosoittimen päässä oleva olio todella on aliluokan olio.

    • Jos kantaluokkaosoittimen päässä on väärän tyyppinen olio, palautetaan tyhjä osoitin 0.

    • Jos kantaluokkaosoittimen päässä on okean tyyppinen olio, palautetaan kyseiseen olioon osoittava aliluokkaosoitin.


Kantaluokkaosoittimesta aliluokkaosoittimeksi
Kantaluokkaosoittimesta aliluokkaosoittimeksi

  • dynamic_cast –muunnosta voi käyttää myös olioviitteisiin (siis tuottamaan aliluokkaviitteen)

  • Ainoa ero osoitinmuunnokseen on se, että jos kantaluokkaviitteen päässä on väärän tyyppinen olio, dynamic_cast hiettää poikkeuksen (std::bad_cast)

    • Miksi näin?

    • Puhumme poikkeuksista lisää seuraavilla luennoilla!


Dynamic cast esimerkki
dynamic_cast esimerkki

bool myohassako(Kirja* kp, const Paivays& tanaan)

{

KirjastonKirja* kpp = dynamic_cast<KirjastonKirja*>(kp);

if(kkp != 0)

{ //jos tultiin tänne, kirja on kirjastonkirja

return kkp->onkoMyohassa(tanaan);

}

else

{ //jos tultiin tänne, kirja ei ole kirjastonkirja

return false;

}

}


Reinterpret cast
reinterpret_cast

  • Joskus joudutaan käsittelemään tietoa tavalla, joka ei ole sen todellisen tyypin mukainen

    • Esim. osoitinta voi joskus joutua käsittelemään muistiosoitteena (=kokonaislukuna)

  • reinterpret_cast:ia käytetään tiedon esitystavan muuttamiseen.

  • Muunnoksen lähes ainoa käyttökohde on muuttaa tieto ensin toisentyyppiseksi ja myöhemmin takaisin.


Reinterpret cast1
reinterpret_cast

  • sallitut käyttökohteet:

    • Osoittimen muunto kokonaisluvuksi, jos kokonaislukutyyppi on niin suuri, että osoitin mahtuu siihen

    • Kokonaisluvun muuntaminen takaisin osoittimeksi

    • Osoittimen muunto toisentyyppiseksi osoittimeksi

    • Viitteen muunto toisentyyppiseksi viitteeksi

    • Funktio-osoittimen muunto toisentyyppiseksi funktio-osoittimeksi.


Reinterpret cast k ytt esimerkki
reinterpret_cast käyttöesimerkki

void luoKayttoliittyma(KirjastonKirja *kirja1, KirjastonKirja* kirja2)

{

luoNappula(“Kirja1”, reinterpret_cast<unsigned long int>(kirja1));

luoNappula(“Kirja2”, reinterpret_cast<unsigned long int>(kirja2));

}

//tätä funktiota kutsutaan kun nappulaa painetaan

void nappulaaPainettu(unsigned long int luku)

{

KirjastonKirja* kp = reinterpret_cast<KirjastonKirja*>(luku);

cout << “Painettu kirjan “ << kp->annaNimi() << “ nappia.” << endl;

}


Miss menn n2
Missä mennään?

  • Rajapinnoista

    • Esimerkki

    • Abstrakti luokka

    • Puhdas virtuaalinen funktio

    • Rajapinnan käytöstä

    • Komponentteihin jaottelusta

  • Perinnän vaikutus olion luontiin ja tuhoamiseen

    • Rakentajat ja perintä

    • Purkajat ja perintä

  • Perityn luokan eri tyypit

    • Aliluokan ja kantaluokan suhde

    • Tyyppimuunnokset

  • Olioiden sijoitus ja kopiointi

    • Olioiden kopiointi

    • Olioiden sijoitus

  • Yhteenveto

    • Puhdasoppinen luokka

    • Kertaus


Olioiden kopiointi
Olioiden kopiointi

  • Olio-ohjelmoinnissa sijoituksen ja kopioinnin merkitys ei ole yhtä selvä kuin perinteisessä ohjelmoinnissa

  • C++:ssa varsinkin kopioinnin merkitys korostuu entisestään, koska kääntäjä itse tarvitsee olioiden kopiointia:

    • välittäessään olioita tavallisina arvoparametreina

    • palauttaessaan olioita paluuarvoina


Olioiden kopioinnista
Olioiden kopioinnista

  • Kopioidun olion määritelmä:

    • Uuden ja vanhan olion arvojen tai tilojen täytyy olla samat.

  • Eri tyyppisiä olioita kopioidaan hyvin eri tavalla

    • Kompleksiluokuolion kopiointiin voi riittää yksinkertainen muistin kopiointi

    • Merkkijonon kopiointi puolestaan saattaa vaatia ylimääräistä muistinvarausta ja muita toimenpiteitä


Olioiden kopioinnista1
Olioiden kopioinnista

  • Yleensä kääntäjä ei pysty automattisesti kopioimaan olioita hyväksyttävällä tavalla, vaan luokan tekijän tulisi itse määritellä mitä kaikkea olioita kopioitaessa täytyy tehdä.

  • Kaikkia olioita ei ole järkevää kopioida

    • (esim. hiissin moottoria ohjaavan olion kopiointi. kopiointi vaatisi myös fyysisen moottorin kopiointia).

    • Tulisi olla mahdollista myös estää luokan olioiden kopiointi kokonaan


Erilaiset kopiointitavat
Erilaiset kopiointitavat

  • Olioiden kopiointitavat jaotellaan usein seuraavasti:

    • Viitekopiointi

    • Matalakopiointi

    • Syväkopiointi

  • Voi olla kuitenkin tarve kopioida osa olioista yhdellä tavalla ja toisia osia toisella


Viitekopiointi reference copy
Viitekopiointi (Reference copy)

  • Kaikkein helpoin kopiointitavoista.

  • Ei luoda ollenkaan uutta oliota vaan uutta oliota kuvastaa viite vanhaan olioon.


Viitekopionti esimerkki
ViitekopiontiEsimerkki

MUISTI:

Alkuperainen

Olio

Viitekopio


Viitekopiointi
Viitekopiointi

  • Käytetään etenkin oliokielissä, missä itse muuttujat ovat aina vain viitteitä olioihin, jotka puolestaan luodaan dynaamisesti (esim. Java ja Smalltalk)

  • C++:ssa viitekopiointia käytetään vain, kun erikseen luodaan viitteitä olioiden sijaan.

  • Viitekopioinnin etu on sen nopeus.

    • “Kopion” luominen ei käytännössä vaadi ollenkaan aikaa

    • Mitään kopioimista ei tarvitse oikeastaan tehdä

  • Viitekopiointi toimii hyvin niin kauan kun olion arvoa ei muuteta.

    • Jos olion arvoa muutetaan, arvo kopiossakin muuttuu.


Matalakopiointi shallow copy
Matalakopiointi (shallow copy)

  • Matalakopioinnissa itse oliosta ja sen jäsenmuuttujista tehdään kopiot

  • Jos jäsenmuuttujina on viitteitä tai osoittimia olion ulkopuolisiin tietorakenteisiin, ei näitä tietorakenteita kopoida.

    • matalakopioinnin lopputuloksena molemmat oliot jakavat samat olioiden ulkopuoliset tietorakenteet.


Matalakopio esimerkki
MatalakopioEsimerkki

Alkuperainen

Olio

MUISTI:

Alkuperaisen

olion ulkoiset

tietorakenteet

Matalakopio


Matalakopiointi
Matalakopiointi

  • Ohjelmointikielten toteutuksen kannalta matalakopiointi on selkeä operaatio

    • siinä kopioidaan aina kaikki olion jäsenmuuttujat eikä mitään muuta

  • Selkeydestä johtuen C++ käyttää oletusarvoisesti matalakopiointia, jos luokan kirjoittaja ei muuta määrää.

  • Kopioinnin tuloksena on ainakin päällisin puolin kaksi oliota.


Matalakopiointi1
Matalakopiointi

  • Yleensä viitekopiointia käytävissä oliokielissä on myös jokin tapa matalakopiointiin

    • Esim. Javan jäsenfunktio clone

  • Eri olioiden jakamat ulkoiset tietorakenteet ovat potentiaalinen ongelma.

    • Muutokset ulkoisissa tietorakenteissa heijastuu kaikkiin matalakopioituihin olioihin


Syv kopiointi deep copy
Syväkopiointi (deep copy)

  • Olion ja sen jäsenmuuttujien lisäksi kopioidaan myös ne olion tilaan kuuluvat oliot ja tietorakenteet, jotka sijaitsvat olion ulkopuolella.

  • Olioiden kannalta ehdottomasti paras kopiointitapa

    • Luodaan kopio kaikista olion tilaan kuuluvista asioista

    • Uusi ja alkuperäinen olio ovat täysin erilliset.


Syv kopio esimerkki
SyväkopioEsimerkki

Alkuperainen

olio

MUISTI:

Alkuperaisen

olion ulkoiset

tietorakenteet

Syväkopion

ulkoiset

tietorakenteet

Syväkopio


Syv kopio ongelmat
Syväkopio Ongelmat

  • Ohjelmointikielen kannalta syväkopiointi on ongelmallista

    • Usein kopioitavat oliot sisältävät osoittimia myös sellaisiin olioihin ja tietorakenteisiin, jotka eivät varsinaisesti ole osa olion tilaa ja joita ei tulisi kopioida.

    • Esim. Kirjaston kirja sisältää osoittimen kirjastoon, josta ne on lainattu. Kirjan tietojen kopioiminen ei saisi aiheuttaa kirjaston kopiointia!


Syv kopio ongelmat1
Syväkopio Ongelmat

  • Syväkopioinnin ongelmien johdosta useimmat ohjelmointikielet eivät tue automaattisesti syväkopiointia

    • Poikkeuksena Smalltalk, joissa oliolta löytyy myös palvelu deepCopy

  • Yleensä oliokielissä annetaan ohjelmoijalle itselleen mahdollisuus kirjoittaa syväkopioinnille toteutus, jota kieli osaa automaatiisesti käyttää

    • C++-kielessä ohjelmoija kirjoittaa luokalle kopiorakentajan, joka suorittaa kopioinnin ohjelmoijan sopivaksi katsomalla tavalla.


Muistatko viel kopiorakentaja copy constructor
Muistatko viel? Kopiorakentaja (copy constructor)

  • Saa parametrina viitteen olemassa olevaan saman luokan olioon.

  • Tehtävänä luoda identtinen kopio parametrina saadusta oliosta

  • Kääntäjä kutsuu sitä automaattisesti tilanteissa, missä kopion luominen on tarpeen.

  • Jos kopiorakentaja puuttuu, se luodaan kääntäjän toimesta automaattisesti


Periytyminen ja kopiorakentaja
Periytyminen ja kopiorakentaja

  • Periytyminen tuo omat lisänsä kopion luomiseen.

  • Aliluokan olio koostuu useista osista, ja kantaluokan osilla on jo omat kopiorakentajansa, joilla kopion kantaluokkaosat saadaan alustetuksi.

  • Aliluokan olion kopioiminen onkin jaettu eri luokkien kesken samoin kuin rakentajat yleensä

    • Aliluokan kopiorakentajan vastuulla on kutsua kantaluokan kopiorakentajaa ja lisäksi alustaa aliluokan osa olioista kopioksi alkuperäisestä


Kopiorakentaja esimerkki
Kopiorakentaja esimerkki

Mjono.cpp

Mjono::Mjono(const Mjono& vanha) : koko_(vanha.koko_), merkit_(0)

{

if (koko_ != 0)

{//Varaa tilaa, jos koko ei ole nolla

merkit_ = newchar[koko_ + 1];

for (unsignedlong i = 0; i != koko_; ++i)

{ merkit_[i] = vanha.merkit_[i];} //kopioi merkit

merkit_[koko_] = ‘\0’; //loppumerkki

}

}

Mjono.h

class Mjono

{

public:

Mjono(constchar* merkit);

//kopiorakentaja

Mjono(const Mjono& vanha);

virtual ~Mjono();

.

.

.

private:

unsigned long koko_;

char* merkit_;

};

Pmjono.h

class PaivattyMjono : public Mjono

{

public:

PaivattyMjono(constchar* merkit, const Paivays& paivays);

//kopiorakentaja

PaivattyMjono(const PaivattyMjono& vanha);

virtual ~PaivattyMjono();

.

.

.

private:

Paivays paivays_;

};

Pmjono.cpp

//olettaa että Paivays-luokalla on kopiorakentaja

PaivattyMjono::PaivattyMjono(const PaivattyMjono& vanha) : Mjono(vanha), paivays_(vanha.paivays_)

{

}


Muista
Muista!

  • Jos unohdat aliluokan kopiorakentajassa kutsua kantaluokan kopiorakentajaa

    • Kääntäjä kutsuu kantaluokan oletusrakentajaa automaattisesti

      Olio ei kopioidu kunnolla


K nt j n luoma oletusarvoinen kopiorakentaja
Kääntäjän luoma oletusarvoinen kopiorakentaja

  • Jos et määrittele luokalle kopiorakentajaa, kääntäjä luo sen automaattisesti

    • Yksinkertaistaa ohjelmointia

    • Oletusarvoinen kopiorakentaja käyttää matalakopiointia

    • Useinmiten matalakopiointi ei ole riittäväjos kopiorakentajan toteutus unohtuu, oliot kopioituvat väärin

  • Jokaiseen luokkaan tulisi erikseen kirjoittaa kopiorakentaja


Kopioinnin est minen
Kopioinnin estäminen

  • Kun ei ole mitään järkeä kopioida oliota, kääntäjän automaattisesta kopiorakentajasta on vain haittaa.

  • Kopiointi on mahdollista estää määrittelemällä kopiorakentaja privaatiksi.

    • Kun olet itse määrittänyt kopiorakentajan, kääntäjä ei yritä tuputtaa omaansa

    • Kukaan luokan ulkopuolella ei pääse kutsumaan kopiorakentajaa

      Onko asia nyt ratkaistu?

      Huomaatko ongelman?


Kopioinnin est minen1
Kopioinnin estäminen

  • privaattiin kopiorakentajaan pääsee käsiksi luokan sisältä tai ystävien kautta

    • Ongelma ratkaistaaan jättämällä kopiorakentaja ilman toteutustaLinkkeri antaa virheilmoituksen, jos joku yrittää käyttää kopiorakentajaa


Esimerkki2
Esimerkki

PaivattyMjono pmj(“paivays”, jokupaivays);

//luodaan kopio

Mjono mj(pmj);

Mjono

PaivattyMjono

Jotain pielessä! Mitä?


Viipaloituminen slicing
Viipaloituminen (Slicing)

  • Ilmiötä, missä oliota kopioitaessa kopioidaankin erehdyksessä vain olion kantaluokkaosa kutsutaan viipaloitumiseksi

PaivattyMjono pmj(“paivays”, jokupaivays);

Mjono mj(pmj); //luodaan kopio

Copy of Mjono

Mjono

PaivattyMjono

PaivattyMjono


Viipaloitumisen kiert minen c kieless
Viipaloitumisen kiertäminen C++ kielessä

  • Otetaan mallia muista oliokielistä

    • toteutetaan kloonaa-funktio ja määritellään se virtuaaliseksi

  • Viipaloitumista ei tapahdu, sillä kloonaa funktion virtuaalisuus takaa sen, että kutsutaan ensin alimmaista lapsiluokkaa

  • Viipaloituminen on kuitenkin edelleen vaarana parametrin välityksessä ja paluuarvoissa.

    • Paras ratkaisu näihin on huolellinen suunnittelu ja ongelmien tiedostaminen.

  • Yksi tapa estää viipaloitumista on myös se, että kaikki kantaluokat ovat abstrakteja.

    • Viipaloitumista ei pääse tapahtumaan, sillä pelkkää abstraktia luokkaa ei voi muodostaa


Olioiden sijoittaminen
Olioiden sijoittaminen

  • Olioiden kopioimisen lisäksi on toinenkin tapa saada aikaan kaksi keskenään samanlaista oliota: Sijoittaminen

  • Sijoittamisen ja kopioinnin ero:

    • kopioinnista luodaan uusi olio, joka alustetaan vanhan olion perusteella

    • sijoittamisessa muutetaan olemassa olevan olion arvo vastaamaan toista oliota


Sijoittamiseen liittyvi ongelmia
Sijoittamiseen liittyviä ongelmia

  • Liittyvät useinmiten vanhan sisällön käsittelyyn

    • Usein joudutaan vapauttamaan vanhaa muistia ja siivoamaan oliota purkajien tapaan ennen kuin uudet arvot voidaan alustaa olioon.

  • Mitä jos siivousoperaatio johtaa virhetilanteeseen?

    • Luultavasti haluttaisiin palauttaa vanhat arvot takaisin oliollePitäisi varmistua siitä, että siivottuja arvoja ei ole vielä heitetty roskiin

  • On myös olemassa tilanteita, missä ei ole mielekästä sallia sijoitusta.pitää olla mahdollista estää sijoitusoperaatio


C sijoitusoperaattori assignment operator
C++ sijoitusoperaattori(assignment operator)

  • C++:ssa olioiden sijoittaminen tapahtuu erityisellä jäsenfunktiolla, jota kutsutaan sijoitusoperaattoriksi

  • Kun ohjelmassa tehdään kahden olion sijoitus a = b, kyseisellä ohjelmarivillä kutsutaan itse asiassa olion a sijoitusoperaattoria ja annetaan sille viite olioon b parametrina.

    • Sijoitus aiheuttaa jäsenfunktiokutsun a.operator =(b)

    • Sijoitusoperaattorin tehtävänä on sitten tuhota olion a vanha arvo ja korvata se olion b arvolla.

    • Se mitä kaikkia operaatioita tähän liittyy, riippuu täysin kyseessä olevasta luokasta


Sijoitusoperaattorin toteutus esimerkki
Sijoitusoperaattorin toteutusEsimerkki

Mjono.h

class Mjono

{

public:

Mjono& operator =(const Mjono& vanha);

.

.

.

};

  • Palauttaa viitteen itseensä

    • mahdollistaa ketjusijoituksen a=b=c

Mjono.cpp

Mjono&Mjono::operator =(const Mjono& vanha)

{

if (this != vanha)

{//Jos ei sijoiteta itseen

delete[] merkit_; merkit_ = 0; //Vapauta vanha

koko_ = vanha.koko_; //Sijoita koko

if (koko_ != 0)

{ //Varaa tila, jos koko ei nolla

merkit_ = newchar[koko_ + 1];

for (unsignedlong i = 0; i != koko_; ++i)

{ merkit_[i] = vanha.merkit_[i];} //kopioi merkit

merkit_[koko_] = ‘\0’; //loppumerkki

}

return *this;

}


Sijoitus itseen
Sijoitus itseen

  • Mitä seurauksia seuraavalla koodilla on?a=a;

  • Miten ongelman voi ehkäistä?

  • Ensin lähdetään tyhjentämään sijoitettavan luokan vanhaa arvoa

  • Samalla tuhotaan vahingossa sijoitettava arvo

  • Eli muistialueen alustamaton sisältö kopioidaan itsensä päälle

  • Tarkastetaan ennen sijoitusoperaatioon ryhtymistä, että kyseessä ei ole sijoitus itseen.

    • Jätetään sijoitusoperaatio tekemättä jos näin on


Periytyminen ja sijoitusoperaattori
Periytyminen ja sijoitusoperaattori

  • Toimitaan samoin kuin kopiorakentajankin kanssa

    • aliluokka kutsuu kantaluokan sijoitusoperaattoria

Pmjono.h

class Mjono

{

public:

Mjono& operator =(const Mjono& vanha);

.

.

.

};

Pmjono.cpp

PaivattyMjono&PaivattyMjono::operator =(const PaivattyMjono& vanha)

{

if (this != vanha)

{//Jos ei sijoiteta itseen

Mjono::operator =(vanha);//Kantaluokan sijoitusoperaattori

//Oma sijoitus, oletetaan että Paivays-luokalla on sijoitusoperaattori

paivays_ = vanha.paivays_;

}

return *this;

}


Oletus sijoitusoperaattori
Oletus-sijoitusoperaattori

  • Jos luokalla ei ole kirjoitettu sijoitusoperaattoria, kääntäjä luo sen itse.

  • Oletus sijoitusoperaattori yksinkertaisesti sijoittaa kaikki olion jäsenet yksi kerrallaan

    • Jos jäseninä on osoittimia, molemmat oliot tulevat sijoituksen jälkeen osoittamaan samaan paikkaan EI HALUTTUA!

  • Jokaiseen luokkaan tulisi erikseen kirjoittaa sijoitusoperaattori!


Sijoituksen est minen
Sijoituksen estäminen

  • Estetään samalla tavalla kuin kopioiminenkin

    • Määritellään sijoitusoperaattori privaatiksi

    • Ei anneta sijoitusoperaattorille toteutusta ollenkaan


Sijoitus ja viipaloituminen
Sijoitus ja viipaloituminen

  • Viipaloituminen on mahdollista jos sijoittaminen tapahtuu kantaluokkaosoittimien tai -viitteiden kautta

void sijoita (Mjono& mihin, const Mjono& mista)

{

mihin = mista;

}

int main()

{

Mjono mj(“Tavallinen”);

PaivattyMjono pmj(“Päivätty”, tanaan);

NumMjono nmj(“Numeroitu”,12);

//Viipaloituminen funktion sisällä!

sijoita (pmj, nmj);

sijoita(mj, pmj);

}


Viipaloitumisen v ltt minen sijoituksessa
Viipaloitumisen välttäminen sijoituksessa

  • Helpointa olisi tehdä luokkahierarkia, jossa kaikki kantaluokat ovat abstrakteja

  • Voit myös aina tarkastaa sijoituksen yhteydessä että molemmat oliot ovat varmasti samaa tyyppiä

    • tämä onnistuu typeid-operaattorin avulla


Sijoitettavien olioiden tyypin tarkastus
Sijoitettavien olioiden tyypin tarkastus

#include <typeinfo>

Mjono&Mjono::operator =(const Mjono& m)

{

if (typeid(*this) == typeid(m)) { /*virhetoiminta*/}

if (this != &m)

{//Jos ei sijoiteta itseen

.

.

.

}

return *this;

}


Miss menn n3
Missä mennään?

  • Rajapinnoista

    • Esimerkki

    • Abstrakti luokka

    • Puhdas virtuaalinen funktio

    • Rajapinnan käytöstä

    • Komponentteihin jaottelusta

  • Perinnän vaikutus olion luontiin ja tuhoamiseen

    • Rakentajat ja perintä

    • Purkajat ja perintä

  • Perityn luokan eri tyypit

    • Aliluokan ja kantaluokan suhde

    • Tyyppimuunnokset

  • Olioiden sijoitus ja kopiointi

    • Olioiden kopiointi

    • Olioiden sijoitus

  • Yhteenveto

    • Puhdasoppinen luokka

    • Kertaus


Yhteenveto puhdasoppinen luokka
YhteenvetoPuhdasoppinen luokka

Olisi hyvä jos kaikki luokat määrittelisivät seuraavat tärkeät funktiot

  • Oletusrakentaja (Default constructor)

  • Kopiointirakentaja (Copy constructor)

  • Sijoitusoperaattorin (Assignment operator)

  • Purkajan (Destructor)

    Tällainen luokkarakenne tunnetaan puhdasoppisen kanonisen luokan muotona (orthodox canonical class)


Puhdasoppinen luokka esimerkki
Puhdasoppinen luokkaEsimerkki

Mjono.h

class Mjono

{

public:

//constructors///////////////////////

Mjono(); //oletusrakentaja

Mjono(const Mjono& vanha); //kopiorakentaja

Mjono(constchar* merkit);

//destructors////////////////////////

virtual ~Mjono(); //purkaja

//operators/////////////////////////

Mjono& operator =(const Mjono& vanha); //sijoitusoperaattori

//operations////////////////////////

unsigned long kerroKoko(){ return koko;}

protected:

private:

unsigned long koko_;

char* merkit_;

};


Mit t n n opimme
Mitä tänään opimme?

  • Rajapintojen käyttö ja toteutuksen kätkentä on yksi ehkä tärkeimmistä ohjelmistotuotannon perusperiaatteista

    • Rajapinta toteutetaan abstrakteina luokkina

    • Abstrakti luokka luodaan puhtaiden virtuaalifunktioiden avulla

    • Rajapintojen avulla voimme pilkkoa monimutkaiset systeemit pienempiin osiin

  • Perinnän käyttö pitää ottaa huomioon olioita luodessa ja tuhotessa

    • Rakentajat ja perintä

    • Purkajat ja perintä

  • Peritty luokka on aina myös kantaluokkansa edustaja.

    • Käytettävissä olevat operaatiot riippuvat siitä minkä tyyppinen osoitin on kyseessä

    • Opimme muuttamaan osoittimien ja viittausten tyyppiä

  • Perintä pitää ottaa myös huomioon olioita kopioitaessa ja sijoittaessa

    • Kääntäjä ei voi tietää miten kopioidaan ja sijoitetaan järkevästi

    • Oletuskopiointi ja oletussijoitus menevät helposti pieleen toteuta kopiorakentaja ja sijoitusoperaattori mielummin itse

  • Puhdasoppinen luokka

    • oletusrakentaja

    • kopiorakentaja

    • sijoitusoperaattori

    • virtuaalinen purkaja