Funkcje

virus1441

     1 Podstawowe informacje
          1.1 Przykłady
     2 Wywoływanie funkcji
          2.2 Przykład
     3 Funkcje inline
     4 Przeładowanie nazwy funkcji

W programowaniu mianem funkcji określa się fragment kodu, który może być wykonywany wielokrotnie z różnych miejsc programu.

Podstawowe informacje

Ogólny zapis funkcji wygląda tak:
typ nazwa(argumenty)
{
  ciało funkcji
}

Typ określa, jaki typ danych zwraca ta funkcja, tzn. do zmiennej jakiego typu można przypisać wynik funkcji. Funkcja może nie zwracać żadnego typu, wtedy jej typem jest Void - jeśli znasz Pascala łatwiej Ci to będzie porównać do procedur. Do zwracania danej wartości przez funkcję odpowiada słowo kluczowe Return. Nazwa służy do identyfikowania funkcji w programie. Nazwa funkcji nie zawsze jednoznacznie identyfikuje funkcję. Argumenty określają, jakiego typu zmienne należy przekazać do funkcji przy jej wywoływaniu. W przypadku, kiedy nazwa nie identyfikuje jednoznacznie funkcji (istnieją dwie różne funkcje o tych samych nazwach), parametry tych funkcji muszą się różnić. Mamy wtedy doczynienia z przeładowaniem nazwy funkcji (patrz niżej). Argumenty funkcji mogą przyjmować wartości domyślne. Należy w takim przypadku po nazwie argumentu dodać znak równości i wartość domyślną. Ciało funkcji jest to kod, który zostanie wykonany po wywołaniu funkcji.

Przykłady

Funkcja nie zwracająca wyniku, nie przyjmująca argumentów (typu [[C/Void]]):
void foo()
{
  cout << "tekst\n";
}

Funkcja nie zwracająca wyniku, przyjmująca parametr bez wartości domyślnych:

void foo(char *tekst)
{
  cout << tekst;
}

Funkcje zwracająca wynik, przyjmująca parametry bez wartości domyślnych:

int foo(int a, int b)
{
  return a + b;
}

int foo2(int a, int b)
{
   int c = a + b;
   return c;
}

Funkcja zwracająca wynik, przyjmująca parametry z wartością domyślną:

int foo(int a, int b = 0)
{
   return a + b;
}

Wywoływanie funkcji

Aby wywołać w programie przygotowaną wcześniej funkcję, należy po prostu wpisać w odpowiednim miejscu jej nazwę, a w nawiasach okrągłych argumenty do tej funkcji. Wywoływana funkcja musi zawsze być zadeklarowana przed miejscem, gdzie została wywołana. Można przed wywołaniem funkcji napisać tylko jej deklarację, zaś definicję (ciało) w dowolnym miejscu programu.

W językach C/C++ jeśli funkcja nie posiada argumentów należy ją wywoływać stawiając za jej nazwą pusty nawias, np foo()

Przykład

```cpp #include <iostream> using namespace std;

int foo(int a, int b); // Deklaracja funkcji

int main()
{
int a;
cin >> a;
int b = foo(a, 5);
cout << b << endl;

return 0;
}

int foo(int a, int b)
{
return a+b;
}

<h2>Funkcje rekurencyjne</h2>
Funkcje rekurencyjne są to funkcje wywołujące same siebie. Może się to wydać na pierwszy rzut oka dziwne. Ten typ funkcji należy omówić na przykładzie. Jedną z takich funkcji rekurencyjnych będzie funkcja obliczających silnię z liczby. Definicja silni wygląda następująco:

0 != 1;
n != (n-1)!*n;

Jeśli rozpiszemy ten wzór, szybko się przekonamy, że silnia to po prostu iloczyn kolejnych liczb mniejszych od tej liczby i tej liczby. Dlatego pierwszą rzeczą jaką trzeba zrobić jest szkielet funkcji:

```cpp
int silnia(int n)
{
}

Na dalszym etapie trzeba mieć opanowane instrukcje warunkowe. Następnym etapem jest sprawdzenie, czy argument n nie jest równy 0. Jeśli jest, można od razu zwrócić wartość (1):

int silnia(int n)
{
   if(n == 0) return 1;
}

