UWAGA! Promocja dla firm - MICROSOFT OFFICE 365  na 12 miesiecy ZA DARMO! Tylko na CentrumXP.pl!
Wielka promocja Office 365 na CentrumXP.pl!
Do góry Skomentuj

07. Abstrakcja w C#

07. Abstrakcja w C#

Autor: Paweł Kruczkowski Opublikowano: 7 listopada 2006 Odsłon: 50 730

W poprzednim tygodniu opowiedzieliśmy sobie o dwóch bardzo ważnych pojęciach jakimi niewątpliwie są: dziedziczenie oraz polimorfizm. Wprowadziliśmy sobie również definicje metod wirtualnych i przesłaniających, a także poznaliśmy nowe, ważne słówko kluczowe: base.

Dzisiaj na pewno każdy z nas potrafiłby wykorzystać swoją wiedzę na powyższe tematy, dlatego też czym prędzej przejdźmy do przykładu:

public class Figura
{
    protected double a;
    protected double b;
 
    public Figura(double a, double b)
    {
        this.a = a;
        this.b = b;
    }
 
    public virtual double PoleFigury()
    {
        System.Console.WriteLine("Niezdefiniowana figura!");
        return 0;
    }
}
 
public class Prostokat : Figura
{
    public Prostokat(double a, double b) : base(a, b)
    {  }
    public override double PoleFigury()
    {
        double pole = a * b;
        System.Console.WriteLine("Obliczamy pole prostokąta.");
        return pole;
    }
}
 
public class Trojkat : Figura
{
    public Trojkat(double a, double b) : base(a, b)
    { }
    public override double PoleFigury()
    {
        double pole = (a * b) / 2;
        System.Console.WriteLine("Obliczamy pole trójkąta.");
        return pole;
    }
}
 
class Glowna
{
    static void Main(string[] args)
    {
        //deklarujemy odpowiednie obiekty wraz z wartosciami ich zmiennych
        Figura f = new Figura(5, 6);
        Prostokat p = new Prostokat(7, 8);
        Trojkat t = new Trojkat(9, 10);
        //wywolujemy metode obliczajaca pole odpowiedniej figury
        System.Console.WriteLine("Pole wynosi więc: {0}", f.PoleFigury());
        System.Console.WriteLine("Pole wynosi: {0}", p.PoleFigury());
        System.Console.WriteLine("Pole wynosi: {0}", t.PoleFigury());
         
    }
}

Powyższy przykład jest dla nas przypomnieniem podstawowej wiedzy na temat dziedziczenia oraz polimorfizmu. Po skompilowaniu otrzymamy następujące wyniki:

Powyższy program jest bardzo dobrym przykładem, aby wytłumaczyć sobie pewną sytuację. A mianowicie taką, w której chcielibyśmy zadeklarować klasę bazową, która to z kolei byłaby wspólna dla pozostałych (klasa Prostokat oraz klasa Trojkat dziedziczą po klasie bazowej: Figura, a więc Figura jest dla pozostałych wspólna) oraz dawałaby możliwość uzupełnienia szczegółów (metoda PoleFigury() w klasie Figura nie powinna obliczać żadnego pola, a jedynie powinna zostać odziedziczona przez klasy pochodne od klasy Figur i tam dopiero obliczać odpowiednie wartości). Mówiąc jaśniej, rozważmy klasę Prostokat w powyższym kodzie. W klasie tej przesłoniliśmy odziedziczoną od klasy Figura metodę PoleFigury(), która w tej klasie oblicza po prostu pole prostokąta. Dla tej klasy nie ma znaczenia, że metoda PoleFigury() nie jest wcześniej zdefiniowana (w naszym przypadku w klasie Figura). Ma natomiast znaczenie, aby klasa pochodna przesłoniła wszystkie konieczne metody (w tym przypadku właśnie metodę obliczającą pole prostokąta). Aby uzyskać taki mechanizm musimy użyć klas oraz metod abstrakcyjnych.

Innymi słowy, aby wymusić utworzenie nowej wersji metody klasy bazowej, należy tę metodę oznaczyć jako metodę abstrakcyjną. Metoda taka nie zawiera kodu, a jedynie w swej definicji ma: nazwę oraz sygnaturkę. Dopiero w klasach pochodnych należy dodać do takiej metody kod. Jeżeli klasa posiada co najmniej jedną metodę abstrakcyjną, to taką klasę nazywamy klasą abstrakcyjną.

