StrukturaCzęść NR.8 Klasy są typami referencyjnymi i ich zawartość jest zawsze tworzona na stercie. W niektórych wypadkach klasa zawiera tak niewielką ilość danych , że zarządzanie nimi na stercie jest nieopłacalne. W takich wypadkach lepiej użyć struktury.
Struktura jest typem wartościowym, czyli jej miejsce jest na stosie.
Chociaż jeśli struktura jest duża to lepiej stosować klasy.
Podobnie jak klasy struktura może mieć własne pola i metody……oraz w pewnym specjalnym wypadku konstruktor.
Przykładem struktury jest np. Point w WPF i Windows Forms, która przechowuje dwie zmienne X i Y.
Jednak co ważniejsze i możesz nie zdawać sobie z tego sprawy, ale strukturami są też podstawowe typy numeryczne, jak np. int , który tak naprawdę jest strukturą System.Int64. Te struktury mają metody jak np. ToString() czy stałe (const) jak wartość maksymalna i minimalna dla int, czy dla float nieskończoność.
Oto mała tabelka wyjaśniająca, co jest strukturą , a co klasą
Słowo kluczowe | Alias do | Czym to jest? |
bool | System.Boolean | Struktura |
byte | System.Byte | Struktura |
decimal | System.Decimal | Struktura |
double | System.Double | Struktura |
float | System.Single | Struktura |
int | System.Int32 | Struktura |
long | System.Int64 | Struktura |
sbyte | System.SByte | Struktura |
short | System.Int16 | Struktura |
uint | System.UInt32 | Struktura |
ulong | System.UInt64 | Struktura |
ushort | System.UInt16 | Struktura |
object | System.Object | Klasa |
string | System.String | Klasa |
Podstawową różnicą pomiędzy strukturą i klasą jest to, że struktury nie obsługują dziedziczenia.
Tak czy siak, oczywiście możemy tworzyć swoje własne struktury.
Tworzenie struktury
Aby zadeklarować strukturę analogicznie do klasy używasz słowa kluczowego struct. Analogicznie do klasy zawartość naszej struktury zawiera się pomiędzy nawiasami klamrowymi.
struct Punkt3D
{
public double X;
public double Y;
public double Z;
}
Struktura może posiadać konstruktor pod warunkiem , że zawiera on jakieś parametry. Mówiąc prościej nie można stworzyć domyślnego konstruktora w strukturze.
struct Punkt3D
{
public Punkt3D(double x, double y, double z)
{
X = x; Y = y; Z = z;
}
public double X;
public double Y;
public double Z;
}
Kompilator zawsze za ciebie go tworzy. W klasie, jeśli nie napiszesz domyślnego konstruktora kompilator go stworzy, a konstruktor wypełni wszystkie pola w klasie domyślnymi wartościami (int =0,bool = false).
Dla domyślnego konstruktora, którego nie możemy stworzyć, wartości stworzone przez niego w strukturze zawsze będą domyślne.
Ważna uwaga co do konstruktorów z parametrami. Dla struktur muszą one uzupełniać wszystkie pola jakimiś wartościami. W tym wypadku wartość “z” nie ma żadnej przypisanej wartości i uzyskałem błąd kompilacji.
Dla dużej ilości pól ten problem może być rozwiązany za pomocą dziedziczenia konstruktorów. Dziedzicząc po konstruktorze domyślnym wartość “Z” będzie ustawiana według niego, czyli na wartość domyślną dla int zero.
public Punkt3D(double x,double y) :this()
{
X = x; Y = y;
}
Wybacz , że nagle mówię o dziedziczeniu i o słowie kluczowym this , o którym jeszcze nic nie wspomniałem, ale lepiej zapamiętać taką sztuczkę.
W strukturze nie możesz inicjować domyślnych wartości dla pól przeciwieństwie do klas.
Oto tabelka podsumowująca różnicę pomiędzy klasą a strukturą.
Pytanie | Struktura | Klasa |
Typ wartościowy czy referencyjny? | Typ wartościowy | Typ referencyjny |
Jej instancja żyje na stosie czy na stercie | Na stosie i są wartościami. | Na stercie i są nazywane obiektami. |
Można w niej napisać domyślny konstruktor | Nie | Tak |
Kiedy napiszesz swój konstruktor, czy kompilator wciąż stworzy swój domyślny. | Tak | Nie |
Jeśli nie zainicjujesz pól w swoim własnym konstruktorze, czy kompilator automatycznie za ciebie je zainicjuje. | Nie | Tak |
Czy możesz przypisać wartości do pól w momencie deklaracji? | Nie | Tak |
Użycie struktury nie powinno być dla ciebie niczym nowym.
Punkt3D p1 = new Punkt3D(1, 2, 3);
Możesz się zastanawiać, dlaczego używamy słowa kluczowego new. Słowo kluczowe new wywołuje konstruktor. Konstruktor, który wypełnia pola. Jednak struktura to typ wartościowy więc powinien dać się używać również bez słowa kluczowego new.
Punkt3D p2;
p2.X = 2;
p2.Y = 3;
p2.Z = 5;
Można używać struktur bez słowa kluczowego new, ale nie jest to zalecane i prowadzi do niepotrzebnego zamieszania. Zalet z takiego rozwiązania prawie nie ma. Trzeba tylko przypisać do wszystkich pól w strukturze wartości, tak jakby zrobił to konstruktor , aby używać jej w pełni poprawnie.
Struktura też może być rozszerzona o typ nullable , aby dać jej możliwość przechowywania braku wartości.
Punkt3D? p1 = null;
Jak działa struktura na stosie. Zobrazowanie
Co się dzieje, gdy napiszę strukturę bez użycia jej konstruktora.
Jak widzisz wartości nie są zainicjowane. Jest to możliwe, ale niektóre funkcje struktury mogą wywołać błąd, ponieważ jej pola nie mają przypisanych wartości.
Oto co się dzieje, gdy użyjemy słowa kluczowego new i wywołamy domyślny konstruktor dla struktury.
Wszystkie pola w strukturze mają teraz domyślne wartości. Myślę ,że wiesz co się wydarzy gdy uruchomię mój konstruktor.
To wszystko. Nie bardzo, czego jeszcze brakuje?
Domyślnie struktury nie mają wbudowanych zachowań dla poszczególnych operatorów. Czyli na chwilę obecną nie mamy możliwości dodawania, odejmowania czy porównywania własnych struktur.
Ma to sens w końcu co byśmy otrzymali dodając dwa punkt w przestrzeni 3D. Powinniśmy może dodawać do punktów 3D tylko odpowiednie wektory. Jednym słowem domyślne wbudowane zachowania jak dodanie jednej wartości do drugiej zrobiłoby tylko nieodpowiednie zamieszanie.
Oczywiście możesz stworzyć swoją implementację dla poszczególnych operacji ,ale o tym kiedy indziej.