Dynaaminen muistinhallinta
Funktio-osoittimet
Ohjelmissa käsitellään sekä tietoa että toimintoja. Funktiotkin ovat tietoa: C++:ssa funktion osoitteen voi tallentaa muuttujaan tai välittää toiselle funktiolle. Tähän käytetään funktio-osoitinta.
Funktiota, joka ottaa parametrinaan toisen funktion tai palauttaa funktion, kutsutaan korkeamman asteen funktioksi (higher-order function). Funktiot, jotka eivät tee kumpaakaan, ovat ensimmäisen asteen funktioita.
Numeerinen integrointi
Tutustu esimerkkiin hakemistossa examples/06/integral/. Numeerisessa integroinnissa arvioidaan funktion kuvaajan ja x-akselin väliin jäävää pinta-alaa jakamalla alue kapeisiin suorakulmioihin. Suorakulmioiden pinta-alat lasketaan yhteen.
Kuvassa vihreiden suorakulmioiden summa muodostaa alasumman ja keltaisten ylärajaa kuvaavan yläsumman. Esimerkkiohjelmassa suorakulmion korkeus valitaan funktion arvosta suorakulmion keskikohdassa. Kun suorakulmioiden määrää kasvatetaan ja niiden leveyttä pienennetään, likiarvo yleensä tarkentuu.
Ohjelman integrate-funktio saa integroitavan funktion ensimmäisenä parametrinaan:
double integrate(Func f, double left, double right, int number_of_partitions = 500);
Parametrin tyyppi Func määritellään esimerkiksi näin:
using Func = double (*)(double);
Tämä tarkoittaa osoitinta funktioon, joka palauttaa double-arvon ja ottaa yhden double-parametrin. Tässä syntaksissa ensimmäinen double on funktion paluuarvon tyyppi, (*) ilmaisee funktio-osoittimen ja viimeisten sulkeiden sisällä luetellaan funktion parametrit.
Saman tyypin voi johtaa olemassa olevasta funktiosta decltype-avainsanalla. Jos polynomial on tyyppiä double polynomial(double), voidaan kirjoittaa:
using Func = decltype(&polynomial);
Myös koko parametrin tyypin voi kirjoittaa suoraan ilman tyyppialiasta:
double integrate(double (*f)(double), double left, double right, int number_of_partitions = 500);
Funktiokutsuissa osoittimen voi antaa funktion nimellä. Esimerkiksi sin välittää sinifunktion osoitteen; sulkeita ei kirjoiteta, sillä tässä ei vielä kutsuta funktiota:
cout << integrate(sin, 0, 2) << endl; cout << integrate(cos, 0, 2) << endl; cout << integrate(sqrt, 0, 2) << endl; cout << integrate(polynomial, 0, 2) << endl;
integrate voi tämän ansiosta käyttää samaa pinta-alan laskentamenetelmää monelle eri funktiolle. Funktion osoittimen tyyppi asettaa kuitenkin vaatimuksen: annettavan funktion on palautettava double ja otettava yksi double-parametri.
Funktio-osoittimien käyttökohteita
- Toiminnan valinta: ohjelman suoritettava toiminto voidaan valita funktion osoittimen perusteella. Tämä voi korvata suuren
if-rakenteen, jonka haarat valitsevat eri toimintoja. Aihe liittyy myös tieto-ohjattuun ohjelmointiin ja esimerkkiinexamples/03/datadrivenprogramming. - Käyttöliittymät: graafisen käyttöliittymän komponenttiin voidaan liittää toiminto, joka suoritetaan esimerkiksi painiketta painettaessa.
Ydinajatus: funktio-osoittimen avulla funktio voidaan antaa toiselle funktiolle parametrina. Näin kutsuva koodi voi määritellä, mitä toimintaa yleiskäyttöinen funktio suorittaa.