Przeciążenie funkcji (overloading) to mechanizm deklarowania kilku funkcji o tej samej nazwie, ale o różnych sygnaturach (liczbie lub typie parametrów).
Wartości domyślne dla parametrów można określać w deklaracji funkcji. Subtelność: wartości domyślne są brane pod uwagę tylko w momencie kompilacji wywołania i podstawiane przez kompilator, na podstawie widocznej sygnatury.
W klasach często spotyka się sytuację:
class Printer { void print(int n, char c = '*') { /* ... */ } void print(const std::string& s) { /* ... */ } }; Printer p; p.print(5); // wywoła print(int n, char c = '*'), c = '*' p.print("Hi"); // wywoła print(const std::string&)
Subtelności:
void foo(int x, int y = 10); void foo(int x); foo(1); // Błąd: niejasne, którą funkcję wywołać
Które z miejsc jest jedynym, gdzie dozwolone jest określenie wartości domyślnej dla funkcji członkowskiej klasy?
Odpowiedź: Wartość domyślna dla metody klasy może być określona w deklaracji metody wewnątrz klasy (lub w pierwszej deklaracji na zewnątrz klasy), ale nie jest dozwolone podawanie jej zarówno w klasie, jak i w implementacji. W przeciwnym razie wystąpi błąd duplikacji definicji.
class X { void func(int x = 5); // Można tutaj }; void X::func(int x) { /* ... */ } // Ale nie tutaj!
Historia 1
W oprogramowaniu bankowym wystąpił błąd na etapie kompilacji: część przeciążonych funkcji z różnymi wartościami domyślnymi utrudniała jednoznaczny wybór potrzebnej, wywołania były niejednoznaczne na etapie kompilacji — rezultat: niemożność skompilowania wersji do czasu wprowadzenia ręcznych poprawek.
Historia 2
W zespole panował styl, w którym wszystkie wartości domyślne były przenoszone do implementacji, a nie do nagłówka klasy, co jednak dla niektórych metod klas powodowało niespójność między interfejsem a implementacją — różne jednostki TU widziały różne parametry funkcji, co prowadziło do dziwnych błędów kompilacji i błędów wykonania.
Historia 3
Przy rozszerzaniu publicznej biblioteki omyłkowo dodano przeciążenie funkcji z tymi samymi parametrami, ale różnymi wartościami domyślnymi. Kompilator zaczął generować niejednoznaczność podczas wywołań API, a użytkownicy napotkali przestarzałe wywołania i uszkodzone zgodności binarne.