Funkcje

  W programowaniu zorientowanym obiektowo (a takim na pewno jest programowanie w C++) uwaga programistów koncentruje się na obiektach. Jednak trudno jest sobie wyobrazić program, który byłby w jakimkolwiek stopniu użyteczny i nie zawierał by żadnych funkcji, dlatego funkcje są głównym komponentem każdego programu.
  Funkcje można podzielić na funkcje globalne występujące poza obiektami, oraz funkcje składowe (metody składowe) występujące wewnątrz obiektów.
  Funkcja jest podprogramem, operującym na danych i zwracającym wartość. Funkcje globalne nie stanowią części jakiegoś obiektu i są dostępne z dowolnego miejsca programu, natomiast funkcje składowe są częścią obiektu i wykonują określone zadania wewnątrz tego właśnie obiektu. W poniższym przykładzie przedstawię dwie funkcje, które nazywają się tak samo i robią to samo, lecz pierwsza jest funkcją globalną, druga natomiast funkcją składową.

// Plik źródłowy np. Unit1.cpp
// Przykład funkcji globalnej PodajWynik
//--------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
            : TForm(Owner)
{
}
//--------------------------------
int PodajWynik(int a, int b)
{
    int c = a + b;
    return c;
}
//--------------------------------


// Plik źródłowy np. Unit1.cpp
// Przykład funkcji składowej PodajWynik
//--------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
            : TForm(Owner)
{
}
//--------------------------------
int TForm1::PodajWynik(int a, int b)
{
    int c = a + b;
    return c;
}
//--------------------------------


  Obydwie funkcje działają tak samo, robią to samo, lecz funkcja składowa jest częścią obiektu Form1. Każda funkcja posiada nazwę (w przykładzie PodajWynik), gdy program napotka nazwę przechodzi do wykonywania kodu zawartego wewnątrz funkcji. Po zakończeniu działania funkcji program wykona instrukcje następujące po wywołaniu funkcji.
  Gdy funkcja zostanie wywołana, wykona instrukcje zawarte wewnątrz po czym może zwrócić rezultat swojej pracy. Ta wartość jest nazywana wartością zwracaną, zaś jej typ musi być zadeklarowany. W podanym przykładzie został zadeklarowany typ całkowity (int), więc funkcja musi również zwrócić wartość całkowitą (typ int). Można również przekazywać wartości do funkcji (w przykładzie: int a, int b). Te wartości pełnią rolę zmiennych, którymi można manipulować wewnątrz funkcji (w przykładzie: a + b). Przekazywane wartości są nazywane parametrami.
  Przeanalizujmy funkcję 'PrzykładowyWynik' z pierwszego przykładu:

int PodajWynik(int a, int b)


Najpierw została zadeklarowana funkcja o nazwie PodajWynik. Deklaracja wskazuje, że funkcja zwraca wartość całkowitą (typ int), oraz zawiera dwa parametry (int a, int b), które są wartościami całkowitymi (jako parametry można przekazywać do funkcji dowolne poprawne wyrażenia języka C++).

{
   int c = a + b;


Następnie jest umieszczany nawias klamrowy otwierający ciało funkcji w którym zostaną umieszczone instrukcje. Potem zostaje umieszczona instrukcja (int c = a + b), jak widać została utworzona nowa zmienna całkowita 'c' a następnie jako wartość została jej przypisana suma wartości parametrów 'a' i 'b', czyli funkcja wykonała dodawanie.

  return c;
}


Następnie funkcja zwraca jako wartość wynik dodawania, czyli wartość zmiennej 'c', po tym kończy się działanie funkcji i zostaje umieszczony nawias klamrowy zamykający ciało funkcji.
Jak więc widać zadaniem przykładowej funkcji było dodanie do siebie dwóch liczb całkowitych i podanie wyniku, ale funkcja nic nie zrobi dopuki nie zostanie wywołana. Najprostszym sposobem wywołania funkcji będzie wykorzystanie zdarzenia 'OnClick' przycisku 'Button1', a wynik działania funkcji zostanie wyświetlony na etykiecie 'Label1'.
Przykład:

// Plik źródłowy np. Unit1.cpp
//--------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
            : TForm(Owner)
{
}
//--------------------------------
int PodajWynik(int a, int b)
{
    int c = a + b;
    return c;
}
//--------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
   int x = PodajWynik(2, 5); // tutej następuje wywołanie funkcji.
   Label1->Caption = IntToStr(x);
}
//--------------------------------


Jako wynik działania funkcji zostanie wyświetlona wartość 7 (nie muszę chyba tłumaczyć dlaczego właśnie tyle). Ponieważ przykładowa funkcja zwraca wartość całkowitą, trzeba utworzyć zmienną tego samego typu (w przykładzie int x), żeby uzyskać wynik. Można by np. wywołać funkcję w ten sposób.
Przykład:

