C++/Przeciążanie funkcji
W języku C++ możliwe jest utworzenie kilku różnych funkcji, które posiadają tę samą nazwę. Takie funkcje muszą różnić się od siebie liczbą lub typem argumentów. Dzięki temu kompilator będzie wiedział dokładnie, którą funkcję należy wywołać. Takie funkcje nazywamy przeciążonymi (czasem również – przeładowanymi).
Przeciążanie (przeładowanie) funkcji to zabieg polegający na utworzeniu kilku funkcji o tej samej nazwie, nazywanych funkcjami przeciążonymi. Takie funkcje muszą różnić się liczbą lub typem argumentów przekazywanych do tej funkcji, dodatkowo mogą różnić się zwracanym typem. |
Oto przykłady funkcji przeciążonych:
void funkcja (int);
void funkcja (std::string);
void funkcja (std::string, std::string);
// int funkcja (int); //niedozwolone, funkcje różnią się tylko zwracanym typem
int funkcja (bool); //dozwolone
Czasami kompilator może zabronić przeładowania, gdy uzna, że typy argumentów są zbyt podobne. Może tak się dziać na przykład w przypadku, gdy:
- użyjemy typu const T i T,
- użyjemy argumentów domyślnych.
void funkcja (int arg1, int arg2 = 0);
void funkcja (int arg1); //to ta sama funkcja, zostanie zgłoszony błąd
Kompilator obsługuje przeciążanie przez dodanie do nazwy każdej z przeciążonych funkcji specjalnego identyfikatora, który związany jest z liczbą i typem argumentów - tak więc po etapie kompilacji wszystkie funkcje mają unikalne nazwy.
Zastosowanie
[edytuj]Przeciążenie funkcji stosuje się przy np. potęgowaniu:
int pot (int, int);
double pot (double, int);
void pot (int&, int);
int pot (int podstawa, int wykladnik)
{
int wynik = 1;
for (int i = 0; i < wykladnik; ++i)
wynik = podstawa*wynik;
return wynik;
}
// przeładowana funkcja I: zwraca inny typ danych i są inne parametry
double pot (double podstawa, int wykladnik)
{
double wynik = 1;
for (int i = 0; i < wykladnik; ++i)
wynik = podstawa*wynik;
return wynik;
}
// przeładowana funkcja II: nie zwraca danych tylko modyfikuje podstawę która jest podana przez referencję
void pot (int& podstawa, int wykladnik)
{
int wynik = 1;
for (int i = 0; i < wykladnik; ++i)
wynik = podstawa*wynik;
podstawa = wynik;
}
Argumenty domyślne
[edytuj]Pierwszym sposobem przeładowania są argumenty domyślne. Deklaracja funkcji wygląda tak:
int potega (int podstawa, int wykładnik = 2);
W tym przypadku, kiedy funkcje wywołamy poprzez potega(2), zostanie dodany parametr domyślny. Będzie to więc znaczyło to samo, co potega(2, 2).
Nie możemy już jednak przeciążyć tej funkcji poniższą:
int potega (int podstawa)
{
return podstawa*podstawa;
}
W tym przypadku, gdy podamy jeden argument, kompilator nie będzie mógł określić o którą funkcję nam chodzi - dwuargumentową z jednym argumentem domyślnym, czy zwykłą jednoargumentową.
Typ argumentów
[edytuj]Czasem możemy chcieć, by funkcja zachowywała się zależnie od tego, jakie argumenty jej dano. Załóżmy, że piszemy własną bibliotekę do obsługi standardowego wyjścia stdout. Chcemy zrobić funkcję wypisującą różne typy danych, w tym typ łańcuchów C++.
void pisz (char);
void pisz (std::string);
void pisz (void);
void pisz (char a){
printf ("%c", a);
}
void pisz (std::string a)
{
printf ("%s", a.c_str());
}
void pisz ()
{
printf ("\n");
}
Uwaga!
|
Szablony funkcji
[edytuj]W C++ dostępne są szablony. Wyobraź sobie sytuację: programista pisze funkcję obsługującą sporo typów danych. Możemy rozwiązać to przez kopiowanie funkcji w kodzie. jednak byłoby to dość uciążliwe. Możemy to zrobić krócej:
template <typename T>
T nazwaFunkcji (argumenty typu T)
{
//do funkcji można przekazać dowolny typ danych
}