W poprzednim artykule stworzyliśmy nasz pierwszy obiekt. Dzisiaj dowiemy się na czym polega mechanizm tworzenia obiektów i jak używać konstruktorów (specjalnych metod przeznaczonych do tego celu).
Definiowanie konstruktorów
Przypomnijmy sobie program z poprzedniego artykułu.
class
Echo
{
string napis;
public void WczytajNapis()
{
System.Console.WriteLine("Podaj napis.");
napis = System.Console.ReadLine();
}
public
void Napisz()
{
System.Console.Write("Napisałeś: ");
System.Console.WriteLine(napis);
}
}
class KlasaGlowna
{
static
void Main()
{
Echo
obiektEcho = new Echo();
obiektEcho.WczytajNapis();
obiektEcho.Napisz();
}
}
Przypominam, że teksty
umieszczone w cudzysłowach to łańcuchy znakowe. Instrukcja „new Echo()”
nakazuje stworzenie nowego obiektu. „Echo()” to konstruktor klasy, której
instancję chcemy stworzyć. No tak, ale przecież
w klasie „Echo" nie mamy zdefiniowanego żadnego konstruktora. Nie jest to
prawdą, ponieważ w każdej klasie jest zdefiniowany domyślny konstruktor, który
możemy zastąpić własnym. Co więcej, możemy w
jednej klasie stworzyć kilka konstruktorów i używać ich w zależności od
potrzeb.
Do czego potrzebne są nam konstruktory? Nie wystarczyłoby
same słówko „new”?
Dzięki konstruktorowi, możemy podczas jego użycia od razu
przypisać wartości zmiennym. Przypatrzmy się poniższemu przykładowi.
class
Echo
{
string
napis;
public
Echo(string nowyNapis)
{
napis = nowyNapis;
}
public void Napisz()
{
System.Console.Write("Napisałeś: ");
System.Console.WriteLine(napis);
}
}
class KlasaGlowna
{
static
void Main()
{
Echo
obiektEcho = new Echo("Napis
podany w konstruktorze");
obiektEcho.Napisz();
System.Console.ReadLine();
}
}
Konstruktor zdefiniowany jest tutaj:
public
Echo(string
nowyNapis)
{
napis = nowyNapis;
}
Definicję konstruktora powinno poprzedzać słówko „public”, ponieważ konstruktor będzie używany wewnątrz innych klas, które będą chciały powoływać do życia obiekty klasy „Echo”. Istnieją sytuacje, w których należy zdefiniować prywatny konstruktor, jednak nas one na razie nie dotyczą J Parametr jaki przyjmuje konstruktor to „nowyNapis”. Jest to parametr typu „string”, a więc tekstowy. W ciele konstruktora, zmiennej „napis” przypisujemy wartość podaną w parametrze.
@STRONA@Zobaczmy teraz jak będzie wyglądał wynik działania programu z domyślnym konstruktorem.
class
Echo
{
string
napis;
public
void Napisz()
{
System.Console.WriteLine(napis);
System.Console.ReadLine();
}
}
class KlasaGlowna
{
static
void Main()
{
Echo
obiektEcho = new Echo();
obiektEcho.Napisz();
}
}
Nic nie pojawiło się na ekranie, ponieważ nie wpisujemy żadnej wartości do zmiennej “napis”. Domyślną wartością dla zmiennej typu string jest pusty tekst, a więc jeśli chcemy użyć zmiennej tekstowej, do której wcześniej nic nie „włożyliśmy” wynik będzie taki, jakbyśmy wykonali wcześniej instrukcję:
napis
= "";
Spójrzmy na program z konstruktorem zdefiniowanym przez nas, ale będącym identycznym jak domyślny.
class
Echo{
string
napis;
public
Echo()
{
}
public
void Napisz()
{
System.Console.WriteLine(napis);
System.Console.ReadLine();
}
}
class KlasaGlowna
{
static
void Main()
{
Echo
obiektEcho = new Echo();
obiektEcho.Napisz();
}
}
Wynik nie będzie się różnił od programu z konstruktorem
domyślnym.
Napiszmy teraz program z kilkoma konstruktorami.
class
Echo
{
string
napis;
string
napis2;
public
Echo()
{
}
public
Echo(string parametr)
{
napis = parametr;
}
public
Echo(string parametr1, string parametr2)
{
napis = parametr1;
napis2 = parametr2;
}
public
void Napisz()
{
System.Console.WriteLine(napis);
System.Console.WriteLine(napis2);
}
}
class KlasaGlowna
{
static
void Main()
{
Echo obiekt1
= new Echo();
Echo obiekt2
= new Echo("Konstruktor
z jednym parametrem.");
Echo obiekt3
= new Echo("Konstruktor
z dwoma parametrami.", "Drugi
parametr.");
obiekt1.Napisz();
obiekt2.Napisz();
obiekt3.Napisz();
System.Console.ReadLine();
}
}
Stworzyliśmy 3 konstruktory, pierwszy bezparametrowy (zmienne “napis” oraz “napis2” otrzymują domyślne puste wartości), drugi z jednym parametrem przypisującym wartość zmiennej „napis” oraz trzeci, który przypisuje wartości obydwu zmiennym. W metodzie „Main()” klasy „KlasaGlowna” tworzymy trzy obiekty klasy „Echo”, wywołując stworzone przez nas konstruktory. Wynik działania programu to wypisane wartości znajdujące się w zmiennych „napis” oraz „napis2” każdego z obiektów.
Ważną sprawą jest, aby deklaracje naszych konstruktorów były unikalne, a więc jeśli mamy 3 różne konstruktory to wywołując je powinno być jednoznacznie wiadomo, o który chodzi. Aby konstruktory odróżniały się muszą mieć różna liczbę parametrów bądź różny ich typ (np. jeden z parametrem typu „string”, a drugi z parametrem typu „int”). W naszym przykładzie konstruktory różnią się ilością otrzymywanych parametrów. Wywołując konstruktor z jednym parametrem typu „string”, jednoznacznie wiadomo, że chodzi o drugi konstruktor.
@STRONA@Inicjalizacja składowych
Jeśli nasz klasa jest rozbudowana i ma wiele zmiennych oraz konstruktorów to może się zdarzyć, że w każdym z nich będziemy musieli przypisywać wartości zmiennym. Dużo nadmiarowej pracy – dublowanie się kodu. Możemy temu zapobiec na kilka sposobów.
Wywołanie jednego konstruktora poprzez drugi
Aby uzyskać taki efekt musimy użyć słówka „this”.
class
Echo
{
string
napis;
string
napis2;
public
Echo(string parametr)
{
napis = parametr;
}
public
Echo(string parametr1, string parametr2) : this(parametr1)
{
napis2 = parametr2;
}
public
void Napisz()
{
System.Console.WriteLine(napis);
System.Console.WriteLine(napis2);
}
}
class KlasaGlowna
{
static
void Main()
{
Echo obiekt
= new Echo("Pierwszy
parametr.", "Drugi
parametr.");
obiekt.Napisz();
System.Console.ReadLine();
}
}
W tym przykładzie mamy dwa konstruktory, z jednym oraz z dwoma parametrami. W definicji drugiego wywołujemy pierwszy poprzez słówko „this” oraz przekazujemy do pierwszego pierwszy parametr. W linijce:
Echo
obiekt = new Echo("Pierwszy
parametr.", "Drugi parametr.");
wywołujemy drugi konstruktor (dwa parametry), ten natomiast wywołuje pierwszy przekazując mu wartość „Pierwszy parametr.". Tak więc wartość zmiennej „napis” jest ustalana w pierwszym konstruktorze, który został wywołany przez drugi, natomiast wartość zmiennej „napis2” jest przypisywana w drugim konstruktorze.
@STRONA@Inicjalizacja w dodatkowej metodzie
Polega ona na przypisaniu wartości do zmiennych w dodatkowej (lub w kilku) metodzie.
class
Echo
{
string
napis;
string
napis2;
public
Echo(string parametr1, string parametr2)
{
PrzypiszWartosci(parametr1, parametr2);
}
public void PrzypiszWartosci(string
parametr1, string
parametr2)
{
napis = parametr1;
napis2 = parametr2;
}
public void Napisz()
{
System.Console.WriteLine(napis);
System.Console.WriteLine(napis2);
}
}
class KlasaGlowna
{
static
void Main()
{
Echo obiekt
= new Echo("Pierwszy
parametr.", "Drugi parametr.");
obiekt.Napisz();
System.Console.ReadLine();
}
}
Inicjalizacja na etapie deklaracji
W C# możemy przypisywać wartości do zmiennych już na etapie ich deklarowania.
class
Echo
{
string napis = "Pierwszy parametr.";
string napis2 = "Drugi parametr.";
public void Napisz()
{
System.Console.WriteLine(napis);
System.Console.WriteLine(napis2);
}
}
class KlasaGlowna
{
static
void Main()
{
Echo obiekt = new Echo();
obiekt.Napisz();
System.Console.ReadLine();
}
}
Ćwiczenie
Stwórz klasę „Czlowiek” zawierającą zmienne:
- imię typu string,
- nazwisko typu string,
- wiek typu int.
Zdefiniuj konstruktor dla tej klasy, który na podstawie otrzymanych parametrów zainicjalizuje jego zmienne.
Stwórz klasę główną aplikacji, w jej metodzie „Main()” stwórz obiekt klasy „Czlowiek” przekazując do konstruktora odpowiednie wartości. Wypisz na ekranie zawartość zmiennych opisujących nowopowstały obiekt (imię, nazwisko oraz wiek).
Rozwiązanie:
class
Czlowiek
{
string imie;
string nazwisko;
int wiek;
public Czlowiek(string noweImie, string
noweNazwisko, int nowyWiek)
{
imie = noweImie;
nazwisko = noweNazwisko;
wiek = nowyWiek;
}
public void WypiszDane()
{
System.Console.WriteLine("Imię: " + imie);
System.Console.WriteLine("Nazwisko: " + nazwisko);
System.Console.WriteLine("Wiek: " + wiek);
}
}
class
KlasaGlowna
{
static
void Main()
{
Czlowiek jan
= new Czlowiek("Janusz",
"Kowalski", 20);
jan.WypiszDane();
System.Console.ReadLine();
}
}