Paweł Łukasiewicz
2015-03-20
Paweł Łukasiewicz
2015-03-20
Udostępnij Udostępnij Kontakt
Jednym z najważniejszych pojęć w programowaniu obiektowym jest dziedzicznie. Dziedziczenie pozwala nam na zdefiniowanie klasy w uogólnieniu innej klasy, co pozwala na łatwiejsze tworzenie i zarządzanie aplikacją. Daje również możliwość ponowego wykorzystania kodu i przyśpiesza czas jego implementacji.

Podczas tworzenia nowej klasy, zamiast pisać zupełnie od nowa wszystkie składowe tej klasy, programista może powiedzieć, że nowa klasa ma dziedziczyć z istniejącej już klasy. Istniejąca klasa nazywana jest klasą bazową a nowa klasa dziedzicząca po klasie bazowej nosi nazwę klasy pochodnej.

Idea dziedziczenia realizuje związek to-jest (IS-A). Przykładowo, ssak ‘to-jest’ zwierzę, pies ‘to-jest’ ssak ale pies ‘to-jest’ też zwierzę, i tak dalej.

Klasa bazowa i pochodna

Klasa może dziedziczyć z jednej klasy, ale może implementować wiele interfejsów.
Składnia dziedziczenia:
modyfikator_dostepu class klasa_bazowa
{
	…
}
class klasa_pochodna : klasa_bazowa
{
	…
}
Tradycyjnie już prześledzmy poniższy przykład, który w czytelniejszy sposób pozwoli zrozumieć idee dziedziczenia:
using System;

namespace Dziedziczenie
{
    class Program
    {
        static void Main(string[] args)
        {
            Prostokat pr = new Prostokat();
            pr.UstawSzerokosc(4);
            pr.UstawWysokosc(5);

            // Obliczenie powierzchni
            Console.WriteLine("Powierzchnia prostokąta: {0}", pr.ObliczPowirzchnie());
            Console.ReadKey();

            // Wynik działania programu
            // Powierzchnia prostokata: 20
        }
    }

    // klasa bazowa
    class Ksztalt
    {
        // modyfikator dostepu protected
        // pola dostepne sa dla klasy oraz klas, której po niej dziedziczą
        // gdybyśmy zastosowali modyfikator dostępu private
        // pole byłoby dostępne tylko dla tej klasy
        protected int szerokosc;
        protected int wysokosc;

        public void UstawWysokosc(int w)
        {
            wysokosc = w;
        }
        public void UstawSzerokosc(int s)
        {
            szerokosc = s;
        }
    }

    // klasa pochodna
    class Prostokat:Ksztalt
    {
        public int ObliczPowirzchnie()
        {
            // mamy dostęp do pól z klasy bazowej
            return wysokosc * szerokosc;
        }
    }
}


Odwołanie do klasy bazowej

Klasa pochodna dziedziczy składowe klasy bazowej, tj. pola, metody. Podczas dziedziczenia wielokrotnie pojawi się potrzeba uzyskania dostępu do składowych klasy bazowej. Dostęp do takich pól czy metod jest możliwy po użyciu słowa kluczowego base. Może ono zostać również użyte do przekazania parametrów konstruktora do klasy bazowej. Poniżej przykład, który pozwoli lepiej zrozumieć regułu użycia słowa kluczowego base:
using System;

namespace DziedziczenieBazowa
{
    class Program
    {
        static void Main(string[] args)
        {
            Blat tp = new Blat(4, 5);
            tp.WyswietInformacje();
            Console.ReadKey();

            // Wynik działania programu
            //Dlugosc: 4
            //Szerokosc: 5
            //Powierzchnia: 20
            //Koszt: 1000
        }
    }

    // klasa bazowa
    class Prostokat
    {
        protected int dlugosc;
        protected int szerokosc;

        public Prostokat(int d, int s)
        {
            dlugosc = d;
            szerokosc = s;
        }

        public int ObliczPowierzchnie()
        {
            return dlugosc * szerokosc;
        }

        public void WyswietlInformacje()
        {
            Console.WriteLine("Długość: {0}", dlugosc);
            Console.WriteLine("Szerokość: {0}", szerokosc);
            Console.WriteLine("Powierzchnia: {0}", ObliczPowierzchnie());
        }
    }

    // klasa pochodna
    class Blat : Prostokat
    {
        // Słowo kluczowe base przy konstruktorze pozwala nam wywowołać konsturktor klasy bazowej
        // W tym momencie przekazaliśmy nasze parametry do konstruktora klasy bazowej
        public Blat(int d, int s) : base(d,s)
        {
        }

        public int Koszt()
        {
            int koszt;
            koszt = ObliczPowierzchnie() * 50;
            return koszt;
        }

        public void WyswietInformacje()
        {
            // słowo kluczowe base pozwala nam odwołać się do składowych klasy bazowej
            // dla kompilatora ważniejsze się zmienne z klasy w której właśnie jesteśmy
            // za pomocą słowa kluczowe base wskazujemy jednoznacznie do której składowej
            // chcemy się odwołać. Dziękimi poniższemu wywołaniu w obecnej metodzie wywołamy
            // również metodę z klasy bazowej - wyświetlona zostanie większa ilość informacji
            base.WyswietlInformacje();
            Console.WriteLine("Koszt: {0}", Koszt());
        }

    }
}

Wielokrotne dziedziczenie

Język C# nie obsługuje wielokrotnego dziedziczenia. Klasa może dziedziczyć po jednej klasie bazowej, ale może implementować wiele interfejsów (zostaną szczegółowo omówione w jednym z kolejnych rozdziałów).
using System;

namespace DziedziczenieInterfejsy
{
    class Program
    {
        static void Main(string[] args)
        {
            Prostokat pr = new Prostokat(4, 5);
            Console.WriteLine(pr.WyswietDlugosc(pr.dlugosc));
            Console.WriteLine(pr.WyswietSzerokosc(pr.szerokosc));
            Console.WriteLine("Cena to: {0}", pr.ObliczKoszt(25));

            Console.ReadKey();
            // Wynik działania programu
            //Dlugosc to: 4
            //Szerokosc to: 5
            //Cena to: 500
        }
    }

    // klasa bazowa
    class Ksztalt
    {
        public int dlugosc;
        public int szerokosc;

        public Ksztalt(int d, int s)
        {
            dlugosc = d;
            szerokosc = s;
        }

        public int ObliczPowierzchnie()
        {
            return dlugosc * szerokosc;
        }
    }

    // definicja interfejsu
    // zawiera tylko szkielet metody
    public interface ObliczKoszt
    {
        int ObliczKoszt(int powierzchnia);
    }

    public interface WyswietlanieInformacji
    {
        string WyswietDlugosc(int dlugosc);

        string WyswietSzerokosc(int szerokosc);
    }

    class Prostokat : Ksztalt, ObliczKoszt, WyswietlanieInformacji
    {
        public Prostokat(int d, int s) : base(d, s)
        {
        }
        // implementacja metody interfejsu ObliczKoszt
        public int ObliczKoszt(int p)
        {
            int koszt;
            koszt = p * ObliczPowierzchnie();
            return koszt;
        }

        // implementacja metod interfejsu WyswietlanieInformacji
        public string WyswietDlugosc(int dlugosc)
        {
            string info = String.Format("Długość to: {0}", dlugosc);
            return info;
        }

        public string WyswietSzerokosc(int szerokosc)
        {
            string info = String.Format("Szerokość to: {0}", szerokosc);
            return info;
        }
    }
}