Klasy w C# są typami referencyjnymi, co oznacza, że każda instancja klasy jest wskaźnikiem na jakiś adres pamięci, gdzie wszystkie pola oraz metody klasy się znajdują. Dzięki takiemu rozwiązaniu dużo szybciej można operować na obiektach danej klasy. W C# każda klasa dziedziczy po klasie Object i może dziedziczyć tylko po jednej klasie. Nie ma natomiast ograniczeń, jeżeli chodzi o dziedziczenie po interfejsach.
Podstawowa deklaracja klasy
Poniżej zamieszczam ogólny wzór podstawowej deklaracji klasy:
Oczywiście rodzaj dostępu może być jednym z pięciu dostępnych:
public - oznacza, że dana zmienna lub metoda są dostępne z każdego miejsca kodu. Ten typ dostępu jest domyślny dla interfejsów;
private - oznacza, że dana zmienna lub metoda są dostępne tylko z wnętrza danego typu, w którym została zadeklarowana. Ten typ dostępu jest domyślny dla klas i struktur;
protected - oznacza, że dana zmienna lub metoda są dostępne z wnętrza klasy do której należy oraz z wnętrza klas pochodnych;
internal - oznacza, że dana zmienna lub metoda są dostępne jedynie z wnętrza złożenia. C# kompiluje pliki *.cs w moduły a następnie grupuje w złożenia;
protected internal - oznacza, że dana zmienna lub metoda są dostępne z wnętrza klasy, w której została zadeklarowana lub z wnętrza złożenia.
Dodawanie pliku klasy do projektu
W głównym kodzie programu (czyli w pliku Program.cs) można co prawda umieszczać deklaracje klas, jednakże nie jest to zalecane zwłaszcza w przypadku dużych projektów. Z tego też powodu warto nauczyć się tworzyć dodatkowe pliki z kodem klas. W tym celu należy wcisnąć kombinację klawiszy Ctr+Alt+L lub w menu kliknąć View→Source Explorer, powinno pojawić się okno Source Explorer, w którym niezwłocznie należy kliknąć prawym przyciskiem myszy by w menu podręcznym kliknąć pozycję Add→Class....
Po kliknięciu wcześniej wymienionej pozycji menu pojawić się powinno okno dialogowe Add New Item - Klasy, w którym niezwłocznie wpisać należy nazwę klasy dodawanej, czyli Point2D po czym należy wcisnąć przycisk Add by plik został dodany.
Przykład implementacji klas
W nowo utworzonym pliku zamieszczony zostanie następujący kod dwóch klas: Point2D i Point3D:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Klasy
{
// ########################### DEKLARACJA KLASY POINT@D #############################
public class Point2D
{
// ####################### CHRONIONE POLA KLASY #################################
protected double x;
protected double y;
// ####################### KONSTRUKTORY KLASY ###################################
public Point2D() // konstruktor zerujący
{
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 double Y
{
get { return y; }
set { y = value; }
}
public double X
{
get { return x; }
set { x = value; }
}
public 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 // 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;
}
}
}
O właściwościach rozpisywałem się przy okazji omawiania tematu związanego z Programowanie → Podstawy C# → Struktury, również temat dotyczący metod został już niejako poruszony, natomiast to na co należy zwrócić uwagę, to sposób dziedziczenia i obsługi konstruktorów klasy.
W pliku Program.cs należy umieścić następujący kod:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Klasy
{
class Program
{
static void Main(string[] args)
{
var p3d = new Point3D(10, 20, 30);
Console.WriteLine(p3d.ToString());
Point2D p2d = p3d;
Console.WriteLine(p2d.ToString());
Console.ReadLine();
}
}
}
Skompilowanie kodu da następujący efekt:
Point3D x = 10; y = 20; z = 30
Point2D x = 10; y = 20
Stało się tak, ponieważ klasa Point3D dziedziczy po klasie Point2D.