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:
... 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 parametrillisessä 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.