// Plik źródłowy np. Unit1.cpp
//--------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
            : TForm(Owner)
{
}
//--------------------------------
int PodajWynik(int a, int b)
{
    int c = a + b;
    return c;
}
//--------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
   PodajWynik(2, 5); // tutej następuje wywołanie funkcji.
}
//--------------------------------


Niestety pomimo tego, że funkcja została wywołana i wykonała swoją pracę, to efektów jej pracy nie będzie nigdzie widać ponieważ zwracana wartość nie została nigdzie przypisana, ale można by przypisać zwracaną wartość bezpośrednio etykiecie 'Label1', np.:

Label1->Caption = IntToStr(PodajWynik(2, 5));


W prezentowanych przykładach do funkcji zostały wprowadzone dwie wartośći 2 i 5, te wartości nazywane są argumentami funkcji. Należy pamiętać, że typy argumentów muszą odpowiadać zadeklarowanym typom parametrów.
  Na samym początku wspomniałem, że funkcje zwracają wartości, ale to nie znaczy że musi tak być. Można utworzyć funkcję void i tak funkcja niczego nie zwraca. Gdybym chciał uzyskać wynik dodawania za pomocą funkcji typu 'void', posłużyłbym się funkcją składową:

// Plik źródłowy np. Unit1.cpp
// Przykład funkcji składowej PodajWynik (typ void)
//--------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
            : TForm(Owner)
{
}
//--------------------------------
void TForm1::PodajWynik(int a, int b)
{
    int c = a + b;
    Label1->Caption = IntToStr(c);
}
//--------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
   PodajWynik(2, 5);
}


Jak widać wynik działania funkcji zostaje wyświetlony na etykiecie 'Label1' jeszcze wewnątrz funkcji. Dzieje się tak dlatego, że funkcja nic nie zwraca, a skoro tak to wyniku jej pracy nie można przypisać żadnej zmiennej. Funkcje, które nic nie zwracają w chwili wywołania nie są przypisaywane żadnym zmiennym. Mógłbym się również posłużyć funkcją globalną, ale tu już się wszystko trochę komplikuje. Dlaczego? Ponieważ funkcja składowa jest częścią obiektu 'Form1' i obiekt 'Label1' również obiektem należącym do obiektu 'Form1' dlatego "widzą" się nawzajem. Natomiast funkcja globalna, nic nie "wie" o obiekcie 'Label1', dlatego należy ją "powiadomić" gdzie znajduje się obiekt 'Label1'.
Przykład:

// Plik źródłowy np. Unit1.cpp
// Przykład funkcji globalnej PodajWynik (typ void)
//--------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
            : TForm(Owner)
{
}
//--------------------------------
void PodajWynik(int a, int b)
{
    int c = a + b;
    Form1->Label1->Caption = IntToStr(c);
}
//--------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
   PodajWynik(2, 5);
}


To jest jednak kiepski pomysł, znacznie lepiej jest podać jako parametr funkcji deklarację klasy 'TLabel', wtedy funkcja będzie mogła wyświetlić wynik na etykiecie Label1, jednak jak to będzie widać w przykładzie jako argument funkcji należy podać nazwę etykiety na której ma zostać wyświetlony wynik.
Przykład:

// Plik źródłowy np. Unit1.cpp
// Przykład funkcji globalnej PodajWynik (typ void)
//--------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
            : TForm(Owner)
{
}
//--------------------------------
void PodajWynik(int a, int b, TLabel *lb)
{
    int c = a + b;
    lb->Caption = IntToStr(c);
}
//--------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
   PodajWynik(2, 5, Label1);
}



  Jeżeli ktoś z Was przed dojściem do tego momentu próbował tworzyć zmienne składowe, mając o tym raczej niewielkie pojęcie, to musiał się mocno rozczarować, dlatego że stnieje coś takiego jak: deklaracja funkcji. W przypdaku funkcji globalnych, definicja funkcji jest jednocześnie jej deklaracją. Funkcje składowe trzeba jednak najpierw zadeklarować, a dopiero potem definiować. Deklaracja informuje kompilator o nazwie funkcji, typie zwracanej przez nią wartości, oraz o jej parametrach. Deklaracja funkcji jest nazywana prototypem.
Funkcje deklaruje się w pliku nagłówkowym (można to robić również w pliku źródłowym, lecz to niepotrzebnie komplikuje kod), w sekcji private dla funkcji dostępnych tylko w obrębie danego formularza, lub w sekcji public dla funkcji dostępnych w całym programie.
Przykład:

// Plik nagłówkowy np. Unit1.h.
// Deklaracja funkcji PodajWynik.
//--------------------------------
private:
   int PodajWynik(int a, int b) // deklaracja funkcji.

public: //--------------------------------


...i to w zasadzie wszystko na temat deklarowania funkcji.