11. Luokka Opetellaan seuraavaksi, miten omia luokkia kirjoitetaan. Aikaisemmin olikin jo esillä, että luokka on tietorakenne, joka sisältää sekä tiedot (attribuutit) että niitä käsittelevät aliohjelmat (palvelut) yhdessä kokonaisuudessa. Luokan määrittely: class class_name access_specifier_1: member1; access_specifier_2: member2;... object_names; Luokan määrittely alkaa avainsanalla class. Sen jälkeen tulee luokan nimi ennen aaltosulkua. Luokan sisällä määritellään luokan jäsenet (joko tieto- tai aliohjelmajäseniä). Jokaiseen jäseneen liittyy suojausmääre (access_specifier) private, protected tai public, joka kertoo, miten jäsen näkyy luokan ulkopuolelle. private: vain luokan jäsenillä ja ystävillä (friend) on oikeus käsitellä jäseniä protected: edellisten lisäksi luokasta periytyvillä johdetuilla luokilla on oikeus käsitellä jäseniä kaikilla näkyvyysalueella olevilla olioilla ja funktioilla on oikeus käsitellä luokan jäseniä. Private-määre on oletus. Luokan määrityksen loppuun voidaan lisät halutun nimisiä olioita 1
(object_names),mutta sitä ei ole pakko tehdä tässä kohdassa. Esimerkki: Tässä luodaan suorakulmio-luokka CRectangle, jossa on kaksi yksityistä tietojäsentä x ja y (sivun pituudet), sekä kaksi julkista jäsenfunktiota set_values ja area. Lopuksi luodaan tätä luokkatyyppiä oleva olio nimeltä rect. class CRectangle int x, y; void set_values (int,int); int area (void); rect; HUOM! On tärkeää erottaa toisistaan luokan nimi (CRectangle) ja olion nimi (rect). Luokan nimi vastaa perinteisen ohjelman tietotyyppiä (esim. int) ja olion nimi muuttujaa (esim. x). Oliot kommunikoivat luokan funktiojäsenien kanssa lähettämällä viestejä, jotka vastaavat aliohjelman kutsuja. Esimerkiksi rect.set_values (3,4); myarea = rect.area(); Edellinen rivi asettaa suorakulmion muuttujien x ja y arvoiksi 3 ja 4. Jälkimmäinen laskee suorakulmion pinta-alan ja sijoittaa tuloksen muuttujaa myarea. Tietojäseniin x ja y ei voi viitata suoraan pääohjelmasta tai muusta aliohjelmasta, koska ne ovat yksityisiä. Ainoastaan luokan julkisilla funktiojäsenillä set_values ja area on oikeus siihen. Seuraavassa on esitetty koko toimiva ohjelma. 2
// classes example #include <iostream> using namespace std; class CRectangle int x, y; void set_values (int,int); int area () return (x*y); ; void CRectangle::set_values (int a, int b) x = a; y = b; int main () CRectangle rect; rect.set_values (3,4); cout << "area: " << rect.area(); return 0; Tässä on luokan funktiojäsenet toteutettu kahdella tavalla. Funktiosta set_values esitetään luokassa ainoastaan prototyyppi eli palvelu. Varsinainen runko-osa eli metodi on esitetty luokan ulkopuolella. Funktio area on kokonaisuudessaan toteutettu luokan sisällä. Molemmat tavat ovat yhtä oikein ; on makuasia kumpaa tapaa haluaa käyttää. Luokan sisällä määritelty funktio on automaattisesti ns. inline-funktio. Menemättä tässä yhteydessä kovin syvälle C++-kääntäjien sielunelämään, riittänee tietää, että inlineksi määritelty funktio saattaa joissakin tapauksissa olla nopeampi suorittaa kuin ei-inline funktio. Suositus on, että ainostaan muutaman rivin mittainen funktio kannattaa koodata inline-funktioksi. Pidemmät inline-funktiot tekevät luokasta helposti vaikealukuisen ja suoritettavan exe-tiedoston koko kasvaa turhan suureksi. Symboli :: on ns. luokkaresoluutio-operaattori. Sitä tarvitaan luokan ulkopuolisen metodin edessä kertomaan, mihin luokkaan kyseinen metodi kuuluu. Esimerkiksi meillä voi olla useita luokkia, joissa on käytössä set_values-niminen metodi, jotka toimivat eri lailla. Silloin täytyy olla joku keino määrittää, minkä luokan set_values-metodista on kysymys. 3
Monesti on välttämätöntä alustaa luokan tietojäsenet johonkin alkuarvoon. Tämä voidaan tehdä muodostimen (constructor) avulla. Muodostimia on kolmenlaisia: Oletusmuodostin alustaa olion automaattisesti johonkin alkuarvoon, ellei sitä erikseen alusteta parametrillisella tai kopiointimuodostimella. Parametrillinen muodostin alustaa olion määriteltyihin alkuarvoihin. Alustus tapahtuu parametrien välityksellä, kuten funktiokutsussa. Kopiointimuodostin alustaa olion jonkin toisen olion arvoihin. Hajotinta (destructor) kutsutaan, kun olio tuhotaan. Automaattinen olio tuhoutuu automaattisesti, kun poistutaan sen määrittelyalueesta (lohkosta). Staattinen olio tuhoutuu ohjelman lopussa. Dynaaminen olio on erikseen tuhottava delete-operaattorilla. Tässä esimerkkiohjelmassa kaikki kolme luku-oliota ovat automaattisia. Ne tuhoutuvat käänteisessä järjestyksessä luontiin verrattuna. Ohjelman muodostimet ja hajotin ilmaisevat keskusmuistiosoitteensa this-osoittimen avulla. This-osoitin osoittaa aina sillä hetkellä aktiivisena olevaan olioon. #include <iostream> using namespace std; class luku private: int x; //Oletusmuodostin alustaa olion nollaksi luku() cout << "Luotiin olio oletusmuodostimella"; cout << " osoitteessa " << this << endl; x=0; //Parametrillinen muodostin //Alustaa olion arvoon param. luku(int param) 4
; cout << "Luotiin olio parametrillisella "; cout << "muodostimella osoitteessa " << this << endl; x=param; //Kopiointimuodostin alustaa olion //jonkin toisen olion arvoilla luku(const luku &olio) cout << "Luotiin olio kopiointimuodostimella "; cout << "osoitteessa " << this << endl; x=olio.x; //Hajotin ~luku() cout << "Tuhottiin olio osoitteessa " << this << endl; //Palvelut void setvalue(); int getvalue() const; int main() luku a;//luonti oletusmuodostimella luku b(2);//luonti param. muodostimella luku c=b; //Luonti kopiointimuodostimella cout << "a = " << a.getvalue() << endl; cout << "b = " << b.getvalue() << endl; cout << "c = " << c.getvalue() << endl; return 0; void luku::setvalue() cout << "Luku?" << endl; cin >> x; int luku::getvalue() const return(this->x); //sama kuin return(x); 5