Esittely latautuu. Ole hyvä ja odota

Esittely latautuu. Ole hyvä ja odota

Olio ohjelmoinnin perusteet luento 3: Johdanto C++ kieleen, Ensimmäinen C++ ohjelma, Olioiden elinkaari Jani Rönkkönen LTY/Tietotekniikan osasto Kalvot.

Samankaltaiset esitykset


Esitys aiheesta: "Olio ohjelmoinnin perusteet luento 3: Johdanto C++ kieleen, Ensimmäinen C++ ohjelma, Olioiden elinkaari Jani Rönkkönen LTY/Tietotekniikan osasto Kalvot."— Esityksen transkriptio:

1 Olio ohjelmoinnin perusteet luento 3: Johdanto C++ kieleen, Ensimmäinen C++ ohjelma, Olioiden elinkaari Jani Rönkkönen LTY/Tietotekniikan osasto Kalvot on muokattu Sami Jantusen luentokalvoista viime vuodelta.

2 Sisältö Johdanto C++ kieleen Olioiden elinkaari
Taustatietoa C++ kielestä Johdanto C++ kielen syntaksiin Ensimmäinen C++ ohjelma Olioiden elinkaari Olioiden syntymä Olioiden kuolema Olioiden elinkaaren määräytyminen

3 C++ Varsinkin teollisuudessa yleistynyt oliokieli
C-kielestä lähinnä laajentamalla johdettu Suurin osa ANSI C -ohjelmista laillisia C++-ohjelmia Tuloskoodi usein varsin tehokasta Luokkakäsite & olio-ajattelu ->korkean tason abstraktio Mahdollisuus myös matalan tason ohjelmointiin Helpohko oppia C:tä osaaville Helppo yhdistää C-kirjastoja C++:aan Kieli ei rajoita ohjelman toteutustapaa Staattinen (käännösaikainen) tyypitys ISO C++ -standardi tarjoaa työkaluja C:n puutteiden kiertämiseen

4 C++ haittoja C:stä periytyvä turvattomuus
Yhteensopivuus C:n kanssa ->ikäviä kompromisseja oliopiirteissä Vaatii myös C-tuntemusta Runsaasti ansoja ohjelmoijalle Helppo kirjoittaa C++:aa C-mäisesti Kielessä ei kaikkialla pakollisia automaattisia virhetarkastuksia->ohjelmien sekoamiset yleisiä C:n matalatasoisuus paistaa kielestä läpi myös oliotasolla Periytymismekanismia käytettäessä sallii toteutukset, jotka itse asiassa olioajattelun vastaisia Ei pakota olioajatteluun

5 C++ kielen ominaisuuksia
perustana on C-kieli, johon on tehty joitakin lisäyksiä ja olio-ohjelmointimekanismit sisältävät laajennus C-kielen laajennukset: Kommentit Tyyppimuunnokset (type casting) Syöttö ja tulostus Muuttujien näkyvyys Nimiavaruudet (namespace) Aliohjelmien oletusparametrit ja ylikuormitus Vakiomuuttujat (constant variables) Viittausmuuttujat (reference variables) Dynaaminen muistinvaraus Inline aliohjelmat Merkkijonojen käsittely

6 Ihan ensimmäinen C++ ohjelma Ohjelman runko
#include <iostream> //otetaan nimiavaruus std käyttöön using namespace std; void main ( ) { // main pitää aina olla! } // Tämä pitäisi muuten tallettaa //johonkin .cpp tiedostoon

7 Ohjelman dokumentointi
Ohjelman dokumentointia sanotaan “kommentoinniksi”. Kääntäjä jättää kommentit huomioimatta C++:ssa kaksi tapaa kommentoida! // Kommentoi loppurivin /* Näin kommentoidaan isompia lohkoja. Kommentointi loppuu kun vastaan tulee */

8 Tyyliopas kommentoinnista
Kunkin lähdekooditiedoston alkuun olisi hyvä kommentoida seuraavat asiat: Ohjelman nimi Tiedoston nimi Tekijän nimi Kuvaus tiedoston siältämistä asioista Kehitysympäristö Muutoshistoria Kunkin funktion alkuun tulisi kommentoida seuraavat asiat Funktion nimi Kuvaus funktiosta Funktioon tuleva tieto Funktiosta lähtevä tieto Älä kommentoi itsestäänselvyyksiä. Perussääntö: Kerro miksi ei miten

9 Esimerkki tiedoston otsikosta
/***************************************** ** Ohjelma: Hello World ** Tiedosto: hello.CPP ** Tekijä: Jani Rönkkönen ** Kuvaus: Tulostaa näytölle sanat “Hello world” ** Ympäristö: Visual C++ 6.0, Windows XP ** Muutokset: (JR) Ensimmäinen versio ** (JR) Laitettu iso kirjan World sanaan ** ***********************************************/

