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