C++ v rámci větší uživatelské přítulnosti poskytuje kromě přetěžování (overload) funkcí/metod také implicitní (default) hodnoty parametrů funkcí/metod (na rozdíl od Javy, u které mně tento syntaktický cukr celkem chybí). Většina programátorů v C++ o tom ví a tuto skutečnost využívá. Co už se ale ví méně, je to, že implicitního parametr funkce nemusí být konstanta. V tomto příspěvku se nebudu zabývat tím, do jaké míry je to vhodné a použitelné (ve většině případů to totiž opravdu vhodné není), ale pouze tím, co C++ v tomto směru umožňuje.
Standard C++98 říká (sekce 8.3.6 - Default arguments), že implicitním argumentem je výraz (expression). Pro úplnost dodávám, že na tento výraz jsou kladena určitá omezení (např. se nesmí jednat o lokální proměnnou, this
atd., viz norma), ale ukázky v tomto příspěvku budou validní. Jdeme tedy na to.
Implicitní hodnotou parametru je hodnota statické proměnné
Na začátek něco jednoduchého.
#include <iostream> using namespace std; class A { public: static int defX; static void f(int x = defX) { cout << "f(): " << x << endl; } }; int A::defX = 5; int main() { A::f(); // Prints "f(): 5" A::defX = 13; A::f(); // Prints "f(): 13" }
Podobný kód je velice běžný, ovšem s tou výjimkou, že defX
bývá konstanta. Zde tomu ovšem tak není a jak vidíme, tak výstup volání metody A::f()
se liší podle toho, jakou hodnotu má statická proměnná defX
třídy A
.
Implicitní hodnotou parametru je výsledek volání funkce
Nyní něco zajímavějšího.
#include <iostream> #include <cstdlib> using namespace std; class B { public: static void f(int x = rand()) { cout << "f(): " << x << endl; } }; int main() { B::f(); // Prints "f(): 1804289383" B::f(); // Prints "f(): 846930886" }
Norma nám zaručuje, že výraz, který tvoří implicitní hodnotu parametru, bude vyhodnocen při každém volání funkce/metody (což bylo ostatně potřeba už v minulém příkladu). Nic nám tedy nebrání na místo implicitní hodnoty parametru dát volání funkce rand()
(mimochodem, po absolvování kurzu funkcionálních jazyků se mně začíná příčit nazývat "funkci" rand()
funkcí :), ale ve smyslu jazyka C++ to funkce je). Při každém zavolání metody f()
třídy B
tedy dojde k vypsání pseudonáhodného čísla.
Změna hodnoty implicitního parametru změnou deklarace funkce
A nakonec něco divočejšího.
#include <iostream> using namespace std; void f(int x = 2) { cout << "f(): " << x << endl; } int main() { f(); // Prints "f(): 2" void f(int x = 7); f(); // Prints "f(): 7" ::f(); // Prints "f(): 2" }
Po prvním zavolání funkce f()
dojde k výpisu čísla 2, ale stačí na lokální úrovni změnit deklaraci funkce f()
a při jejím následném zavolání dostaneme změněný výpis. Pokud bychom nyní chtěli zavolat funkci f()
z deklarace na globální úrovni, lze použít operátor ::
. Detaily viz norma C++98, sekce 8.3.6.4 a 5.1.4.