Ylös Edellinen Seuraava Otsikkosivu Hakemisto Sisällys

9.4.6 Myöhäinen sidonta

Ongelma täytyy ratkaista siten, että jo alkuperäisessä luokassa kerrotaan että vasta ohjelman suoritusaikana selvitetään mistä luokasta todella on kyse, kun metodia kutsutaan. Tällaista ominaisuutta sanotaan myöhäiseksi sidonnaksi ( late binding) (tälle monisteellekin tulee kyllä myöhäinen sidonta), vastakohtana sille, jota olemme edellä käyttäneet, eli aikainen sidonta ( early binding ). Sidonnan sisäisen mekanismin opettelun jätämme jollekin toiselle kurssille (ks. vaikkapa Olio- ohjelmointi ja C++/VL ).

Myöhäinen sidonta saadaan C++:ssa aikaan liittämällä virtual- avainsana metodien eteen. Kaikki ne metodit täytyy ilmoittaa myöhäiseen sidontaan, joita mahdolliset perilliset tulevat muuttamaan. Siis luokat vielä kerran remonttiin:

olioalk\aikacla9.cpp - myöhäinen sidonta

	#include <iostream.h>
	#include <iomanip.h>
	
	class cAika {
	  int h,m;
	public:
	  virtual void aseta(int ih,int im=0) {                      // lisätty virtual
	    h = ih; m = im; lisaa(0);
	  }
	  cAika(int ih=0, int im=0) { aseta(ih,im); }
	  virtual void lisaa(int lisa_min)  {                        // lisätty virtual
	    int yht_min = h * 60 + m + lisa_min;
	    h = yht_min / 60;
	    m = yht_min % 60;
	  }
	  virtual void tulosta(int lf=1) const  {                    // lisätty virtual
	    cout << setfill('0') << setw(2) << h << ":" << setw(2) << m;
	    if ( lf ) cout << endl;
	  }
	};
	
	class cAikaSek : public cAika {
	  int s;
	public:
	  virtual void aseta(int ih=0, int im=0) { cAika::aseta(ih,im); } // lisätty
	  virtual void aseta(int ih, int im, int is) {               // lisätty virtual
	    s = is; aseta(ih,im); lisaa(0,0);                        // pois cAika::
	  }
	  cAikaSek(int ih=0, int im=0, int is=0) { aseta(ih,im,is); }
	  virtual void lisaa(int lisa_min) { cAika::lisaa(lisa_min); } // lisätty
	  virtual void lisaa(int lisa_min, int lisa_sek) {           // lisätty virtual
	    s += lisa_sek; lisaa(lisa_min+s/60); s %= 60;            // pois cAika::
	  }
	  virtual void tulosta(int lf=1) const  {                    // lisätty virtual
	    cAika::tulosta(0);
	    cout <<  ":" << setw(2) << s;
	    if ( lf ) cout << endl;
	  }
	};
	
	
	int main(void)
	.. kuten  aikacla8.cpp + cAika *pAika; ...

Virtual sanat on lisätty kaikkien metodien eteen. Aliluokassa virtual on tarpeeton uudelleenmääriteltävien (korvaaminen, syrjäyttäminen, overriding) metodien kohdalle, mutta se on hyvä pitää siellä kommenttimielessä.

Sitten tuleekin hankalammin selitettävä asia. Miksi yksi-parametrinen lisaa ja kaksi-parametrinen aseta on täytynyt kirjoittaa uudelleen? Tämä johtuu kielen ominaisuuksista, sillä muuten vastaavat useampi-parametriset metodit syrjäyttäisivät alkuperäiset metodit ja alkuperäisiä ei olisi lainkaan käytössä. Tässä tapauksessa olisimmekin voineet antaa niiden syrjäytyä, mutta koska tulevaisuudesta ei koskaan tiedä, on alkuperäiselläkin parametrimäärällä olevien metodien ehkä hyvä säilyä.

Parempi ratkaisu olisi ehkä kuitenkin ollut, jos jo alkuperäisessä luokassa olisi varauduttu sekuntien tuloon, vaikka niitä ei olisi mitenkään otettukaan huomioon:

olioalk\aikaclaA.cpp - myöhäinen sidonta, sekunnit jo kantaluokassa

	... 
	class cAika {                           // Muutokset aikacla8.cpp:hen verrattuna
	  int h,m;
	public:
	  virtual void aseta(int ih=0,int im=0, int lisa_sek=0) {   // virtual, lisa_sek
	    h = ih; m = im; lisaa(0);
	  }
	  cAika(int ih=0, int im=0) { aseta(ih,im); }
	  virtual void lisaa(int lisa_min, int lisa_sek=0)  {       // virtual, lisa_sek
	    int yht_min = h * 60 + m + lisa_min;
	    h = yht_min / 60;
	    m = yht_min % 60;
	  }
	  virtual void tulosta(int lf=1) const  { ... }                // virtual
	};
	
	class cAikaSek : public cAika {
	  int s;
	public:
	  virtual void aseta(int ih=0, int im=0, int is=0) {           // virtual
	    s = is; cAika::aseta(ih,im); lisaa(0);                     // järj. vaihd.
	  }
	  cAikaSek(int ih=0, int im=0, int is=0) { aseta(ih,im,is); }
	  virtual void lisaa(int lisa_min, int lisa_sek=0) {           // virtual
	    s += lisa_sek; cAika::lisaa(lisa_min+s/60); s %= 60; 
	  }
	  virtual void tulosta(int lf=1) const  {                      // virtual
	};
	...
	int main(void)
	{
	...
	  cAika *pAika;
	  pAika = &a1;  pAika->tulosta();
	  pAika = &a4;  pAika->tulosta();
	  return 0;
	}

Varoitus: Borlandin C++5.1 :en optimoivalla kääntäjällä käännettynä em. koodi kaatoi kääntäjän ympäristöineen jos cAikaSek::aseta oli muodossa:

	cAika::aseta(ih,im); s = is; lisaa(0);	:-(

Tehtävä 9.84 Miksi ensin sekuntien alustus?

Osaatko selittää miksi sekunnit pitää alustaa ensin metodissa: cAikaSek::aseta? Jos osaat, olet jo melkein valmis C++- ohjelmoija!

Tehtävä 9.85 2-3 - parametrinen aseta

Onko nyt olemassa 2 ja 3 - parametrinen aseta- metodi?

Ylös Edellinen Seuraava Otsikkosivu Hakemisto Sisällys