Jeśli wartość jeszcze nie została zwrócona (a tym samem funkcja nie przerwała działania), oznacza to, że n jest różne od 0. Wyliczmy wtedy wartość silni ze wcześniej podanego wzoru:

int silnia(int n)
{
   if(n == 0) return 1;
   return silnia(n-1)*n; // rekurencja
}

Aby sprawdzić, czy funkcja rzeczywiście działa, napiszmy prosty program korzystający z niej:

#include <iostream>
using namespace std;

int silnia(int n)
{
   if(n == 0) return 1;
   return silnia(n-1)*n;
}

int main()
{
   int a;
   cin >> a;
   cout << silnia(a) << endl;
   return 0;
}

Przykładowe wyniki to:

0 != 1;
1 != 1;
2 != 2;
3 != 6;
4 != 24;
10 !=  3628800

Funkcje inline

Funkcje inline to mechanizm występujący w C++, podobny do [[C/Makro|Makrodefinicji]] z klasycznego C. Polega on na tym, że funkcja nie jest wywoływana, tylko jej zawartość jest "wklejana" w określone miejsce programu. Jest to korzystne dla bardzo małych funkcji - objętość kodu zwiększa się, ale zaoszczędza się czas związany z wywołaniem funkcji.
inline int dodaj(int a, int b)
{
    return a + b;
}

Przeładowanie nazwy funkcji

Przeładowanie (ang. overloading) nazwy funkcji związane jest z tym, że ma ono więcej niż jedno znaczenie. Ogólnie rzecz biorąc - ta bardzo przydatna cecha języka [[C|C++]] służy do zadeklarowania (i oprogramowania) kilku funkcji o takiej samej nazwie. To oczywiście nie wszystko. Gdyby cała idea przeładowania nazwy funkcji kończyła się na samej jej nazwie, byłoby to po prostu nielogiczne. Reasumując, możemy zmieniać typy przekazywanych argumentów funkcji, jak również ich ilość oraz typ, który zwraca funkcja (ale zmiana jedynie zwracanego typu bez zmiany listy argumentów nie powoduje przeciążenia funkcji!).

Spójrz na przykład:

int dodaj(int liczba1, int liczba2)
{
  return liczba1 + liczba2;
}

double dodaj(double liczba1, double liczba2)
{
  return liczba1 + liczba2;
}

Powyżej zdefiniowałem dwie funkcje dodaj(), które zostały przeładowane, tj. różnią się listą argumentów (w pierwszej użyto typu Int, w drugiej Double). Przykład z użyciem powyższych funkcji:

int main()
{
  cout << dodaj(2, 4) << endl; // wyświetli: 6
  cout << dodaj(2.5, 4.5) << endl; // wyświetli: 7
}

W pierwszym wypadku wyświetlamy wynik dodawania liczb całkowitych, a potem - za pomocą "tej samej" funkcji - wynik dodawania liczb typu zmiennoprzecinkowego. Jest to przecież wygodniejsze, niż pisanie dwóch funkcji o różnych nazwach, gdyż zmieniamy tylko wartości przekazywane do parametrów, nie grzebiąc w nazwach funkcji. Jest to przydatne szczególnie w większych programach. Oczywiście nic nie stoi na przeszkodzie, aby zmienić ilość argumentów jednej z funkcji (w przytoczonym przykładzie przekazujemy dwa argumenty w obu funkcjach).

W C++ czasami lepiej zastosować Szablony funkcji niż przeładowywanie nazw.

7 komentarzy

ja bym jeszcze dodal ze silnia moze byc tylko z liczb nieujemnych (dodatnich i zera)

Funkcje rekurencyjne jak pięknie zrobiona ^^ z tylu zadań z matmy moge pujść na łatwizne...

Jeszcze warto wspomnieć o funkcjach inline

Nie chodzi przecież o podstawową składnię między C a C++ (pod C++ printf() też pójdzie :)), tylko o istotę działania funkcji więc myślę, że można dać sobie z takimi detalami spokój :P

Nie, chyba, ze w jakis magiczny sposob umiesz korzystac z iostream w C.

dotyczy c i c++, nie widać?

Nie mozna bylo do Worda tego wkleic? :/ Poza tym artykul mozna by napisac tak aby dotyczyl i C i C++.