Podręcznik
Wersja podręcznika: 1.0
Data publikacji: 01.01.2022 r.
8. Funkcje
8.4. Przeciążanie nazw funkcji
Wspomniałem, że w C++ nazwa funkcji nie jest jej unikalnym identyfikatorem – że kompilator automatycznie dodaje do nazw przyrostek zawierający typy wszystkich argumentów w odpowiedniej kolejności. Ten mechanizm jest wykorzystany do przeciążania nazw funkcji, czyli pozwolenia na to, by w programie mogło występować kilka funkcji o tej samej nazwie.
Przy czym kompilator musi mieć możliwość odgadnięcia, o którą funkcję chodzi autorowi, więc - muszą się różnić typami parametrów na liście (nie samymi nazwami - bo one nie są wykorzystywane przy wywołaniu), i nie można wykorzystać do przeciążania typu wartości zwracanej (wartość zwracają można "porzucić" - i nie byłoby przesłanki do wyboru odpowiedniej wersji funkcji.
Przykłady prawidłowego i nieprawidłowego przeciążania:
// prawidłowo
int funkcja(int _a);
int funkcja(int _a, int _y);
int funkcja(double _a);
int funkcja(string _a);
// nieprawidłowo
int funkcja(int _a);
double funkcja(int _a);
Kompilator sam dopasuje odpowiednią funkcję w momencie wywołania, kierując się następującymi zasadami:
- Ścisła zgodność (bez konwersji lub konwersje trywialne – tablica na wskaźnik, stała na zmienną, nazwa funkcji na funkcję)
- Zgodność z zastosowaniem promowania typów całościowych (bool na int, char na int i odpowiedniki bez znaku)
- Zgodność z zachowaniem standardowych konwersji (całkowite na zmiennoprzecinkowe i vice versa, rzutowania klas, rzutowanie na void*)
- Zgodność z zachowaniem definiowanych konwersji (dla klas)
- Zgodność z wielokropkiem w deklaracji funkcji.
void drukuj(int _x);
void drukuj(const char* _x);
void drukuj(double _x);
void drukuj(long _x);
void drukuj(char _x);
void h(char _c, int i, short s, float f)
{
// ścisla zdodnosc
drukuj(c);
drukuj(i);
// trywialna konwersja
drukuj('c');
drukuj(49);
drukuj(0);
drukuj("A");
// promocja w zakresie typów całościowych
drukuj(s); // wywoła drukuj(int)
// promocja w zakresie konw. standardowych
drukuj(f); // wywoła drukuj(double)
}
Jeśli znaleziono więcej niż jedną pasującą funkcję na tym samym poziomie – będzie błąd kompilacji. Jak się taki błąd pojawi – co robić? Najlepiej ręcznie rozwiać wątpliwości kompilatora:
void f1(char);
void f1(long);
void f2(char*);
void f2(int*);
...
int i;
f1(i); // niejednoznaczne
f1(long(i)); // ok
f2(0); // niejednoznaczne
f2(static_cast<int*>(0)); // ok
double pow(int x, int y);
double pow(double x, double y);
...
pow(2.0, 2); // niejednoznaczne
pow(2.0, (double)2); // i już ok.
</int*>