Funkcje przeciążone (Function Overloading)
1. Co to jest przeciążanie funkcji?
Przeciążanie funkcji (function overloading) to mechanizm w języku C++, który pozwala tworzyć wiele funkcji o tej samej nazwie, ale:
- z różnymi parametrami,
- lub różnymi typami parametrów,
- lub różną liczbą parametrów.
Kompilator wybiera odpowiednią funkcję na podstawie listy argumentów w momencie wywołania.
➡ Dzięki temu jeden identyfikator funkcji może obsługiwać wiele wariantów tego samego działania.
2. Po co stosuje się przeciążanie funkcji?
Poprawa czytelności
Zamiast:
możemy napisać:
Ujednolicenie interfejsu
Pozwala tworzyć spójne API — ta sama nazwa, różne konteksty.
Lepsza organizacja kodu
Funkcje robią logicznie to samo, więc mają wspólną nazwę.
3. Zasady przeciążania funkcji
Funkcje muszą różnić się sygnaturą, czyli:
- liczbą parametrów,
- typem parametrów,
- kolejnością parametrów.
NIE WOLNO przeciążać funkcji tylko na podstawie typu zwracanego!
To nie działa:
4. Przykłady przeciążania
4.1. Różne typy parametrów
4.2. Różna liczba parametrów
4.3. Różna kolejność typów parametrów
4.4. Przeciążanie z parametrami domyślnymi (uwaga!)
Wywołanie:
→ Niejednoznaczność, bo kompilator nie wie, którą wersję wybrać.
5. Jak kompilator wybiera odpowiednią funkcję? (Overload Resolution)
Procedura wyboru składa się z etapów:
Szukanie kandydatów
- Wszystkie funkcje o dopasowanej nazwie.
Filtrowanie wykonalnych funkcji
- Lista argumentów musi pasować po konwersji.
Wybór najlepszego dopasowania
Preferowane są:
- brak konwersji > konwersja standardowa > konwersja złożona,
- unikanie rzutowania (castów),
- unikanie konwersji wielokrotnych.
6. Przykłady z konwersją — uwaga na niejednoznaczność
Przykład niejednoznaczny:
Znak 'a' może być:
- konwertowany do int,
- albo do double.
➡ Kompilator wybierze int, bo to lepsze dopasowanie (konwersja integralna).
Bardziej problematyczny przykład:
10 jest typu int → oba są możliwe.
Kompilator wybiera wersję z long, ponieważ konwersja int -> long jest lepsza niż int -> double.
7. Częste błędy przy przeciążaniu
1. Przeciążanie tylko przez typ zwracany
Nie działa — typ zwracany nie jest częścią sygnatury.
2. Konflikty z parametrami domyślnymi
3. Niejednoznaczność wywołań
4. Przeciążanie bez sensownej logiki
Trzeba wiedzieć, kiedy to ma sens — nadużywanie przeciążania utrudnia czytelność.
8. Przeciążanie funkcji a funkcje szablonowe
Funkcje szablonowe również mogą być przeciążane:
Jeśli wywołamy:
→ kompilator wybiera wersję konkretną (dla int), bo jest lepszym dopasowaniem niż szablon.
9. Przykład praktyczny — przeciążenie operatora
Przeciążanie funkcji dotyczy również operatorów.
Operator + jest przeciążoną funkcją o specjalnej nazwie.
10. Kiedy warto stosować przeciążanie?
- Gdy funkcje wykonują to samo, ale przyjmują inne dane.
- Gdy chcemy uprościć API.
- Gdy naturalne jest użycie jednej nazwy (np.
print,add,compare). - Gdy tworzymy biblioteki i chcemy wygodnego interfejsu dla użytkownika.
11. Podsumowanie
Funkcje przeciążone to jeden z mechanizmów polimorfizmu w C++. Umożliwiają:
- większą czytelność,
- elastyczność,
- spójne nazwy funkcji,
- wygodniejsze korzystanie z kodu.
Trzeba jednak uważać na:
- niejednoznaczność,
- konwersje typów,
- parametry domyślne,
- przeciążanie niepoparte logiką.