Na
początku wprowadźmy sobie pojęcie sygnatury.
Sygnatura jest to nazwa metody oraz lista parametrów, jakie ta metoda
przyjmuje. Mówimy więc, że dwie metody mają różne sygnatury, gdy nazywają się
inaczej, bądź mają różną listę parametrów (co do liczby lub ich nazwy).
Spójrzmy na poniższy fragment kodu:
public int
MojaMetoda(int param1);
public int MojaMetoda(int
param1, int param2);
public int MojaMetoda(int
param1, int param2, int
param3);
public int
MojaMetoda(int param1, double
param2, string param3);
Pierwsze trzy metody mają taka samą nazwę oraz zwracają ten
sam typ, ale różnią się ilością parametrów jakie przyjmują. Natomiast trzecia
metoda różni się od czwartej typem dwóch parametrów, jakie ta czwarta metoda
przyjmuje (double param2, string param3).
A więc przeciążenie metody (ang. Method overloading) – czyli
innymi słowy utworzenie nowej wersji metody, polega na zmianie sygnatury tej
metody (zmianie nazwy metody lub liczby parametrów jaką ta metoda przyjmuje,
lub zmianie typu parametrów metody).
Napiszmy więc pierwszy przykład, który będzie ilustrował
przeciążanie metod:
class Przeciazenie
{
public void MojaMetoda()
{
System.Console.WriteLine("Brak parametrów w metodzie.");
}
//przeciazenie
metody mojaMetoda() - dodanie jednego parametru
public void MojaMetoda(int
param1)
{
System.Console.WriteLine("Jeden parametr w metodzie, którego wartość wynosi:
{0}", param1 + ".");
}
//przeciazenie
metody mojaMetoda() - dodanie dwoch parametrow
public void MojaMetoda(int
param1, int param2)
{
System.Console.WriteLine("Dwa parametry w metodzie. Parametr pierwszy to: {0},
a parametr drugi to: {1}", param1,param2 + ".");
}
//przeciazenie
metody mojaMetoda() - parametr typu string
public string
MojaMetoda(string param1)
{
return param1;
}
}
class Glowna
{
static void Main()
{
string
napis;
//obiket
klasy Program
Przeciazenie
prz = new Przeciazenie();
//wywolanie
przeciazonych metod z klasy Przeciazenie
prz.MojaMetoda();
prz.MojaMetoda(8);
prz.MojaMetoda(8, 23);
napis = prz.MojaMetoda("CentrumXP.pl");
System.Console.WriteLine("Nasz napis to: {0}", napis + ".");
}
}
W wyniku uruchomienia powyższego przykładu otrzymamy
następujące wyniki:

Jak
widać, metoda MojaMetoda() jest
przeciążana 4-krotnie. Pierwsza wersja tej metody nie przyjmuje żadnego
parametru. Druga wersja przyjmuje jeden parametr (jest to liczba całkowita).
Natomiast trzecia wersja metody MojaMetoda()
przyjmuje dwa parametry, które również są liczbami całkowitymi.
Wreszcie
czwarta wersja przyjmuje jeden parametr, który jest typu string. A więc przeciążenie tutaj polega na zmianie typu parametru
tej metody. Ta wersja metody różni się od swoich poprzedniczek również typem
jaki zwraca (pierwsze trzy metody MojaMetoda()
zwracają typ intiger, natomiast ta -
czwarta jest typu string).Wprowadzona przez nas definicja przeciążania
mówi o różnicach sygnatur między kolejnymi wersjami metod (wersja czwarta
niewątpliwie spełnia ten wymóg), natomiast nic nie mówi o typach zwracanych
przez poszczególne metody. Czy zmiana tylko typów zwracanych przez dwie metody
przy niezmiennej sygnaturze tych metod sprawi, że obie metody będziemy uważać
za przeciążone?
Jak
się pewnie domyślamy, zmiana samego typu zwracanego nie tworzy nowej wersji
metody, a samo utworzenie dwóch metod o tej samej sygnaturze, ale innym typie
zwracanym, spowoduje, że w trakcie kompilacji otrzymamy błąd (można spróbować
napisać sobie w ramach pracy domowej przykład takiej sytuacji i upewnić się, że
tak naprawdę jest).
W
poniższym przykładzie natomiast, przeciążymy dwukrotnie metodę, której druga
wersja przyjmie inny typ parametru (nazwy parametrów będą w obu metodach te
same) oraz zwróci inny typ niż jej poprzedniczka (pierwsza metoda będzie
zwracać intiger, natomiast druga: typ
o nazwie long).
Oto
przykład:
class Przeciazenie
{
public int MojaMetoda(int
liczba1)
{
return 10 + liczba1;
}
public long
MojaMetoda(long liczba1)
{
return 20 + liczba1;
}
}
class Glowna
{
static void Main()
{
int a;
int b;
Przeciazenie
prz = new Przeciazenie();
a = prz.MojaMetoda(10);
b = prz.MojaMetoda(30);
System.Console.WriteLine("Wynik po wywołaniu pierwszej metody wynosi: {0}",
a);
System.Console.WriteLine("Wynik po wywołaniu drugiej metody wynosi: {0}",
b);
}
}
Po uruchomieniu będziemy mieli następujące wyniki:

A
więc jak widzimy, taki sposób przeciążania metody jest jak najbardziej
prawidłowy i dozwolony. Pomimo faktu, że sposób ten nie jest najczęściej
wykorzystywany przez programistów to pamiętajmy, że można i tak przeciążać
metody.
Podsumowując
przeciążanie metod w języku C#, powiemy, że polega ono po prostu na tworzeniu
nowych wersji tych metod poprzez zmianę ich sygnatur (czyli nazwy i listy
parametrów metody przeciążanej). Klasa może zawierać dowolną liczbę metod, o
ile każda metoda ma inną, unikalną sygnaturę. Każda inna sytuacja spowoduje, że
podczas przeciążania metod, nasz kompilator wyświetli komunikat o błędzie.
Na
koniec przejdźmy do przeciążanie konstruktorów.Podobnie jak w metodach, tak i w konstruktorach możemy używać mechanizmu
przeciążania. Mechanizm ten nie będzie różnił się niczym szczególnym w stosunku
do zwykłego przeciążania metod.
Napiszmy
program, który będzie w zupełności przedstawiał mechanizm przeciążania
konstruktorów. Program ten będzie obliczał pole kwadratu (gdy podamy jeden
wymiar), pole prostokąta (gdy podamy 2 wymiary). Oto przykładowy program:
public class Figura
{
int a;
int b;
//pierwszy
konstruktor, ktory używany jest, gdy nie podamy żadnego wymiaru
public
Figura()
{
a = 0;
b = 0;
}
//drugi
konstruktor, który używany jest, gdy tworzony jest kwadrat
public
Figura(int bok)
{
a = b = bok;
}
//trzeci
konstruktor, ktory uzywany jest, gdy tworzony jest prostokat
public
Figura(int bok1, int
bok2)
{
a = bok1;
b = bok2;
}
//metoda, ktora
oblicza pole odpowiedniej figury
public int Oblicz()
{
return a * b;
}
}
class Glowna
{
public static void Main(string[] args)
{
int
wynik;
//tworzymy
figury, uzywajac roznych konstruktorow
Figura figura1 = new Figura();
Figura figura2 = new Figura(5);
Figura
figura3 = new Figura(6);
//podaje pole
pierwszej figury
wynik = figura1.Oblicz();
System.Console.WriteLine("Pole pierwszej figury wynosi: {0}",
wynik);
//podaje pole
drugiej figury
wynik = figura2.Oblicz();
System.Console.WriteLine("Pole drugiej figury wynosi: {0}",
wynik);
//podaje pole
trzeciej figury
wynik = figura3.Oblicz();
System.Console.WriteLine("Pole trzeciej figury wynosi: {0}", wynik);
}
}
Po
skompilowaniu, otrzymujemy następujące wyniki:

W
powyższym przykładzie klasa Figura posiada
3 konstruktory: pierwszy używany jest w programie przy inicjalizacji obiektu: figura1, gdy nie podamy żadnego wymiaru
boku. W ten sposób w konstruktorze tym, odpowiednim zmiennym przypisywana jest
wartość 0, stąd metoda Oblicz()
(metoda ta oblicza pole na podstawie podanych wymiarów) zwraca dla tego
przypadku pole równe 0.
Drugi
konstruktor używany jest przy inicjalizacji obiektu: figura2, gdy podamy jeden wymiar boku. W ten sposób metoda Oblicz() zwróci pole równe 25 (podaliśmy
jeden wymiar, więc zbudowaliśmy kwadrat). Natomiast trzeci konstruktor używany
jest przy tworzeniu obiektu: figura3. Jest
to przypadek, gdy w konstruktorze podaliśmy 2 wymiary i metoda Oblicz() zwróci nam pole dla prostokąta
(pole w naszym programie wynosi: 36).
Dzisiaj
opowiedzieliśmy sobie o przeciążaniu metod oraz konstruktorów. Są to mechanizmy
bardzo często wykorzystywane przez programistów i na pewno stanowią regułę, a
nie wyjątek.
Za
tydzień opowiemy sobie o hermetyzacji danych w języku C# 2.0.