previous next Up Title Contents Index

9.4.7 Yliluokan muodostajan kutsuminen ennen muodostajaa


Joskus kirjoittamalla vähän enemmän voi saada aikaan nopeampaa ja turvallisempaa koodia. Niin tässäkin tapauksessa. Nimittäin säätäminen siinä, ettemme vaivautuneet kirjoittamaan kumpaankin luokkaan erikseen oletusmuodostajaa, johtaa siihen että esimerkiksi alustus
	cAikaSek a4(12,55,45);
kutsuu kaikkiaan seuraavia metodeja:
	cAikaSek::cAikaSek(12,55,45);
	  cAika::cAika(0,0);           // Oletusalustus yliluokalle
	    cAika::aseta(0,0,0);
	      cAika::lisaa(0,0);       // Tässä cAika, koska ei vielä "kasvanut" cAikaSek
	  cAikaSek::aseta(12,55,45);
	    cAika::aseta(12,55);
	      cAikaSek::lisaa(0,0);    // HUOM!  Todellakin cAikaSek::lisaa virt.takia
	        cAika::lisaa(0,0);
	    cAikaSek::lisaa(0,0);
	      cAika::lisaa(0,0);
Olisitko arvannut! Enää ei tarvitse ihmetellä miksi olio- ohjelmat ovat isoja ja hitaita. Totta kai voitaisiin sanoa, että hyvän kääntäjän olisi pitänyt huomata tuosta optimoida päällekkäisyydet pois. Mutta tämä on vielä tänä päivänä kova vaatimus kääntäjälle. Mutta ehkäpä voisimme ohjelmoijina vähän auttaa:

olioalk\aikaclaB.cpp - oletusmuodostajat

	... 
	class cAika {
	  int h,m;
	public:
	  virtual void aseta(int ih=0,int im=0, int is=0) { ... }
	  cAika() { h = 0; m = 0; } // tai cAika() : h(0), m(0) {}  // Oletusmuodostaja
	  cAika(int ih, int im=0) { aseta(ih,im); }                 // ih=0 oletus pois
	  virtual void lisaa(int lisa_min, int lisa_sek=0)  { ... }
	  virtual void tulosta(int lf=1) const  { ... }
	};
	
	class cAikaSek : public cAika {
	  int s;
	public:
	  virtual void aseta(int ih=0, int im=0, int is=0) {...}
	  cAikaSek() : s(0), cAika() {}                             // Oletusmuodostaja
	  cAikaSek(int ih, int im=0, int is=0) : cAika(ih,im), s(is) { lisaa(0); }
	};
	...
Nyt on saatu ainakin seuraavat edut: oletustapauksessa kumpikin luokka alustuu pelkillä 0:ien sijoituksilla, ilman yhtään ylimääräistä kutsua. Oletusmuodostaja luokalla cAika voidaan esitellä esim. seuraavilla tavoilla, joista keskimmäistä voidaan pitää parhaana:
	cAika() { h = 0; m = 0; }   // Normaalit sijoitukset
	cAika() : h(0), m(0) {}     // h:n muodostaja arvolla 0, eli h=0 kokonaisluvulle
	                            // m:n muodostaja arvolla 0, eli m=0
	cAika() : h(0) { m=0; }    
Vastaavasti luokalle cAikaSek pitää oletusmuodostaja tehdä seuraavanlaiseksi:
	cAikaSek() : s(0), cAika() { }      // s alusetetaan 0:ksi ja peritty yliluokka
	                                    // alustetaan muodostajalla cAika()
	cAikaSek() { s = 0; }               // TÄMÄ on TÄSSÄ tapauksessa sama kuin
	                                    // edellinen, koska jos yliluokan muodostajaa
	                                    // ei itse kutsuta, kutsutaan 
	                                    // oletusmuodostajaa
ELI! Perityn yliluokan muodostajaa kutsutaan automaattisesti, jollei sitä itse tehdä. Nyt parametrillisessa muodostajassa kutsutaan yliluokan muodostajaa, ja näin voidaan välttää ainakin oletusmuodostajan kutsu:
	cAikaSek(int ih, int im=0, int is=0) : cAika(ih,im), s(is) { lisaa(0); }
Nyt alustuksesta
	cAikaSek a4(12,55,45);
seuraa seuraavat metodikutsut
	cAikaSek::cAikaSek(12,55,45);
	  cAika::cAika(12,55);           //  NYT EI oletusalustusta yliluokalle
	    cAika::aseta(12,55,0);
	      cAika::lisaa(0,0);
	  cAikaSek::lisaa(0,0);
	    cAika::lisaa(0,0);
Turhaahan tuossa on vieläkin, mutta tippuihan kuitenkin noin puolet pois! Joka tapauksessa periminen tuottaa jonkin verran koodia, aina kun yliluokan metodeja käytetään hyväksi. Ja jollei käytettäisi, kirjoitettaisiin samaa koodi uudelleen, eli palattaisiin 70- luvulle. Nykyisin kasvanut koneteho kompensoi kyllä tehottomamman oliokoodin ja olio- ohjelmoinnin ansiosta pystytään kirjoittamaan luotettavampia (?) ja monimutkaisempia ohjelmia.

Tehtävä 9.86 Yliluokan alustajan kutsu

Pöytätestaa sekä aikaclaA.cpp että aikaclaB.cpp alustuksella cAikaSek a4(1,95,70);


previous next Up Title Contents Index