Při programování v C++ se s předáváním parametrů setkáváme neustále. Zároveň je mnoho způsobů, jak parametr předat. Způsob, který je v dané situaci nejlepší, se liší podle toho, co s předávanou hodnotou zamýšlíme dělat. Proto parametry funkcí rozlišujeme na:
Dejme tomu, že se snažíme funkci předat proměnnou typu T.
T), konstantní referencí (const T&), nebo ukazatelem na konstatní hodnotu (const T*).
return.
T&) nebo ukazatelem (T*).
Tím, jak proměnnou předáme, také dokumentujeme, co s proměnnou děláme uvnitř funkce.
Začněme tímto jednoduchým programem:
#include <iostream> #include <vector> #include <string> int main() { std::vector<std::string> jmena = { "Petr", "Jan", "Jana", "Karel", "Katka" }; for (const auto& s : jmena) { std::cout << s << '\n'; } }
Tento program vypíše:
Petr Jan Jana Karel Katka
Naším cílem bude upravit tento program tak, aby přidal oslovení ke každému jménu, a následně je vypsal:
pan Petr pan Jan slecna Jana pan Karel slecna Katka
Doporučujeme postupovat tak, že
Pohlavi a funkci, která pro std::string vždy vrátí Pohlavi::muz (nebo zena).
Mohou se hodit některé z těchto metod vectoru a stringu:
.size() poskytne počet prvků ve vektoru, příp. počet znaků v řetězci.
.empty() rozhodne, zda počet prvků ve vektoru je 0, příp. počet znaků v řetězci je 0.
.front() poskytne referenci na první prvek, příp. znak.
.back() poskytne referenci na poslední prvek, příp. znak.
Navíc string má k dispozici operátor +, který zřetězí (spojí) dva řetězce.
Zkopírujte si následující kód:
#include <iostream> enum class Mesic { leden, unor, brezen, duben, kveten, cerven, cervenec, srpen, zari, rijen, listopad, prosinec }; void vypis(std::ostream& out, Mesic m) { switch (m) { case Mesic::leden: out << "1."; break; case Mesic::unor: out << "2."; break; case Mesic::brezen: out << "3."; break; case Mesic::duben: out << "4."; break; case Mesic::kveten: out << "5."; break; case Mesic::cerven: out << "6."; break; case Mesic::cervenec: out << "7."; break; case Mesic::srpen: out << "8."; break; case Mesic::zari: out << "9."; break; case Mesic::rijen: out << "10."; break; case Mesic::listopad: out << "11."; break; case Mesic::prosinec: out << "12."; break; } } Mesic dalsiMesic(Mesic m) { switch (m) { case Mesic::leden: return Mesic::unor; case Mesic::unor: return Mesic::brezen; case Mesic::brezen: return Mesic::duben; case Mesic::duben: return Mesic::kveten; case Mesic::kveten: return Mesic::cerven; case Mesic::cerven: return Mesic::cervenec; case Mesic::cervenec: return Mesic::srpen; case Mesic::srpen: return Mesic::rijen; case Mesic::zari: return Mesic::zari; case Mesic::rijen: return Mesic::listopad; case Mesic::listopad: return Mesic::prosinec; case Mesic::prosinec: return Mesic::leden; } } int main() { Mesic m1 = Mesic::leden; Mesic m2 = Mesic::prosinec; vypis(std::cout, m1); std::cout << '\n'; vypis(std::cout, m2); std::cout << '\n'; vypis(std::cout, dalsiMesic(m1)); std::cout << '\n'; vypis(std::cout, dalsiMesic(m2)); std::cout << '\n'; }
Úkoly:
vypis tak, aby neobsahovala příkaz switch se dvanácti návěštími case. K tomu je možné využít static_cast<int>(m), kde m je proměnná typu měsíc – takto získáme číslo, pomocí kterého je položka enumerace reprezentována.
dalsiMesic. Použítím static_cast<Mesic>(cislo) naopak získáme položku enumerace z čísla.
predchoziMesic.
Datum, která obsahuje den, měsíc a rok.
vypis pro typ Datum. Datum se vypíše do daného proudu ve formátu den. mesic. rok.
pocetDni(mesic, rok), která vrátí, kolik dní obsahuje daný měsíc v daném roce.
pocetDni(rok), která vrátí, kolik dní obsahuje daný rok.
pridejRok(datum, pocet), která k danému datu přičte daný počet let.
pridejMesic(datum, pocet), která k danému datu přičte daný počet měsíců.
pridejDen(datum, pocet), která k danému datu přičte daný počet dní.
pridejRok, pridejMesic a pridejDen tak, aby mohl být počet přičtených let/měsíců/dní záporný.
Na prvním cvičení jsme se zmínili o tom, že přístup mimo alokované pole je nedefinované chování, ale neukázali si k čemu to může vést. Tentokrát si to ukážeme.
Následující program obsahuje drobnou chybu v přístupu do pole čísel, která může vést k přístupu mimo pole (a tudíž k nedefinovanému chování). Zkuste si ho zkompilovat a spustit, nejdříve bez optimalizací, poté s nimi:
#include <iostream> #include <iomanip> int elements[] = {1, 2, 3, 4}; bool contains(int elem) { for (int i = 0; i <= 4; ++i) { if (elements[i] == elem) { return true; } } return false; } int main() { int num; while (std::cin >> num){ std::cout << std::boolalpha << contains(num) << '\n'; } }