5. Funkcje własne.

5.9. Domyślne wartości parametrów

W tym rozdziale porozmawiamy o bardzo przydatnej możliwości nadania formalnym parametrom domyślnych wartości. Wśród funkcji standardowych są takie, gdzie niektóre parametry mają już swoje wartości domyślne. Proponuję najpierw przeanalizować działanie jednej z nich, a potem stworzymy funkcję własną.

W rozdziale 3.9. Przekształcenie double do string opisano funkcję DoubleToString(), która pozwala liczbę zmiennoprzecinkową przekonwertować na tekst, tj. double na string. Ta funkcja potrzebuje 2 wartości: 1 - to liczba typu double, którą trzeba zamienić na tekst, 2 - to liczba typu int, która określa ilość cyfr po znaku dziesiętnym. Przy tym 2 argument można nie podawać w nagłówku funkcji i wtedy w przekształconym tekście liczba będzie miała 8 cyfr po przecinku. Dlaczego 8? A to właśnie dlatego, że 2 parametr ma domyślną wartość 8. O tym możemy dowiedzieć się z podpowiedzi (rys. 1), która pojawi się po napisaniu w MetaEditor 4 nazwy tej funkcji i otwierającego nawiasu ( lub w opisie funkcji w Pomocy edytora (rys 2) lub na oficjalnej stronie MQL4.

Rys. 1. Okienko podpowiedzi dla funkcji DoubleToString().


Rys. 2. Opis funkcji DoubleToString() w Pomocy.


Wygodne rozwiązanie, nieprawdaż! Niżej pokażę jak można to zrealizować we własnej funkcji na przykładzie obliczenia objętości prostopadłościanu (rys. 3). Oczywiście, MQL4 służy nie do przeprowadzenia obliczeń matematycznych, a do opracowania programów do zarabiania na rynkach finansowych . Do tego dojdziemy. Na razie na prostych przykładach chcę pokazać możliwości MQL4, dopiero po tym jak podstawy zostaną opanowane, komfortowo przejdziemy na wyższy poziom wtajemniczenia.

Rys. 3. Formuła obliczenia objętości prostopadłościanu.


Niżej przedstawiam kod źródłowy skryptu do obliczenia objętości prostopadłościanu z wykorzystaniem funkcji własnej (kod 1).

Kod 1
#property strict

void OnStart()
  {
   int a = 620;     // szerokość, mm
   int b = 440;     // grubość, mm
   int c = 1550;    // wysokość, mm

   double v = CuboidVolume(a, b, c);  // objętość prostopadłościanu

   Print("Objętość prostopadłościanu = ", DoubleToString(v, 5), " L.");
  }

//--- funkcja własna do obliczenia objętości prostopadłościanu
double CuboidVolume(int f_1 = 100// szerokość, mm
                    int f_2 = 200// grubość, mm
                    int f_3 = 300// wysokość, mm
  {
   double V_mm3 = f_1 * f_2 * f_3;  // objętość w mm3
   double V_L   = V_mm3 / 1000000;  // objętość w L
   return(V_L);
  }

Długość ścianek będziemy podawać w milimetrach. Ich wartości będą liczbami całkowitymi, dlatego w kodzie dla zmiennych a, b i c zastosujemy typ int . Ponieważ objętość będziemy obliczać w litrach, otrzymany wynik może być liczbą zmiennoprzecinkową, dlatego zmienna v oraz funkcja CuboidVolume() będą mieć typ double . W opisie funkcji własnej widzimy, że wszystkim trzem parametrom przypisano jakąś domyślną wartość. Przypisanie wartości wygląda tak: najpierw typ parametru, potem jego nazwa, znak równości = , a na końcu wartość. Np. dla pierwszego parametru zapis wygląda tak: int f_1 = 100.

Jak to działa i jakie wartości ta funkcja przyjmie do obliczenia wyniku? Po uruchomieniu tego skryptu w MetaTrader 4 zobaczymy, że wynik będzie równy 422.84000 L, co odpowiada wymiarom 620 x 440 x 1550 mm, tj. wartościom a, b i c.


Teraz przekażmy do funkcji tylko 2 wartości: a i b (kod 2).

Kod 2
double v = CuboidVolume(a, b);  // objętość prostopadłościanu

Po uruchomieniu takiego skryptu wynik będzie równy 81.84000 L. Myślę, że domyślasz się dlaczego właśnie taki. Ta objętość odpowiada wymiarom prostopadłościanu 620 x 440 x 300 mm, tj. wartościom a, b i domyślnej wartości parametru f_3. W tym przypadku nie przekazaliśmy funkcji wysokości tej bryły geometrycznej, ale funkcja wiedziała, że należy użyć 300.

Jeśli przekażemy do funkcji tylko zmienną a (kod 3), to wynik będzie równy 37.20000 L, co odpowiada wymiarom 620 x 200 x 300 mm. W tym przypadku okaże się, że funkcja użyje wartości a oraz domyślnych wartości parametrów f_2 i f_3.

Kod 3
double v = CuboidVolume(a);  // objętość prostopadłościanu

Jeśli nic nie zostanie przekazane do funkcji (kod 4), to wynik będzie równy 6.00000 L, co odpowiada wymiarom 100 x 200 x 300 mm, tj. domyślnym wartościom f_1, f_2 i f_3.

Kod 4
double v = CuboidVolume();  // objętość prostopadłościanu

Na początku tego rozdziału zaznaczyłem, że po napisaniu nazwy funkcji i otwierającego nawiasu ( pojawi się podpowiedź z charakterystykami parametrów. Taka sama podpowiedź pojawi się i dla każdej funkcji własnej w przypadku jeśli została ona już opisana (rys. 4). Jest to niesamowicie przydatna właściwość MetaEditor 4, ponieważ jeśli dołączymy do programu bibliotekę funkcji, która zawiera np. kilkaset funkcji, to było by bardzo uciążliwe przypominanie sobie - ile to parametrów zawiera każda z nich. A tak w tej małej podpowiedzi widzimy, że ta funkcja ma 3 parametry oraz ich wartości domyślne jeśli mają. Bez takiego małego pomocnika życie programisty było by trudniejsze.

Rys. 4. Podpowiedź dla funkcji własnej.


Może pojawić się pytanie - kiedy parametrom przypisywać domyślne wartości, a kiedy nie. Właściwie sprawa jest bardzo indywidualna i zależy od gustu programisty. Jeśli nie przypiszemy parametrom żadnych wartości domyślnych, to przy wywołaniu funkcji trzeba będzie jej przekazać wszystkie dane. Jeśli przypiszemy parametrom wartości, to pewnych danych możemy nie przekazywać.


Jeśli jakiemuś parametrowi przypisano wartość domyślną, to wszystkie następne parametry też muszą mieć wartości domyślne.

Niżej kilka kolejnych przykładów (kod 5).

Kod 5
//--- Przykład 1
double CuboidVolume(int f_1,           // ok
                    int f_2 = 200,     // ok
                    int f_3 = 300)     // ok
{
//...
}

//--- Przykład 2
double CuboidVolume(int f_1,           // ok
                    int f_2 = 200,     // ok
                    int f_3)           /* błąd, należy przypisać wartość domyślną
                                          ponieważ drugi parametr ma */

{
//...
}

//--- Przykład 3
double CuboidVolume(int f_1 = 100,     // ok
                    int f_2,           /* błąd, należy przypisać wartość domyślną
                                          ponieważ pierwszy parametr ma */

                    int f_3 = 300)
{
//...
}                    

//--- Przykład 4
int SomeFunction(double v,             // ok
                 uint   matrix = 555,  // ok
                 bool   sw = true;     // ok
                 double f_res = -5.73, // ok
                 string st = "Rabbit") // ok
{
//...
}

//--- Przykład 5
int SomeFunction(double v,             // ok
                 uint   matrix = 555,  // ok
                 bool   sw = true;     // ok
                 double f_res,         // błąd
                 string st)            // błąd
{
//...
}