Klasy i metody abstrakcyjne

Autor podstrony: Krzysztof Zajączkowski

Stronę tą wyświetlono już: 3089 razy

Wstęp

Chociaż interfejsy w wielu przypadkach są wystarczające, jednakże czasami trzeba użyć klas abstrakcyjnych, czyli takich, których instancji obiektu nie da się utworzyć bezpośrednio, nawet jeżeli metody takiej klasy nie są abstrakcyjne. Jest to istotne, ponieważ interfejsy umożliwiają jedynie zaznaczenie, jakie metody muszą obsługiwać klasy po nich dziedziczące.

Przykładowa implementacja klasy abstrakcyjnej

Oto prosty przykład klasy abstrakcyjnej:

public abstract class aGeometryObj { public string object_name; public aGeometryObj() { object_name = ""; } public aGeometryObj(string object_name) { this.object_name = object_name; } public double Length { get; set; } public abstract override string ToString(); public double X { get; set; } public double Y { get; set; } } // ########################### DEKLARACJA KLASY POINT@D ############################# public class Point2D : aGeometryObj//, IPoint2D { // ####################### CHRONIONE POLA KLASY ################################# protected double x; protected double y; // ####################### KONSTRUKTORY KLASY ################################### public Point2D() // konstruktor zerujący : base("Początek układu współrzędnych") { x = y = 0; } public Point2D(double x, double y) // konstruktor ustawiajacy { this.x = x; this.y = y; } public Point2D(Point2D p) // kosntruktor kopiujący { this.x = p.x; this.y = p.y; } // ######## WŁAŚCIWOŚCI KLASY ########## public new double Y { get { return y; } set { y = value; if( y == 0 && x == 0){ this.object_name = "Początek układu współrzędnych"; } } } public new double X { get { return x; } set { x = value; if( y == 0 && x == 0){ this.object_name = "Początek układu współrzędnych"; } } } public new double Length { get { return Math.Sqrt(x * x + y * y); } // pobieranie długości wektora set // ustawianie długości wektora { if (x != 0 || y != 0) // gdy wektor nie jest zerowy to { double k = value / Length; x *= k; // skalowanie składowej x wektora y *= k; // skalowanie składowej y wektora } } } // ########### METODY ############# public override string ToString() // przeładowana metoda ToString klasy bazowej Object { return "Point2D x = " + x + "; y = " + y; } } // ############################## DEKLARACJA KLASY POINT3D ################################# public class Point3D : Point2D, Klasy.IPoint3D // dziedziczy po Point2D { // ########################## CHRONIONE POLA KLASY ##################################### protected double z; // ########################## KONSTRUKTORY KLASY ####################################### public Point3D() : base() // wywołanie bezparametrowego kosntruktora klasy bazowej { z = 0; } public Point3D(double x, double y, double z) : base(x, y) // wywołanie ustawiającego konstruktora klasy bazowej { this.z = z; } public Point3D(Point3D p) // konstruktor kopiujący : base(p) // wywołanie kontruktora kopiującego klasy bazowej { z = p.z; } // ################# WŁAŚCIWOŚCI ############### public double Z { get { return z; } set { z = value; } } public new double Length // przysłanianie właściwości z klasy bazowej (oznacza to słowo kluczowe new) { get { return Math.Sqrt(x * x + y * y + z * z); } // pobieranie długości wektora set // ustawianie długości wektora { if (x != 0 || y != 0 || z != 0) { double k = value / Length; X *= k; Y *= k; z *= k; } } } // ################# METODY ################ public new string ToString() // przysłanianie metody z klasy bazowej (oznacza to słowo kluczowe new) { return "Point3D x = " + X + "; y = " + Y + "; z = " + z; } }

W powyższym kodzie klasa abstrakcyjna aGeometryObj ma publiczne pole object_name, zaimplementowane na wypadek, gdyby ktoś zażyczył sobie stworzyć jakiś obiekt geometryczny o szczególnych cechach, który zostałby opisany nazwą własną. Takim obiektem może być np. punkt 2W lub 3W. Trochę na wyrost umieściłem tutaj metody oraz właściwości klasy, które zostały zaimplementowane wcześniej w interfejsie IPoint2D, ale to tylko po to aby pokazać, że można tutaj umieszczać również funkcje i właściwości klas. Teraz korzystając z powyższych klas, mogę zrobić coś takiego:

aGeometryObj[] t = new aGeometryObj[2]; t[0] = new Point2D(100, 200); t[1] = new Point3D(20, 30, 40); foreach (aGeometryObj p2 in t) { if (p2 is Point3D) { Console.WriteLine(((Point3D)p2).ToString()); } else { Console.WriteLine(p2.ToString()); } } Console.ReadLine();

Wynik działania:

Point2D x = 100; y = 200
Point3D x = 20; y = 30; z = 40

Czyli to samo co poprzednio, ale poprzednio nie mogłem zrobić czegoś takiego:

aGeometryObj[] t = new aGeometryObj[2]; t[0] = new Point2D(100, 200); t[0].object_name = "Punkt 2W - tutaj zaczepię środek ciężkości trójkąta"; t[1] = new Point3D(20, 30, 40); t[1].object_name = "Punkt 3W - tutaj będzie środek ciężkości jakiejś bryły przestrzennej"; foreach (aGeometryObj p2 in t) { if (p2 is Point3D) { Console.WriteLine(((Point3D)p2).ToString()); } else { Console.WriteLine(p2.ToString()); } Console.WriteLine(p2.object_name); } Console.ReadLine();

Wynik działania tego kodu jest następujący:

Point2D x = 100; y = 200
Punkt 2W - tutaj zaczepię środek ciężkości trójkąta
Point3D x = 20; y = 30; z = 40
Punkt 3W - tutaj będzie środek ciężkości jakiejś bryły przestrzennej
Propozycje książek