10 Esimerkki funktion otsikosta
/************************************************ ** CircleArea -- ** This function calculates the area of a circle ** with the specified radius. ** Inputs: the circle's radius as a parameter ** Output: the circle's area as the return value **************************************************/

11 Näytölle tulostus Käytä cout –oliota.
Tarvitsee iostream luokkakirjastoa cout pystyy tulostamaan kutakuinkin mitä vaan. Erityyppisiä muuttujia Useita asioita kerrallaan erikoismerkkejä kuten ‘\n’ (newline), ‘\a’ (alert), jne.. Useita asioita tulostetaan erottelemalla ne <<:llä endl:n avulla tehdään rivinsiirto Esimerkki: #include <iostream> using namespace std; int main(void) { string teksti = “Mitä häh?”; cout<<”Teksti: “<<endl<<teksti<<endl; return 0; }

12 Käyttäjän syötteen lukeminen
Käytä cin –oliota. Tarvitsee iostream luokkakirjastoa Lue syötteet muuttujiin >> avulla Esimerkki: #include <iostream> using namespace std; int main(void) { // Luodaan muuttuja int myInt; // Luetaan tietoa näppikseltä cin >> myInt; // Ja tulostetaan näytölle cout << “myInt is “ << myInt << endl; return 0; }

13 Uudet otsikkotiedostot
Vaikka on mahdollista käyttää vanhoja C kielestä periytyviä kirjastofunktioiden otsikkotiedostoja, kannattaa aina käyttää uusia C++ versioita, jotka tukevat nimiavaruuksia: Kääntäjän omat otsikkotiedostot sisällytetään ilman .h –ekstensiota #include <iostream.h>  #include<iostream> C-kielestä perittyihin otsikkotiedostoiden nimiin lisätää lisäksi ‘c’ eteen #include <string.h>  #include <cstring>

14 Nimiavaruudet (namespace)
Uusia otsikkotiedostoja käytettäessä standardikirjastoihin kuuluvat asiat on määritelty nimiavaruuteen std ja niihin pääsee käsiksi näkyvyystarkeninoperaattorin :: avulla, esimerkiksi: std::cout << ”Hello” << std::endl; Jotta aina ei tarvitsisi kirjoittaa kaiken eteen nimiavaruuden nimeä, voidaan käytettävä nimiavaruus esitellä using komennolla esimerkiksi tiedoston alussa: using namespace std; Nyt tässä tiedostossa riittää pelkästään cout << ”Hello” << endl; Nimiavaruuksiin palataan myöhemmin uudestaan

15 Sääntöjä luokkien luomisesta
Luokat yleensä nimetään alkamaan isolla kirjaimella Tidosto, jonne kirjoitat luokan pitäisi nimetä saman nimiseksi luokan kansa: <class name>.cpp Esimerkki: Jos meillä on tarve luoda koirasta luokka annamme sille nimen Dog ja tallennamme sen tiedostoon Dog.cpp Muista että C++ on case-sensitiivinen!

16 Nimeämiskäytännöistä
Nimeämiskäytännöillä on huomattava vaikutus luokkien käytettävyyteen. Tavoite: Luokat, funktiot ja muuttujat tulisi nimetä niin, että koodi muistuttaa englanninkielistä tekstiä Kullakin yrityksellä tyypillisesti omat tyylioppaat. Esimerkki tyylioppaasta, Tampereen Teknillisen Yliopiston tekemä tyyliopas:

