Funkcje

Stronę tą wyświetlono już: 280 razy

Ważnym elementem programowania są funkcje, których definicja podstawowa jest następująca:

Listing 1
  1. typ_zwracany nazwa_funkcji(typ_argumentu_funkcji_1 arument1, typ_argumentu_funkcji_2 argument2, ... ) // to jest nagłówek funkcji
  2. {
  3. // blok instrukcji
  4. return wartosc; // zwracanie jakiejś wartości przez funkcję
  5. }

A oto praktyczny przykład definicji własnej funkcji obliczającej silnię:

Listing 2
  1. int silnia(int s){ // funkcja przyjmuje jako argument zmienną typu int
  2. int silnia = 1;
  3. for(int i = 1; i <= s; i++){
  4. silnia *= i;
  5. }
  6. return silnia; // funkcja zwraca wartość typu int
  7. }

Powyższy kod można wykorzystać do napisania prostego programiku, który będzie obliczał wartość silni:

Listing 3
  1. #include <iostream>
  2. using namespace std;
  3. int silnia(int s){
  4. int sil = 1;
  5. for(int i = 1; i <= s; i++){
  6. sil *= i;
  7. }
  8. return sil;
  9. }
  10. int main(){
  11. int s = 0;
  12. cout<<"Podaj wartość obliczanej silni:";
  13. cin>>s;
  14. cout<<s<<"!="<<silnia(s); // wywołanie funkcji w kodzie programu
  15. cout<<"Wcisnij dowolny przycisk, aby zamknac program...";
  16. cin.get();
  17. return 0;
  18. }

Funkcja silnia z powyższego kodu zwraca dane poprzez wartość, możliwe jest jednak zwrócenie liczby poprzez wykorzystanie referencji w sposób następujący:

Listing 4
  1. #include <iostream>
  2. using namespace std;
  3. void silnia(int s, int &sil){
  4. sil = 1;
  5. for(int i = 1; i <= s; i++){
  6. sil *= i;
  7. }
  8. return sil;
  9. }
  10. int main(){
  11. int s = 0;
  12. cout<<"Podaj wartość obliczanej silni:";
  13. cin>>s;
  14. int sil = 0;
  15. silnia(s, sil); // wywołanie funkcji w kodzie programu
  16. cout<<s<<"!="<<sil;
  17. cout<<"Wcisnij dowolny przycisk, aby zamknac program...";
  18. cin.get();
  19. return 0;
  20. }

Ważną zmianą w funkcji silnia jest również podanie jako typu zwracanego słowa kluczowego void, które informuje kompilator, że nie będzie on zwracał żadnej zmiennej. Operator dereferencji & sprawia, że nie będzie tworzona kopia tej zmiennej w pamięci komputera. Dzięki temu program może modyfikować wartość zapisaną w zmiennej utworzonej zewnętrznie. Gdyby zastąpić nagłówek funkcji z powyższego kodu nagłówkiem takiej oto postaci:

Listing 5
  1. void silnia(int s, int sil)

Wtedy funkcja utworzyłaby kopię zmiennej sil i w związku z tym wynik obliczeń nie byłby dostępny poza ciałem funkcji.

Ciekawą konstrukcją funkcji są funkcje rekurencyjne, które wywołują same siebie wewnątrz kodu aż do momentu spełnienia pewnego warunku koniecznego. Oto przykład funkcji rekurencyjnych obliczających silnię:

Listing 6
  1. #include <iostream>
  2. #include <conio.h>
  3. using namespace std;
  4. int silnia(int s){
  5. if(s < 0)
  6. return 0;
  7. else if(s < 2)
  8. return 1;
  9. return silnia(s-1) * s; // rekurencyjne wywołanie funkcji
  10. }
  11. int main(){
  12. int s = 0;
  13. cout<<"Podaj wartość obliczanej silni:";
  14. cin>>s;
  15. int sil = 1;
  16. cout<<s<<"! ="<<silnia(s); // wywołanie funkcji silnia
  17. cout<<"Wcisnij dowolny przycisk, aby zamknac program...";
  18. cin.get();
  19. return 0;
  20. }

Tego typu funkcje powinno się stosować jedynie wtedy, gdy nie ma możliwości wykorzystania pętli for, while lub do while a to dlatego, że takie wielokrotne wywołania funkcji przy dużej liczbie operacji są bardzo kosztowne czasowo oraz pamięciożerne.

Jeszcze jedna uwaga, nagłówek funkcji może być oddzielony od ciała funkcji, np. w sposób zapisany poniżej:

Listing 7
  1. #include <iostream>
  2. using namespace std;
  3. void silnia(int s, int &sil); // oddzielnie umieszczony nagłówek funkcji
  4. int main(){
  5. int s = 0;
  6. cout<<"Podaj wartość obliczanej silni:";
  7. cin>>s;
  8. int sil = 0;
  9. silnia(s, sil); // wywołanie funkcji w kodzie programu
  10. cout<<s<<"!="<<sil;
  11. cout<<"Wcisnij dowolny przycisk, aby zamknac program...";
  12. getch();
  13. return 0;
  14. }
  15. void silnia(int s, int &sil){ // nagłówek funkcji z jej ciałem
  16. sil = 1;
  17. for(int i = 1; i <= s; i++){
  18. sil *= i;
  19. }
  20. return sil;
  21. }

Dzięki takiej konstrukcji funkcja silnia jest widoczna wewnątrz ciała funkcji main.

Dodatkowym ciekawym aspektem tworzenia funkcji jest możliwość ich przeładowanie, czyli mogę napisać kilka funkcji o tej samej nazwie, ale o różniej liczbie argumentów lub różnych typach argumentów. Przykład:

Listing 8
  1. int mnozenie(int a, int b){
  2. return a * b;
  3. }
  4. double mnozenie(double a, double b){
  5. return a * b;
  6. }
  7. double a = 100.5;
  8. int b = 2;
  9. int abInt = mnozenie((int)a /*konieczne jest rzutowanie typów, aby kompilator mógł rozpoznać, z której wersji funkcji ma skorzystać*/,b);
  10. double abDouble = mnozenie(a,(double)b /*konieczne jest rzutowanie typów, aby kompilator mógł rozpoznać, z której wersji funkcji ma skorzystać*/);

Komentarze