Funktiot
Parametrien välitys arvona ja viitteenä
C++:ssa muuttujan määrittelyn yhteydessä voi päättää, luodaanko uusi muuttuja vai viite jo olemassa olevaan muuttujaan. Tämä vaikuttaa myös siihen, miten funktion parametrit toimivat.
Todelliset parametrit kirjoitetaan funktion kutsussa. Muodolliset parametrit määritellään funktion otsikossa, ja niiden avulla funktion rungossa käsitellään kutsussa annettuja arvoja.
Arvoparametrit
C++:ssa parametrit välitetään oletusarvoisesti arvona. Funktio saa tällöin parametrina annetusta arvosta oman kopionsa:
#include <iostream> using namespace std; void arvoparametrifunktio(int luku) { luku = 2 * luku; } int main() { int muuttuja = 7; cout << muuttuja << endl; // Tulostaa 7 arvoparametrifunktio(muuttuja); cout << muuttuja << endl; // Tulostaa edelleen 7 }
Muodollinen parametri luku on uusi muuttuja, joka alustetaan todellisen parametrin muuttuja arvolla 7. Funktion muuttama kopio ei vaikuta alkuperäiseen muuttujaan.
Viiteparametrit
Muodollisen parametrin voi määritellä viitteeksi kirjoittamalla &-merkin tyypin ja parametrin nimen väliin. Viiteparametri on lisänimi kutsussa annetulle muuttujalle, joten funktion tekemät muutokset näkyvät myös kutsukohdassa.
#include <iostream> using namespace std; void viiteparametrifunktio(int& luku) { luku = 2 * luku; } int main() { int muuttuja = 7; cout << muuttuja << endl; // Tulostaa 7 viiteparametrifunktio(muuttuja); cout << muuttuja << endl; // Tulostaa 14 }
Tässä parametri luku viittaa muuttujaan muuttuja, joten arvon kaksinkertaistaminen muuttaa suoraan alkuperäistä muuttujaa.
Viiteparametrille on annettava muuttuja, johon viite voi sitoutua. Esimerkiksi kokonaislukuliteraali 7 ei ole muuttuja, joten sitä ei voi välittää tavalliselle muokattavalle viiteparametrille:
void viiteparametrifunktio(int& luku) { luku = 2 * luku; } int main() { viiteparametrifunktio(7); // VIRHE: literaali ei ole muuttuja }
Pythonin parametrit
Pythonissa parametri ei ole C++-tyylinen arvoparametri tai viiteparametri. Python välittää olioita koskevia viitteitä eli nimi sidotaan kutsussa annettuun olioon. Jos olio on muuttuva, sen muuttaminen funktion sisällä näkyy kutsukohdassa; parametrin uudelleensitominen paikalliseen nimeen ei muuta kutsujan nimeä. Muuttumattoman olion, kuten kokonaisluvun, muuttaminen ei onnistu, joten se voi näyttää siltä kuin parametri olisi välitetty arvona.
Vakioviiteparametrit
Jos funktio saa lukea parametria mutta sen ei pidä muuttaa sitä, parametri voidaan määritellä const-vakioksi. Esimerkiksi:
void tulosta_sana(string const& sana) { cout << sana << endl; string paikallinen_sana = sana; }
Kääntäjä sallii parametrin lukemisen ja arvon kopioimisen paikalliseen muuttujaan, mutta estää parametrin muuttamisen:
void tulosta_sana(string const& sana) { sana = "uusi sana"; // VIRHE: const-parametria ei voi muuttaa } int main() { tulosta_sana("moi"); // Sallittu: const-viite voi sitoutua tilapäiseen arvoon }
const string& on hyödyllinen yhdistelmä: se välittää viitteen eikä kopioi koko merkkijonoa, mutta funktio ei voi muuttaa merkkijonoa tämän parametrin kautta. Myös merkkijonoliteraalin kutsussa muodostama tilapäinen string-arvo voi sitoutua tällaiseen vakioviitteeseen.
Vakioviiteparametrin käyttäminen arvoparametrin sijasta ei ole tarpeen pienille tyypeille, kuten int. Niiden kopioiminen on edullista, eikä viitteestä yleensä saada tehokkuushyötyä.
Yleinen nyrkkisääntö: välitä pieni perustyyppi, kuten int, arvona. Välitä suuri tietorakenne const-viitteenä, jos funktion ei tarvitse muuttaa sitä. Käytä muokattavaa viitettä, kun funktion on tarkoitus muuttaa kutsujan muuttujaa.
Kokeile itse: ennusta tulos
Mitä ohjelma tulostaa, kun funktiolle annetaan muuttuja luku?
void kasvata(int& arvo) { ++arvo; } int main() { int luku = 4; kasvata(luku); cout << luku; }
arvo on viite muuttujaan luku. Kasvatus muuttaa siis kutsukohdan muuttujaa, ja tuloste on 5.