17 Yksinkertaisin luokka
Luokan määre: class <class name> { }; Esimerkki: sinua pyydetään luomaan luokka X ratkaisu: class X { Muista, että luokka pitäisi talletta X.cpp nimiseen tiedostoon (EI x.cpp!)

18 Ensimmäinen oliopohjainen ohjelma: Koirat eläintarhassa
Haluamme määritellä koiraluokan ja luoda sen mukaisia koiraolioita eläintarhaan! luokka CDog: Attribuutit (ominaisuudet) vesikauhuinen vai ei (bool) paino (int or float) nimi (string) Toiminnallisuus murise syö CDog bool rabidOrNot int weight string name void growl() void eat()

19 Vaihe 1: Luokan runko CDog class CDog { // attribuutit tähän – nimi,
// paino, vesikauhuisuus // toiminto tähän– murise, syö }; CDog bool rabidOrNot int weight string name void growl() void eat()

20 Vaihe 2: Attribuutit class CDog { bool rabidOrNot; int weight;
std::string name; // Toiminnallisuus tänne }; CDog bool rabidOrNot int weight string name void growl() void eat()

21 Vaihe 3: Rakentaja (Constructor)
Rakentaja on erityinen funktio Sitä käytetään alustamaan uusi olio Aktivoidaan kun joku luo uuden (esim. komento new) instanssin luokasta Rakentajalle ei määritellä ollenkaan paluutyyppiä Rakentajan TÄYTYY olla saman niminen kuin luokkakin

22 Vaihe 3: Rakentajan suunnittelu
Rakentajat eroavat toisistaan tarpeen mukaan Kysy itseltäsi: Syntyvätkö kaikki CDog:t joko vesikauhuisena tai terveenä? (kyllä – kaikki koirat syntyvät terveinä) Syntyvätkö kaikki CDog:t saman painoisena? (ei – koiranpennut on eripainoisia) Onko kaikilla koiranpennuilla sama nimi? (ei – niillä on eri nimiä) Jos vastaus kysymykseen on ei, silloin joudut toimittamaan kyseisen tiedon rakentajalle parametrinä

23 Vaihe 3: Rakentaja Huomaa, että jokainen
class CDog { bool rabidOrNot; int weight; std::string name public: // Constructor CDog::CDog (int x, std::string y) { rabidOrNot = false; weight = x; name = y; } // Toiminnallisuus tänne }; Huomaa, että jokainen CDog minkä luomme syntyy terveenä. Paino ja nimi riippuu parametrien arvoista.

24 Vaihe 4: Rentoudu ja pidä tauko
Palaamme murinaan ja syömiseen hieman myöhemmin Meidän pitää vielä puhua: Lukijametodeista Muuttajametodeista Toimintaa toteuttavista metodeista Leikitään ensin vähän aikaan ohjelman pääalgoritmilla

25 Zoo Nyt puhutaan ihan uudesta tiedostosta! (Zoo.cpp)
Zoo sisältää pääfunktion main main sisältää kontrolloivan algoritmin Askeleet: Luo runko Luo muutamia olioita luokista Ala kertomaan mitä olioiden pitäisi tehdä

26 Vaihe 1: Luo runko #include <iostream> void main ( ) {
// Luo oliosi täällä! }

27 Vaihe 2: Määritä CDog osoitin
#include <iostream> void main ( ) { CDog *c1=NULL; } // null means “dead” Memory null c1

28 new operaattori new Formaatti: Tuo oliot henkiin
Kutsuu luokan rakentajaa (constructor) Varaa riittävästi muistia luotavalle oliolle Formaatti: <class> *<var_name>; <var_name> = new <class> (<parameters>);

29 Vaihe 3: herätä c1 henkiin
#include <iostream> void main ( ) { CDog *c1; c1 = new CDog (14, “Bob”); } Memory null c1 new kutsuu CDog:n rakentajaa CDog::CDog (int x, std:string y) { rabidOrNot = false; weight = x; name = y; }

30 Tee muistiin tilaa null #include <iostream> void main ( ) {
CDog* c1; c1 = new CDog (14, “Bob”); } Memory null c1 new kutsuu CDog:n rakentajaa CDog::CDog (int x, std:string y) { rabidOrNot = false; weight = x; name = y; }

31 Tiedon välitystä null #include <iostream> void main ( ) {
CDog* c1; c1 = new CDog (14, “Bob”); } Memory null c1 CDog::CDog (int x, std::string y) { rabidOrNot = false; weight = x; name = y; } // Tämä tapahtuu CDog.cpp -tiedostossa

32 Tiedon välitystä null #include <iostream> void main ( ) {
CDog* c1; c1 = new CDog (14, “Bob”); } Memory null c1 CDog::CDog (int x, std::string y) { rabidOrNot = false; weight = x; name = y; } // Tämä tapahtuu CDog.cpp -tiedostossa rabid:false weight:14 name:”bob”

33 Luo toinen CDog olio null #include <iostream> void main ( ) {
CDog* c1; c1 = new CDog (14, “Bob”); CDog c2 (7, “Ethel”); } Memory null c1 CDog::CDog (int x, std:string y) { rabidOrNot = false; weight = x; name = y; } // Tämä tapahtuu CDog.cpp -tiedostossa rabid:false weight:14 name:”bob”

34 Tee muistiin tilaa null #include <iostream> void main ( ) {
CDog* c1; c1 = new CDog (14, “Bob”); CDog c2 (7, “Ethel”); } Memory null c1 CDog::CDog (int x, std:string y) { rabidOrNot = false; weight = x; name = y; } // Tämä tapahtuu CDog.cpp -tiedostossa c2 rabid:false weight:14 name:”bob”

35 Tiedon välitystä null #include <iostream> void main ( ) {
CDog* c1; c1 = new CDog (14, “Bob”); CDog c2 (7, “Ethel”); } Memory null c1 CDog::CDog (int x, std::string y) { rabidOrNot = false; weight = x; name = y; } // Tämä tapahtuu CDog.cpp -tiedostossa c2 rabid:false weight:14 name:”bob”

