11.4 Argumenty domyślne

W C/C++ istnieje możliwość definiowania funkcji o domyślnych wartościach argumentów. Znaczy to, że wywołując taką funkcję nie trzeba podawać wszystkich argumentów: dla tych argumentów, których wartość nie została podana, przyjęta zostanie wartość domyślna.

Aby skorzystać z tej możliwości, deklarujemy (lub od razu definiujemy) funkcję, określając wartości domyślne dla parametrów funkcji bezpośrednio w nagłówku. Muszą to być końcowe parametry: jeśli któryś z parametrów ma wartość domyślną, to wszystkie parametry występujące na liście parametrów po nim też muszą mieć przypisane wartości domyślne. Wartości domyślne można przypisać tylko raz: jeśli zrobimy to w deklaracji, to nie powtarzamy tego w definicji ani innych deklaracjach. Na przykład, można zadeklarować funkcję fun o jednym argumencie obowiązkowym i dwoma z wartościami domyślnymi:

       void fun(int i, int b = 0, double x = 3.14);
Ponieważ w deklaracji nazwy parametrów są i tak pomijane, tę samą deklarację możemy zapisać tak:
       void fun(int, int = 0, double = 3.14);
W dalszej części programu musimy oczywiście podać definicję tej funkcji; tam już przypisania wartości domyślnych nie umieszczamy:
       void fun(int i, int b, double x) {
           // ...
       }
Teraz możemy wywoływać funkcję fun na różne sposoby, np.:
       fun(3, 4, 7.5);
       fun(3, 4);
       fun(3);

W linii pierwszej podaliśmy wszystkie argumenty, więc żadna wartość domyślna nie zostanie użyta. W drugiej linii podaliśmy dwa argumenty: wartość pierwszego zostanie użyta do zainicjowania parametru pierwszego (i), wartość drugiego — parametru drugiego (b); tu wartość domyślna 0 zostanie zignorowana). Trzeciego argumentu nie podaliśmy, więc parametr trzeci (x) zostanie zainicjowany wartością domyślną (3,14). W trzeciej linii podaliśmy tylko jeden argument; dla dwóch pozostałych przyjęte zostaną wartości domyślne. Tak więc powyższe trzy wywołania równoważne są wywołaniom:
       fun(3, 4, 7.5);
       fun(3, 4, 3.14);
       fun(3, 0, 3.14);

Zauważmy, że nie ma sposobu, aby podać wartość trzeciego argumentu nie podając drugiego, gdyż kolejne argumenty przypisywane są zawsze do kolejnych parametrów i, jeśli lista parametrów nie została wyczerpana, dla pozostałych użyte będą wartości domyślne. Nie da się również wywołać funkcji nie podając argumentów odpowiadających parametrom, dla których wartości domyślne nie zostały określone. W naszym przypadku na przykład, nie byłoby możliwe wywołanie funkcji fun bez żadnych argumentów, ponieważ argument odpowiadający pierwszemu parametrowi jest obowiązkowy.

Argument domyślny może być wyrażeniem, którego wartość zostanie obliczona przy wywoływaniu funkcji (takim wyrażeniem może być na przykład wyrażenie zawierające nazwę zmiennej globalnej lub wywołanie funkcji). Jeśli tak jest, to wartość tego wyrażenia znajdowana jest za każdym razem gdy funkcja jest wywoływana, ale w zakresie tej deklaracji, gdzie wartości domyślne zostały zdefiniowane. Na przykład w poniższym programie w zakresie, do którego należy deklaracja funkcji kolo (), widoczną zmienną PI jest globalna zmienna o tej nazwie.


P65: wardom.cpp     Wartości domyślne funkcji

      1.  #include <iostream>
      2.  using namespace std;
      3.  
      4.  double PI = 3;
      5.  
      6.  double kolo(double, double = PI);          
      7.  
      8.  int main() {
      9.      double r = 1;
     10.  
     11.      cout << "1. PI = " << PI << " Pow = "
     12.                         << kolo(r) << endl; 
     13.      double PI = 3.14;
     14.      cout << "2. PI = " << PI << " Pow = "
     15.                         << kolo(r) << endl; 
     16.      ::PI = 3.14;                           
     17.      cout << "3. PI = " << PI << " Pow = "
     18.                         << kolo(r) << endl;
     19.  }
     20.  
     21.  double kolo(double r, double pi) {
     22.      return pi*r*r;
     23.  }

W pierwszym wywołaniu funkcji (linia ) użyta zostanie wartość 3. W drugim wywołaniu (), lokalna zmienna PI przysłania w funkcji main zmienną globalną o tej samej nazwie, ale wartość domyślna drugiego argumentu funkcji fun zostanie obliczona w zakresie globalnym, a zatem w dalszym ciągu będzie to wartość 3! Natomiast jeśli zmienimy wartość zmiennej globalnej (), to ta nowa wartość zostanie użyta przy inicjowaniu parametrów domyślnych dla trzeciego wywołania, o czym przekonuje nas wydruk:

    1. PI = 3 Pow = 3
    2. PI = 3.14 Pow = 3
    3. PI = 3.14 Pow = 3.14

Parametry funkcji zadeklarowane jako obowiązkowe można przedeklarować tak, aby miały wartości domyślne. Należy tylko pamiętać, aby każdy parametr deklarowany jako domyślny był w ten sposób deklarowany tylko raz. Zmienić status parametrów z obowiązkowego na parametr z wartością domyślną można tylko dla ostatnich obowiązkowych parametrów na liście.

Załóżmy, że w pliku nagłówkowym wardom1h.h zadeklarowana jest funkcja z czterema parametrami, w tym tylko ostatni ma wartość domyślną (równą 255):

       void kolor(int r, int g, int b, int alpha = 255);
Rozpatrzmy teraz program


P66: wardom1.cpp     Przedeklarowywanie wartości domyślnych

      1.  #include <iostream>
      2.  using namespace std;
      3.  
      4.  #include "wardom1h.h"
      5.  
      6.  void kolor(int, int , int = 0, int);        
      7.  
      8.  int main() {
      9.      kolor(100,150,250,199);
     10.      kolor(100,150,250);
     11.      kolor(100,150);
     12.  }
     13.  
     14.  void kolor(int red, int green, int blue, int alpha) {
     15.      cout << "Alpha = " << alpha << " (R,G,B) = (" << red
     16.           << ","  << green  <<  "," << blue << ")" << endl;
     17.  }

Na początku włączamy plik nagłówkowy wardom1h.h. W zasięgu znajdzie się zatem deklaracja funkcji kolor z jednym (czwartym) argumentem domyślnym. Ostatnim na liście parametrem obowiązkowym jest parametr trzeci. Możemy więc zmienić jego status — robimy to przedeklarowując funkcję w linii . Zauważmy, że nie piszemy wartości domyślnej dla czwartego parametru: ten parametr już jest domyślny (ma wartość domyślną 255) i drugi raz przypisywać mu wartości domyślnej, nawet tej samej, nie wolno. Redeklaracja zmienia zatem status trzeciego parametru na domyślny i możliwe jest teraz wywołanie funkcji z czterema, trzema i dwoma argumentami; otrzymujemy

    Alpha = 199 (R,G,B) = (100,150,250)
    Alpha = 255 (R,G,B) = (100,150,250)
    Alpha = 255 (R,G,B) = (100,150,0)
„Sztuczek” z przedeklarowywaniem funkcji i zmienianiem statusu ich parametrów lepiej jednak unikać, gdyż bardzo skutecznie zaciemniają kod.

Argumenty domyślne stosuje się często w konstruktorach klas.

T.R. Werner, 25 lutego 2017; 22:31