previous next Up Title Contents Index

19.3 Funktiomallit (template- funktiot)

Funktio ota_seuraava C- merkkijonoa varten voidaan tehdä seuraavasti:

talletus.2\jasen.cpp - ota_seuraava

	static int ota_seuraava(istream &is, char *s, int max_koko, char erotin)
	{
	  if ( max_koko <= 0 ) return 0;
	  s[0] = 0;
	  if ( !is ) return 1;
	  is.getline(s,max_koko,erotin);
	  poista_tyhjat(s);
	  return ( is == 0 );
	}
Tätä käyttäen voimme tehdä saman funktion kuormitettuja versioita muille tietotyypeille:
	int ota_seuraava(istream &is, double &d,  char erotin)
	{
	  char s[100];
	  int err = ota_seuraava(is,s,sizeof(s),erotin);
	  d = jono_doubleksi(s,"%lf");
	  return err;
	}
	int ota_seuraava(istream &is, int &i,  char erotin)
	{
	  char s[100];
	  int err = ota_seuraava(is,s,sizeof(s),erotin);
	  i = jono_intiksi(s,"%d");
	  return err;
	}
Ja vielä tarvittaisiin lisää! Kuitenkin nämä näyttävät keskenään yllättävän samanlaisilta. Kirjoittamalla pari apualiohjelmaa ja vaihtamalla nimiä saadaankin niistä täsmälleen samanlaisia:
	int ota_seuraava(istream &is, double &a,  char erotin)
	{
	  char s[100];
	  int err = ota_seuraava(is,s,sizeof(s),erotin);
	  muunna_jono(s,a);
	  return err;
	}
	
	int ota_seuraava(istream &is, int &a,  char erotin)
	{ ... ihan sama ... }
	
	inline void muunna_jono(const char *s,int &i)
	{
	  i = jono_intiksi(s,"%d");
	}
	
	inline void muunna_jono(const char *s,double &d)
	{
	  d = jono_doubleksi(s,"%lf");
	}
Seuraavaksi herääkin kysymys: Kannattaako ota_seuraava- funktiota kirjoittaa erikseen useita eri versioita yhden sanan muutoksella. Kyllähän näitä leikkaa- liimaa - menetelmällä syntyy kuin sieniä sateella, mutta entäpä ylläpito, jos yleiseen kaavaan tuleekin pieni muutos. Kokemus osoittaa että jostakin "samanlaisesta" funktiosta muutos unohtuu ja virhe paljastuu vasta aikojen kuluttua!

Onneksi C++:ssa on apu tätä varten: funktiomallit (function template). Idea on siinä, että jokin yleinen funktio kirjoitetaan tyyppiä vaille valmiiksi ja kääntäjä generoi sitten tästä mallista (muotista) tarvittavan määrän vastaavia todellisia funktioita niille tyypeille, joilla funktiota kutsutaan:

	template <class TYPE>
	int ota_seuraava(istream &is, TYPE &a,  char erotin)
	{
	  char s[100];
	  int err = ota_seuraava(is,s,sizeof(s),erotin);
	  muunna_jono(s,a);
	  return err;
	}
Jos nyt on esimerkiksi kutsu:
	int i;
	ota_seuraava(is,i,'|');
generoituu tästä funktio jossa TYPE on korvattu tyypillä int:
	int ota_seuraava(istream &is, int &a,  char erotin);
Nyt joudumme kirjoittamaan vaan muunna_jono- funktion kutakin eri tietotyyppiä varten. Tämä ei ole kohtuuton vaatimus, sillä kullekin tietotyypille olisi hyvä olla tapa muuntaa se merkkijonoksi (meillä jonoksi) ja päinvastoin.

Siis jos lisätään uusi tietotyyppi, kirjoitetaan funktiot:

	void muunna_jono(const char *s,uusi_tyyppi &u);
	string jonoksi(const uusi_tyyppi &u);


previous next Up Title Contents Index