36 Kopioi arvon muistiin null #include <iostream> void main ( ) {
CDog* c1; c1 = new CDog (14, “Bob”); CDog c2 (7, “Ethel”); } Memory null c1 // Tämä tapahtuu CDog.cpp -tiedostossa CDog::CDog (int x, std:string y) { rabidOrNot = false; weight = x; name = y; } c2 rabid:false rabid:false weight:14 weight:7 name:”bob” name:”Ethel”

37 Takaisin CDog-luokan pariin
using namespace std; class CDog { bool rabidOrNot; int weight; string name; public: // Constructor CDog::CDog (int x, string y) { rabidOrNot = false; weight = x; name = y; } // Toiminnallisuus. Vielä pitäisi //syödä ja murista }; CDog bool rabidOrNot int weight string name void growl() void eat()

38 Toiminnallisuuden toteuttaminen
void CDog::eat ( ){ cout << name << “ is now eating” << endl; weight++; } void CDog::growl ( ) const{ cout << “Grrrr” << endl; CDog bool rabidOrNot int weight string name void growl() void eat()

39 Lisää metodit luokkaan
using namespace std; class CDog { bool rabidOrNot; int weight; string name; public: // Constructor CDog::CDog (int x, string y) { rabidOrNot = false; weight = x; name = y; } void CDog::eat ( ) { cout << name << “ is now eating” << endl; weight++; void CDog::growl ( ) const { cout << “Grrrr” << endl; }; CDog bool rabidOrNot int weight string name void growl() void eat()

40 “.” ja “->” operaattorit
“.” ja “->” operaattoreita käytetään jotta: päästään käsiksi olion attribuutteihin päästään käsiksi olion metodeihin päästään ylipäätänsä olion sisuksiin käsiksi “.” operaattoria käytetään konkreetiisten instanssien kanssa (ei siis pointtereissa) Formaatti:<instanssi>.<attribuutti tai metodi> “->” operaattoria käytetään pointtereiden kanssa Formaatti:<instanssi> -> <attribuutti tai metodi>

41 “.” ja “->” operaattiorien käyttö
#include <iostream> void main ( ) { CDog* c1; c1 = new CDog (14, “Bob”); CDog c2 (7, “Ethel”); c2.eat( ); c1->growl( ); }

42 Lukijametodit (accessors) ja muuttajametodit (modifiers)
palauttaa olion atribuutin arvon ei voi olla paluuarvotyypiltään void metodissa pitää olla return komento Muuttajametodit muuttavat olion attribuutin arvoa yleensä paluuarvotyyppinä void Yleensä jokaisella attribuutilla on yksi lukijametodi ja yksi muuttajametodi (Get-Set metodit)

43 Lukija- ja muuttajametodit
Lukijametodi rabid attribuutille bool CDog::getRabid ( ) const{ return rabidOrNot; } Muuttajametodi rabid attribuutille void CDog::setRabid (bool myBoolean) { rabidOrNot = myBoolean; Sijoita nämä CDog luokan sisälle

44 Lukija- ja muuttajametodien käyttö
#include <iostream> using namespace std; void main ( ) { CDog* c1; c1 = new CDog (14, “Bob”); CDog c2 (7, “Ethel”); c1->setRabid (true); // prints 1 for true cout << c1->getRabid( ) << endl; }

45 Vakioparametrit ja -metodit
int metodi(const int &i) const; Metodi voidaan määritellä vakioksi lisäämällä sen perään varattu sana const Vakiometodi ei voi muuttaa olion tilaa, eli metodin kutsuja voi luottaa siihen, että olion tila ei muutu metodin kutsun yhteydessä Käyttämällä parametrin määrityksessä vakioviittausta tai osoitinta vakioon, voidaan varmistaa, että metodi ei muuta parametrin tilaa Vakioparametrien käytöllä taataan luokan käyttäjälle, että parametrina annettu asia ei varmasti muutu ja siksi sen käyttöä kannattaa suosia

46 Vakio-oliot Kun olio määritellään vakioksi, voidaan käyttää ainoastaan olion vakiometodeita Tällä estetään vakio-olion tilan muuttuminen Tyypillinen käyttökohde on lähettää olio parametrina aliohjelmalle, joka ottaa sen vastaan vakiona -> aliohjelman sisällä voidaan nyt käyttää ainoastaan parametrina tulleen luokan vakiometodeita Tästä syystä kaikki metodit, jotka eivät muuta olion tilaa tulisi määritellä vakiometodeiksi Tyypillisesti esimerkiksi lukijametodit ovat tälläisiä

47 Valmista? kääntyykö ohjelma?
Pahoja ongelmia Missä vika????

48 Ongelman etsiminen…. Jotta ymmärtäisimme ongelman, tutkitaanpa ensin hieman miten C++ kääntäjät toimivat

49 Käännetty vs. Tulkittu Tulkit tulkitsevat lähdekoodia “lennosta” ohjelmaa ajettaessa Kääntäjät muuntavat lähdekoodin koneen ymmärtämään muotoon ennen ohjelman ajoa Nopeus? Käännetty ohjelma voittaa Turvallisuus, suoja viruksilta ym? Tulkittu ohjelma voittaa

50 Ohjelman kääntäminen Käytät jompaa kumpaa seuraavista:
Komentorivi: g++ (Unixissa) IDE (Esim. Visual C++)

51 Työkaluista: Integrated Development Environments (IDE)
Helppo hallita suurempienkin ohjelmien kehitystä Siisäänrakennettu kääntäjä ja linkkeri Usein mukana online syntaksi oppaat Paljon käyttäjäystävällisempi kuin komentorivi Visual C++ on esimerkki IDE:stä

52 Käännösprosessi (Compiling)
Muuntaa lähdekoodin luettavasta muodosta (.cpp) tietokoneen ymmärtämään muotoon (.obj) Yhdistää (Link) käännetyn koodin liittämiisi kirjastoihin Tuloksena ajettava tiedosto (.exe)

53 Käännös

54 Hyvä tietää C++ käännösprosessista
C++ kääntäjä käsittelee kutakin lähdekooditiedostoa kerrallaan yhtenä kokonaisuutena. Jos käännettävä tiedosto sisältää viittauksia luokkiin, mitkä on kuvattu jossain toisessa tiedostossa, ne pitäisi jollain lailla “esitellä” käännöksen aikana Ratkaistaan ongelma eriyttämällä luokan esittely ja konkreettinen toteutus eri tiedostoihin

55 Otsikkotiedostot (Header files)
Sisältävät luokan esittelyn Tiedoston nimi on muotoa LuokanNimi.h Otsikkotiedostoon voi kirjoittaa avoimien (public) funktioiden toteutuksia. Tätä kannattaa käyttää hyväksi yksinkertaisten get-set metodien yhteydessä

56 Otsikkotiedostot (Header files)
Otsikkotiedostot otetaan käyttöön seuraavilla tavoilla: #include “MinunLuokka.h” #include <iostream> #-symboli kertoo, että komento on tarkoitettu esikäsittelijän suoritettavaksi. (esikäsittely tapahtuu ennen varsinaista käännöstä) #include –komento kertoo, että kääntäjä käsittelee käännettävää tiedostoa aivan kun #include rivin tilalla olisi kyseisen tiedoston koko sisältö Hakasulut (<>) kertovat, että otsikkotiedosto sijaitsee kääntäjän omissa hakemistoissa Lainausmerkit kertovat, että kyseessä on ohjelmoijan tarjoama otsikkotiedosto

57 C++ ohjelman rakenne

58 Kumpi tuli ensin: Muna vai kana?
Ongelmia luokkien esittelyssä kun luokat viittaavat toisiinsa (mutual recursion) Viittaus toiseen luokkaan voidaan hyväksyä luokan jäsenmuuttujaksi vain jos kääntäjä on jo tietoinen luokasta. Ratkaisuna ongelmaan on etukäteen julkaisu (forward declaration): Kana *äiti Kana Muna *lapsi

59 Moninkertainen otsikkotiedoston esittely
Suurissa ohjelmissa #include-rakenteet tulevat mutkikkaiksi ja monitasoisiksi. Kääntäjä voi tällöin virheellisesti saada käsittelyyn saman otsikkotiedoston useaan kertaan. Virhetilanne Pääohjelma #include “tietokanta.h” #include “loki.h” tietokanta.h #include “paivays.h” loki.h #include “paivays.h” paivays.h

60 Esikäääntäjän ehdollinen kääntäminen
Ehdollisella kääntämisellä (#ifndef X #define X … #endif) voidaan varmistaa, että esittely näkyy kääntäjälle vain yhden kerran #ifndef C_MODUULI_H #define C_MODUULI_H typedef struct paivays data { int p , k , v ; }paivays_PVM; paivays_PVM paivays_luo( int paiva, int kuukausi, int vuosi ); paivays_tulosta( paivays_PVM kohde ); #endif /* C_MODUULI_H */

61 #include käytöstä vielä
Vältä otsikkotiedostojen sisällyttämistä muihin otsikkotiedostoihin Ihanteellisessa tilanteessa otsikkotiedostoon pitää sisällyttää vain kyseisen luokan kantaluokan otsikkotiedosto Muita pakollisia sisällytettäviä tiedostoja ovat niiden luokkien otsikkotiedostot, jonka tyyppisiä jäsenmuuttujia luokassa on Jos vain viitataan toisen tyyppiseen olioon pelkkä luokan esittely riittää

62 Linkkaus

63 Milloin kannattaisi kääntää?
Nyrkkisääntö: Mitä epävarmempi olet, sitä useammin käännät Tämä nopeuttaa virheiden paikallistamisessa Käännä: Ohjelman rungon luomisen jälkeen Joka 5-10 uuden rivin jälkeen Älä kuitenkaan tule riippuvaiseksi kääntäjästä!

64 Palataanpa takaisin koirat eläintarhassa esimerkkiin
#ifndef CDog_H #define CDog_H #include <iostream> class CDog { int weight; bool rabidOrNot; std::string name; public: CDog (int x, std::string y); bool getRabid ( ) const; void setRabid (bool x); std::string getName ( ) const; void setName (std:string z); int getWeight ( ) const; void setWeight (int x); void eat( ); void growl( ) const; }; #endif /* CDog_H */ Luodaan erillinen otsikkotiedosto CDog luokalle Tiedoston nimi CDog.h Vielä paljon kerrottavaa Ei vielä ihan tyylipuhdas luokan esittely. CDog bool rabidOrNot int weight string name void growl() void eat()

65 CDog.cpp näyttää nyt tältä:
#include <string> #include “CDog.h” using namespace std; // Constructor CDog::CDog (int x, string y) { rabidOrNot = false; weight = x; name = y; } void CDog::eat ( ) { cout << name << “ is eating” << endl; weight++; void CDog::growl ( ) const{ cout << “Grrrr”; bool CDog::getRabid ( ) const{ return rabidOrNot; } void CDog::setRabid (bool x) { rabidOrNot = x; int CDog::getWeight ( ) const{ return weight; void CDog::setWeight (int y) { weight = y; string CDog::getName ( ) const{ return name; void setName (string z) { name = z);

66 Ensimmäinen C++ ohjelma Yhteenveto
Luokkia luodessa Luo luokan runko Määrittele attribuutit Kirjoita luokalle rakentaja Kirjoita toiminnallisuus (mukaanlukien lukija- muuttajametodit) Kirjoita luokat eri tiedostoihin Olioiden ominaisuuksia käytetään “.” and “->” operaattorien avulla

67 Missä mennään? Olioiden elinkaari Johdanto C++ kieleen
Taustatietoa C++ kielestä Johdanto C++ kielen syntaksiin Ensimmäinen C++ ohjelma Olioiden elinkaari Olioiden syntymä Olioiden kuolema Olioiden elinkaaren määräytyminen

68 Olioiden syntymä Olioiden luomiseen saattaa liittyä monimutkaisiakin toimenpiteitä kuten esim: Muistin varaaminen toisten olioiden luominen rekisteröitymiset (palvelinolio rekisteröi syntyessään palvelunsa järjestelmänlaajuiseen tietokantaan) resurssien käyttöönotto (tietokantaolio avaa syntyessään tietokannan sisältävän tiedoston ja lukeen sen muistiin) muut toimenpiteet (ikkunaolio piirtää syntyessään ikkunan ruudulle) Alustustoimenpiteet sysätään kunkin olion omalle vastuulle

69 Olioiden kuolema Kun oliota ei tarvita enää, tulisi suorittaa siivoustoimenpiteitä kuten: muistin vapautus toisten olioiden tuhoaminen rekistereistä poistuminen resurssien vapauttaminen Siivoustoimenpiteet ovan myöskin kunkin olion omalla vastuulla

70 Olioiden elinkaaren määräytyminen
Staattinen elinkaari Dynaaminen elinkaari

71 Staattinen elinkaari Oliot, jotka luodaan tavallisen muuttujan tapaan. Esim: CDog c2(7, “Ethel”); Kissa minunKissa; Olion syntymä- ja tuhoutumishetki on määrätty jo käännösaikana. Kääntäjä osaa suorittaa automaattisesti luomis- ja tuhoamistoimenpiteet Suositeltava tapa. Ei vaaraa muistivuodoista. Silti mahdollisuus vakaviin virheisiin . Esimerkki: Osoittimet saattavat viitata automaattisesti tuhottavaan olioon Muista, että olio tuhoutuu automaattisesti tietyssä kohdassa ohjelmaa

72 Dynaaminen elinkaari Olion elinkaaresta huolehtiminen on jätetty ohjelmoijan vastuulle Olio ei tuhoudu automaattisesti. Se täytyy erikseen tuhota. Pakko käyttää tilanteissa, missä olion elinkaari ei rajaudu tiettyyn osaa koodia Mitä luot new -komennolla, sen tuhoat delete –komennolla Vaarallista! Muistivuotoja tulee helposti

73 Tyypillisiä dynaamiseen luontiin liittyviä ongelmia
Unohdetaan tuhota olio(t) Olio tuhotaan kahteen kertaan Tuhotun olion käyttäminen Taulukkojen tuhoaminen

74 Esimerkki (asetetaan d1 osoittamaan d2:n osoittamaan olioon)
Memory Dog *d1, *d2; d1 = new Dog (5, “bob”); d2 = new Dog (5, “bob”); d1 = d2; null d1 d2 rabid=false rabid=false weight=5 weight=5 name=“bob” name=“bob”

75 Muistin tarkastelu Nyt, d1 ja d2 osoittavat samaan olioon
Memory Nyt, d1 ja d2 osoittavat samaan olioon Mutta mikään ei osoita tähän Koska mikään osoitin ei osoitaa kyseiseen olioon, emme voi enää käyttää sitä. Kutsumme tätä osaa muistia roskaksi. Teimme oliosta käyttökelvottoman! null d1 d2 rabid=false rabid=false weight=5 weight=5 name=“bob” name=“bob”

76 Muistin vapauttamisesta
Muista vapauttaa käyttämätön muistialue Sääntö: Älä koskaan vain aseta osoitinta null:ksi Muista käyttää delete ( ) operaattoria Esim: delete d1;

77 Ohjeita virheiden välttämiseen
Määrittele, kuka “omistaa” olion ja on täten vastuussa sen tuhoamisesta Pyri siihen, että dynaamisesti luotuja olioita ei käytetä monen eri tahon toimesta. Nollaa osoittimet tuhoamisen jälkeen Paivays *p = new Paivays; //käytetään päiväystä delete p; p =0; Tämä estää tilanteen, missä muuttujat viittaavaat muistipaikkaan, missä tuhotun olion ylitse ei ole kirjoitettu vielä uutta tietoa (Zombie-olioiden käyttö) Kirjoita koodia, mikä pyrkii toipumaan virhetilanteista (Tästä lisää myöhemmissä luennoissa)

78 Rakentaja (constructor)
Tunnetaan myös nimellä Muodostaja Tehtävänä hoitaa kaikki uuden olion alustamiseen liittyvät toimenpiteet Jäsenmuuttujien alustus Olioon kuuluvien olioiden ulkopuolisten tietorakenteiden ja olioiden luominen Olion rekisteröiminen jonnekkin Kolmenlaisia rakentajia: oletusrakentaja (default constructor) olion tietojäsenten alustus oletusarvoilla kopiointirakentaja (copy constructor) olion tietojäsenten alustus toisesta oliosta kopioimalla parametrilliset rakentajat

79 Rakentaja (constructor) Sääntöjä
Kääntäjä luo jokaiselle luokalle oletusrakentajan ellei sellaista ole itse ohjelmoitu Rakentajan nimi täytyy olla sama kuin luokan nimi Rakentaja ei palauta paluuarvoa Rakentajalle ei voi määritellä paluuarvon tyyppiä (ei edes void)

80 Oletusrakentaja (default constructor) Esimerkki
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; }

81 Rakentaja (constructor) Sijoitus vs. Alustuslista
Jäsenmuuttujiin sijoitus Pvm::Pvm(const int p_pp, const int p_kk, const int p_vv) { pp = p_pp; kk = p_kk; vv = p_vv; } Alustuslistan käyttö Pvm::Pvm(const int p_pp, const int p_kk, const int p_vv) : pp(p_pp), kk(p_kk), vv(p_vv) { //Ei mitään tehtävää täällä }

82 Rakentaja (constructor) Sijoitus vs. Alustuslista
Useinmiten sijoituksen ja alustuslistan käytöllä ei ole lopputuloksessa eroa Vakioita ja viittauksia ei kuitenkaan voi alustaa sijoittamalla. Alustuslistaa käyttämällä tämän voi tehdä. Esimerkki: Sijoitusta yrittäen: Luokan kuvaus: ConstRef:: ConstRef (int ii ) { // sijoitus i=ii //OK ci=ii //error: ei voi sijoittaa vakioon ri=i; //error: ri ei ole alustettu } class ConstRef { public: ConstRef( int ii); private: int i; const int ci; int &ri; }; Alustuslistaa käyttäen: ConstRef:: ConstRef (int ii ) :ci(ii),ri(i) //alustus { i=ii; }

83 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 Asiasta puhutaan lisää myöhemmillä luennoilla

84 Parametrillinen rakentaja
Tarjoaa luokan luojalle mahdollisuuden määritellä kullekkin luotavalle oliolle alustettavat arvot Parametrillinen rakentaja on aina ohjelmoijan kirjoittama Samat säännöt kuin oletusrakentajalla. Poikkeus: Parametrillisen rakentajan parametreihin voidaan määritellä tarvittaessa myös oletusarvot (näistäkin lisää myöhemmissä luennoissa) Luokka voi sisältää useita erilaisilla parametreilla varustettuja rakentajia Kääntäjä ei generoi oletusrakentajaa, jos ohjelmoija on määritellyt luokkaan parametrillisen rakentajan

85 Parametrillinen rakentaja Esimerkki
#include <iostream> #include <ctime> Using namespace std; class Pvm { int pp, kk, vv; public: Pvm(const int, const int, const int); //parametrillinen rakentaja 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<<endl; int main(void) Pvm Paiva(3, 3, 2006); //Paiva-olion luonti ja alustus Paiva.nayta(); return 0;

86 Purkaja Tunnetaan myös nimellä Hajoitin Purkajan nimi on ~Luokan_nimi
Purkaja ei saa parametreja Purkajalla ei ole tyyppiä, ei saa palauttaa mitään arvoa Esittelyssä ei saa esiintyä varattuja sanoja const, volatile tai static Purkaja voi olla (suositellaan!!) virtuaalinen (liittyy periytymiseen, tästä puhutaan lisää myöhemmin) Jos purkajaa ei määritellä, kääntäjä luo oletuspurkajan. On kuitenkin suositeltavaa aina itse määritellä purkaja kullekin luokalle

87 Purkaja Purkajaa kutsutaan automaattisesti seuraavissa tilanteissa:
Poistutaan koodialueesta, missä olio on luotu staatisella tavalla Tuhotaan olio delete -komennolla On mahdollista (mutta hyvin harvinaista) kutsua purkajaa eksplisiittisesti. Purkajan kutsu: Olio.Luokka:: ~Luokka(); Olio->Luokka:: ~Luokka(); Purkajan esittely: class Luokka ... public: ~Luokka(); }; Purkajan määrittely: Luokka:: ~Luokka() { tietojäsenten tyhjennys }

88 Lisätään CDog esimerkkiin tuhoaja ja delete kutsu:
CDog.h: #ifndef CDog_H #define CDog_H #include <iostream.h> class CDog { int weight; bool rabidOrNot; std:string name; public: CDog (int x, std::string y); ~CDog(); //tuhoajan esittely bool getRabid ( )const; void setRabid (bool x); std::string getName ( )const; void setName (std::string z); int getWeight ( )const; void setWeight (int x); void eat( ); void growl( )const; }; #endif /* CDog_H */ Zoo.cpp: #include <iostream> #include "CDog.h" void main ( ) { CDog* c1; c1 = new CDog (14, “Bob”); CDog c2 (7, “Ethel”); c2.eat( ); c1->growl( ); delete c1; //tuhotaan olio c1 c1=0; } CDog bool rabidOrNot int weight string name void growl() void eat()

89 CDog.cpp bool CDog::getRabid ( ) const{ return rabidOrNot; }
#include <string.h> #include “CDog.h” using namespace std; // Constructor CDog::CDog (int x, string y) { rabidOrNot = false; weight = x; name = y; } // destructor CDog::~CDog() {} void CDog::eat ( ) { cout << name << “ is eating” << endl; weight++; void CDog::growl ( ) const{ cout << “Grrrr”; bool CDog::getRabid ( ) const{ return rabidOrNot; } void CDog::setRabid (bool x) { rabidOrNot = x; int CDog::getWeight ( ) const{ return weight; void CDog::setWeight (int y) { weight = y; string CDog::getName ( ) const{ return name; void setName (string z) { name = z;

90 Pvm esimerkki #include <iostream> #include <ctime>
Using namespace std; class Pvm{ int pp, kk, vv; public: Pvm(const int, const int, const int); //parametrillinen rakentaja Pvm(); //oletusrakentaja ~Pvm(); //tuhoaja 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; } Pvm::Pvm(const int p_pp, const int p_kk, const int p_vv=06): pp(p_pp), kk(p_kk), vv(p_vv) {} Pvm::~Pvm() { pp = 0; kk = 0; vv = 0; } void Pvm::Nayta() const cout<<pp<<'/'<<kk<<'/'<<vv << endl; int main(void) Pvm Paiva1; Paiva1.Nayta(); Paiva1.Pvm::~Pvm(); Pvm *Paiva2 = new Pvm(2, 2); Paiva2->Nayta(); Pvm Paiva3(4,6,98); Paiva3.Nayta(); delete Paiva2; Paiva2=0; return 0;


Lataa ppt "Olio ohjelmoinnin perusteet luento 3: Johdanto C++ kieleen, Ensimmäinen C++ ohjelma, Olioiden elinkaari Jani Rönkkönen LTY/Tietotekniikan osasto Kalvot."

Samankaltaiset esitykset


Iklan oleh Google