Aby zadeklarować metodę musimy użyć modyfikatora: abstract w następujący sposób:

abstract public void MojaMetoda();

Ponieważ metoda abstrakcyjna nie posiada kodu, po jej sygnaturze nie ma nawiasów klamrowych, a jej definicja kończy się średnikiem.

Aby zadeklarować klasę abstrakcyjną, również używamy słówka: abstract jak poniżej:

 

abstract class MojaKlasa

            {  }

Jak zostało wyżej napisane, klasa abstrakcyjna stanowi jak gdyby bazę metod dla wszystkich jej klas pochodnych, ale – co bardzo ważne – w programie nie wolno nam tworzyć instancji tej klasy. Próba zdefiniowania obiektu klasy abstrakcyjnej zakończy się niepowodzeniem, dlatego też, jeśli jakaś klasa zawiera choć jedną metodę abstrakcyją, to już nie będziemy mogli się do niej odwoływać przez obiekt tej klasy a jedynie poprzez mechanizm dziedziczenia oraz polimorfizmu.

Prześledźmy poniższy przykład:

abstract public class Pierwsza
{
    abstract public void Abstrakcja();
    
    public void Rzeczywistosc()
    {
        System.Console.WriteLine("Moja najzwyklejsza metoda.");
    }
}
 
public class Druga : Pierwsza
{
    public override void Abstrakcja()
    {
        System.Console.WriteLine("Moja pierwsza przesłonięta metoda abstrakcyjna!");
    }
}
 
class Glowna
{
    static void Main(string[] args)
    {
        Druga dr = new Druga();
        dr.Abstrakcja();
        dr.Rzeczywistosc();
    }
}

Klasa Pierwsza implementuje abstrakcyjną metodę Abstrakcja(), która w swej definicji posiada jedynie nazwę oraz sygnaturkę. Klasa ta posiada więc co najmniej jedną abstrakcyjną metodę, stąd jest klasą abstrakcyjną. Klasę tę dziedziczy klasa Druga, w której przesłaniamy metodę abstrakcyjną i dodajemy jej kod. Zauważmy, że w powyższym przykładzie nie ma definicji obiektu klasy pierwszej, ponieważ klasa ta jest abstrakcyjna. Drugi ważny wniosek do zapamiętania: klasa pochodna po klasie abstrakcyjnej musi przesłonić wszystkie metody abstrakcyjne jakie ona posiada.

Po uruchomieniu powyższego programu otrzymamy następujące wyniki:

Znając definicję oraz sposób deklarowania klas oraz metod abstrakcyjnych, spróbujmy udoskonalić pierwszy przykład z dzisiejszego artykułu poprzez zdefiniowanie między innymi klasy Figura jako klasy abstrakcyjnej:

//deklaracja abstrakcyjnej klasy
abstract public class Figura
{
    protected double a;
    protected double b;
 
    public Figura(double a, double b)
    {
        this.a = a;
        this.b = b;
    }
 
    //deklaracja abstrakcyjnej metody
    abstract public double PoleFigury();
}
 
public class Prostokat : Figura
{
    public Prostokat(double a, double b)
        : base(a, b)
    { }
    //przesłoniece abstrakcyjnej klasy
    public override double PoleFigury()
    {
        double pole = a * b;
        System.Console.WriteLine("Obliczamy pole prostokąta.");
        return pole;
    }
}
 
public class Trojkat : Figura
{
    public Trojkat(double a, double b)
        : base(a, b)
    { }
    //przesloniecie abstrakcyjnej metody
    public override double PoleFigury()
    {
        double pole = (a * b) / 2;
        System.Console.WriteLine("Obliczamy pole trójkąta.");
        return pole;
    }
}
 
class Glowna
{
    static void Main(string[] args)
    {
        //deklarujemy odpowiednie obiekty wraz z wartosciami ich zmiennych
        Prostokat pr = new Prostokat(5, 6);
        Prostokat p = new Prostokat(7, 8);
        Trojkat t = new Trojkat(9, 10);
        //wywolujemy metode obliczajaca pole odpowiedniej figury
        System.Console.WriteLine("Pole wynosi więc: {0}", pr.PoleFigury());
        System.Console.WriteLine("Pole wynosi: {0}", p.PoleFigury());
        System.Console.WriteLine("Pole wynosi: {0}", t.PoleFigury());
    }

}

