Definicja klasy i obiektu

underTaker

Klasa a obiekt

Aby zrozumieć różnicę pomiędzy klasą a obiektem, możemy spojrzeć na te dwa pojęcia jak na przykład wzięty z życia. Mamy dajmy na to samochód. Samochodów może być dużo, mogą mieć różne marki, różne kolory oraz różnych właścicieli. Taki właśnie samochód jest klasą - wiemy jakie ma parametry, lecz nie znamy ich wartości. Spośród wielu samochodów wybieramy sobie jeden, a właściwie tworzymy go. Chcemy aby taki samochód przykładowo był Fordem w kolorze czarnym posiadanym przez nas. Ten właśnie Ford jest obiektem - posiada nadane jakieś wartości i możemy wykonywać na nim dalsze operacje.

Tyle z teorii, zobaczmy teraz jak powyższy wstęp prezentuje się w kodzie. Żeby utworzyć obiekt, należy najpierw mieć klasę, czyli typ danych. Typem danych może być int, string, point czy właśnie klasa stworzona przez nas. Stwórzmy zatem naszą klasę. Będę dalej opisywał wszystko na podstawie poprzedniego przykładu samochodu. Zatem nasz samochodzik w kodzie prezentuje się w następujący sposób:

class Samochod
{
    public string marka;
    public int kolor;
    public int przebieg;
}

Wiemy, że będziemy mogli przypisać mu markę, kolor oraz przebieg, lecz nie możemy nic z nim zrobić - co to za samochód, którym nie można jeździć? Oczywiście klasa nie ogranicza się do zawierania jedynie pól (pole - zmienna na poziomie klasy) - klasa może zawierać także metody, właściwości, inne klasy, struktury itp. itd.

Jak widać przez deklaracją każdego pola użyte zostało słówko kluczowe public - jest to Modyfikator dostępu mówiący kompilatorowi, że jest to obiekt, który będzie widoczny dla wszystkich.

Dodajmy więc jakieś metody do naszej klasy.

class Samochod
{
    public string marka;
    public int kolor;
    public int przebieg;

    public void Drive()
    {
        Console.WriteLine("Prowadzę samochód!");
    }

    public void Ignition()
    {
        Console.WriteLine("Uruchomiono silnik!");
    }
}

Jeśli spróbujemy użyć któregoś w powyższych pól, czy metod w odpowiedzi zobaczymy jedynie błąd - nie możemy przecież użyć wartości jakiegoś samochodu - musimy użyć konkretnego auta. Jako że aktualnie nie posiadamy żadnego, musimy go sobie stworzyć.

Samochod auto = new Samochod();

W tym momencie tworzymy instancję klasy - czyli jej obiekt. Kluczowym słówkiem w tej konstrukcji jest słówko new - zajmuje ono miejsce w pamięci dla tworzonego obiektu, wykonując jednocześnie kod zawarty w konstruktorze klasy. W naszym wypadku nie stworzyliśmy żadnego konstruktora. Czym właściwie ów konstruktor jest? Jest to po prostu metoda wykonywana zaraz przy tworzeniu instancji obiektu o definicji takiej samej jak każda inna metoda - posiada modyfikatory dostępu, oraz parametry - nie posiada jednak dowolnej nazwy (zawsze nazywa się tak, jak klasa, w której się zawiera) oraz zwracanego typu.

Konstruktor klasy

Załóżmy, że po wyprodukowaniu naszego samochodu lakierujemy go na losowy kolor. Jest to idealne zadanie do wykonania właśnie w konstruktorze klasy. Konstruktor jest wykonywane tylko i wyłącznie raz - jak wyżej napisałem - przy tworzeniu jej instancji. Stwórzmy zatem nasz konstruktor.

Do klasy Samochód należy dopisać metodę bez zwracanego typu o nazwie takiej samej jak jego klasa - czyli Samochod:

public Samochod(string marka)
{
    Random rand = new Random();
    kolor = rand.Next(); //Lakierujemy na losowy kolor
    przebieg = 0; //Dopiero wyjechaliśmy z fabryki
    this.marka = marka; //Ustawiamy markę naszego samochodu na podaną jako parametr
}

Po pierwsze losujemy kolor dla naszego autka i go ustawiamy. Następnie ustawiamy przebieg na zero (nie jest to konieczne, ponieważ zmienne typu int domyślnie mają wartość 0), następnie ustawiamy markę naszego samochodu na taka, jaką przekazaliśmy w parametrze. Użyliśmy jednak nowego słówka - this. To słówko "mówi" kompilatorowi, że chcemy użyć jakiegoś obiektu, który jest zdefiniowany na poziomie klasy - w naszym wypadku pole marka. Dlaczego jednak nie trzeba było użyć tego słówka przy poprzednich polach? Kompilator "szuka" najpierw zmiennych o podanej nazwie w metodzie, w której się znajduje, a następnie w klasie, przez co użycie tego słówka nie jest konieczne. Zauważmy jednak, że nazwałem parametr naszego konstruktora tak samo jak nazwa pola marka - to nie jest błędem, w takiej sytuacji należy jednak poinformować kompilator której z tych zmiennych chcemy użyć. Można to zrobić jedynie za pomocą słówka this, które zwraca obiekt, na którym właśnie pracujemy.

Pojęcie konstruktora i destruktora jest szerzej opisane w artykule Konstruktory i Destruktory.

Używanie obiektu

Dobrze, mamy zdefiniowaną nasza klasę oraz stworzony obiekt. Musimy więc też umieć go używać.
Mając zmienną auto, typu Samochod, możemy za jej pomocą użyć pól i metod, które są w klasie. Wyświetlmy zatem markę, kolor oraz przebieg naszego samochodu. Jako, że dodaliśmy do konstruktora parametr marka, musimy go podać przy tworzeniu instancji tej klasy.

Samochod auto = new Samochod("Ford"); //Podajemy wartość parametru jak przy zwykłej metodzie
Console.WriteLine(auto.marka);
Console.WriteLine(auto.kolor);
Console.WriteLine(auto.przebieg);

Wynik powinien być następujący:

Ford
-553249 //Tutaj oczywiście zależy jaki kolor został wylosowany
0

W taki sposób możemy również wywoływać metody oraz zmieniać wartości pól.

Samochod auto = new Samochod("Ford");
auto.Drive();
auto.kolor = -65535;

Podsumowanie

Klasy i obiekty to podstawa języka C#, co zresztą wskazuje sama nazwa - obiektowy język programowania. Oczywiście artykuł ten przedstawia jedynie podstawy obiektowości, która daje ogromne możliwości, które są bardziej szczegółowo opisane w dalszej części tego działu.

4 komentarzy

Popraw linki bo w jednym są krzaczki a drugi ma podkreślniki.

Całkiem nieźle wytłumaczone, ale mam wrażenie że przykłady czerpałeś z kursy na MVA "C# Fundamentals for Absolute Beginners".

Nie, this używamy także, gdy chcemy wywołać np. jakąś metodę w klasie aktualnie używanym obiektem.

Np.

Masz dwie metody w klasie: DodajDwa i DodajTrzy;
W metodzie DodajDwa chcesz, by wykonała ona inną metodą: DodajTrzy.
Dlatego w kodzie DodajDwa pisze się
this.DodajTrzy();

czy this.typ w takiej formie używa się tylko w przypadku kolizji nazw "parametru" i "elementu klasy" ?