07. Tworzenie oraz inicjalizacja obiektów

07. Tworzenie oraz inicjalizacja obiektów

 Daniel Celeda
Daniel Celeda
00:00
10.01.2006
31 komentarz
253471 wyświetlenie

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();
    }
}