Klasa Figura stała się klasą abstrakcyjną, która posiada abstrakcyjną metodę: PoleFigury(), która to dopiero w klasach pochodnych zostanie odpowiednio zaimplementowana do obliczania pól odpowiednich figur. Oczywiście nie jest możliwe utworzenie obiektu klasy abstrakcyjnej, gdyż kompilator zwróciłby nam błąd. Po prawidłowym skompilowaniu orztymamy następujące wyniki:

W dzisiejszym artykule powiedzieliśmy sobie o klasach i metodach abstrakcyjnych, które ściśle wiążą się z mechanizmami dziedziczenia oraz polimorfizmu. Dowiedliśmy, że klasy abstrakcyjne nie są jedynie sztuczką programowania obiektowego, a reprezentują w pełni tego słowa znaczeniu „abstrakcję”, która umożliwia utworzenie kontraktu dla wszystkich klas pochodnych. Innymi słowy, klasy abstrakcyjne są opisem publicznych metod klas pochodnych, które to rozwijają abstrakcję. Alternatywą dla klas abstrakcyjnych są interfejsy, o których już niedługo sobie opowiemy. Za tydzień natomiast będziemy kontynuować temat klas w języku C# 2.0.

Zobacz również

Komentarze

Brawo, ciekawie i bardzo przystepnie opisane.
jbk, 6 listopada 2007, 17:32
Wreszcie zrozumialem to cholerstwo :) Pozdrawiam.
Tyson, 7 stycznia 2008, 15:12
Brakuje trochę opisu polimorfizmu, czyli odwoływania się do każdej z figur z ostatniego przykładu przez referencję do CFigura zamiast CKwadrat, CProstokat itd.
Jurek Ogórek, 8 stycznia 2008, 09:18
 nic nie czaje

hy, 11 czerwca 2009, 20:03
nie placz Skarbie zdazysz sie jeszcze nauczyc

hyhy, 11 czerwca 2009, 20:05
Hmm ... mam mieszane uczucia, zawsze programiści robili różne dziwne konstrukcje, zeby osiagnąc zamierzony efekt, które minimalizowały wkład pracy nad kodem programu. Tu mamy pierwszorzędny tego przykład! Przecież można to zrobic NORMALNIE, bez udziwnień w semantyce i składni :-) i żadne pieprzone "abstrakcje" nie są do tego potrzebne.
janf, 2 sierpnia 2011, 15:26
#janf Po przeczytaniu tego artykułu, gdybym nie znał wcześniej C++, pomyślałbym tak samo. A to dlatego że autor artykułu nie wspomniał o NAJWAŻNIEJSZEJ funkcji polimorfizmu, czyli tworzenia obiektów klas dziedziczących ze wskaźnika (w c++; w c# to jakoś inaczej się nazywa) na klasę bazową. I dopiero wtedy ten cały system abstrakcji i metod wirtualnych nabiera sensu. W tym kodzie można by usunąć wszystkie słowa "abstract", "virtual" i "override", a program działałby nadal tak samo. Polecam na własną rękę poczytać w googlach o polimorfiźmie w C#, bo w tym artykule brakuje podstawowej informacji - jak można to wykorzystać.
programista, 9 sierpnia 2011, 05:52

Dodaj swój komentarz

Zasady publikacji komentarzyZasady publikacji komentarzy

Redakcja CentrumXP.pl nie odpowiada za treść komentarzy publikowanych na stronach Portalu
i zastrzega sobie prawo do usuwania wypowiedzi, które:

  • zawierają słowa wulgarne, obraźliwe, prowokujące i inne naruszające dobre obyczaje;
  • są jedynie próbami reklamowania stron internetowych (spamowanie poprzez umieszczanie linków);
  • przyczyniają się do złamania prawa bądź warunków licencyjnych oprogramowania (cracki, seriale, torrenty itp.);
  • zawierają dane osobowe, teleadresowe, adresy mailowe lub numery GG;
  • merytorycznie nie wnoszą nic do dyskusji lub nie mają związku z tematem komentowanego newsa, artykułu bądź pliku.

Autor:

Komentarz:

Dodaj komentarz