programowanie obiektowe 07, c c++, c#


Operatory

Przegląd zagadnień

0x08 graphic

Tematyka zajęć skupia się wokół pojęcia operatorów. Na początku przypomniane zostaną rodzaje stosowanych operatorów. Omówiona zostanie konwersja typów, która również może odbywać się w sposób jawny za pomocą operatorów konwersji.

W dalszej części zostaną omówione operatory stosowane w stosunku do obiektów. Przedstawione zostaną metody porównujące referencje obiektów, a następnie przeciążanie operatorów.

Wiadomości zostaną podsumowane, a wiedza przyswojona przez studentów skontrolowana za pomocą pytań sprawdzających. W pozostałym czasie studenci wykonają samodzielnie ćwiczenia laboratoryjne utrwalające zdobyte umiejętności.

Rodzaje operatorów (1)

0x08 graphic

Program manipulując danymi, wykonuje na nich operacje. Wartości liczbowe poddawane są działaniom arytmetycznym, łańcuchy znaków mogą być łączone. Wszystkie te operacje wykonywane są przy wykorzystaniu operatorów - symboli wskazujących na określoną funkcjonalność.

Operatory możemy wykorzystywać do wykonywania pojedynczej operacji na jednej zmiennej (operatory unarne) lub dwóch zmiennych (operatory binarne). Operatory wymienione na slajdzie powinny być już znane z praktyki i wcześniejszych kursów.

Znaczenie wybranych operatorów:

% - dzielenie całkowite,
&, |, ^ - bitowe AND, OR, XOR,
<<, >> - przesunięcia bitowe,
~ - bitowa negacja.

Rodzaje operatorów (2)

0x08 graphic

Operatorów używa się również do porównywania wartości zmiennych przy testowaniu warunków w instrukcjach warunkowych.

Operatorów arytmetycznych i bitowych możemy używać w skróconej formie, jeśli wynik działania chcemy przypisać do zmiennej po jednej ze stron działania.

W języku C#, podobnie jak w niektórych innych współczesnych języków, istnieje operator ternarny, który zwraca jedną z dwu podanych wartości w zależności od warunku.

Konwersja typów

0x08 graphic

Znane już powinno być pojęcie typu zmiennej. Między zmiennymi można przekazywać wartość nawet, gdy są innych typów, jednak dokonuje się wtedy konwersji.

Nie trzeba wykonywać żadnych specjalnych zabiegów, gdy chcemy przypisać wartość zmiennej zapisywanej w mniejszej liczbie bitów do zmiennej zapisanej w większej liczbie bitów. Nie są wtedy tracone żadne dane, dochodzi do konwersji niejawnej.

Na przykładzie widzimy zapis wartości zmiennej typu byte (8 bitów) do zmiennej typu int (32 bity), a następnie z int do long (64 bity) - mamy do czynienia z konwersją niejawną. Podobnie odbywa się to w przypadku przypisania wartości zmiennej typu float (32 bity) do zmiennej typu double (64 bity).

Jeśli przekazanie wartości wiąże się z ryzykiem utraty danych - wartość jest przekazywana do zmiennej zapisanej na mniejszej liczbie bitów - trzeba konwertować typ jawnie. Na przykładzie jawnie konwertowana jest wartość zmiennej typu long do typu int oraz typu double do float.

Konwersji jawnej dokonuje się za pomocą operatora konwersji - docelowego typu podanego w nawiasach okrągłych.

Porównywanie obiektów (1)

0x08 graphic

Korzystanie z operatorów w przypadku typów prostych jest w większości intuicyjne, jednak w jaki sposób można wykonywać działania na obiektach?

Zacząć należy od tego, że oznaczenie zmienna obiektowa (jak na przykładzie g, h, k, l) nie przechowuje samej instancji, lecz referencję wskazującą instancję. Przypisanie na pierwszym przykładzie nie skopiuje więc obiektu do drugiej zmiennej, tylko przekaże referencje. Mamy więc jedną instancję, do której można uzyskać dostęp przez dwie zmienne obiektowe.

Operator porównania, zastosowany do zmiennych obiektowych porównuje domyślnie tylko referencje do instancji, nie porównuje wartości składowych. Na pierwszym przykładzie porównujemy dwie zmienne przechowujące referencje do tej samej instancji. Porównanie tych zmiennych zwraca więc wartość logiczną prawda.

Drugi przykład to porównanie dwóch zmiennych przechowujących referencje do dwóch obiektów. Mimo, że obie instancje mają te same wartości zmiennych składowych (zostały stworzone przy użyciu konstruktora z tym samym parametrem), porównanie ich zwraca fałsz.

Takie domyślne zachowanie nie zawsze jest wygodne, dlatego można przeciążyć działanie operatora porównania, o czym za chwilę.

Porównywanie obiektów (2)

0x08 graphic

Poza operatorem porównania, w języku C# do dyspozycji są jeszcze trzy metody realizujące podobną funkcjonalność: statyczne metody EqualsReference() i Equals() oraz metoda wirtualna Equals().

Metoda EqualsReference() zawsze porównuje referencje do obiektów. Metoda statyczna Equals() sprawdza najpierw, czy porównywane obiekty są tych samych klas i czy jeden z nich nie jest wartością null, po czym wywołuje metodę Equals() obiektu.

Metodę wirtualną Equals() można przeciążyć w definicji klasy.

Na przykładzie przeciążamy metodę Equals() aby porównywała instancje klasy Student. Przyjmujemy, że jeśli dwa obiekty tej klasy mają równe wartości składowej NumerIndeksu, wówczas obiekty są równe.

Na slajdzie wyróżniona została deklaracja odpowiedniego przeciążenia metody.

Przeciążanie operatorów (1)

0x08 graphic

Jak wspomniano, można przeciążać również operatory. Zaczniemy od operatorów porównania - chcielibyśmy porównywać obiekty klasy Wektor przy użyciu operatora == tak, aby porównywane były poszczególne wymiary wektora zamiast domyślnego porównywania referencji.

W klasie Wektor należy zdefiniować metodę operatora porównania. Deklaracja jest wyróżniona na slajdzie. Istotne, aby metoda była publiczna i statyczna, a jeśli przeciążamy operator porównania, powinien zwracać wartość logiczną (bool).

W przypadku operatorów porównania, przeciążanie jest dostępne tylko parami: przeciążając operator == należy również przeciążyć operator !=, przeciążając operator relacji większości, należy też przeciążyć operator relacji mniejszości.

Przeciążanie operatorów (2)

0x08 graphic

Aby uprościć działania na obiektach danej klasy, można przeciążyć inne operatory. Na przykładzie przeciążamy operator dodawania w klasie Wektor. Metoda dodaje wszystkie składowe i zwraca nowy obiekt klasy wektor.

Podobnie, przeciążamy operator mnożenia przez wartość skalarną (zmienna typu double).

Podsumowanie

0x08 graphic

Na zajęciach omówione zostały rodzaje operatorów, wśród których można wyróżnić operatory unarne i binarne, arytmetyczne, bitowe i logiczne oraz operatory porównania i przypisania.

Przypisując wartości zmiennych jednego typu do innego, przeprowadzana jest konwersja. Jeśli konwersja wiąże się z ryzykiem utraty danych, należy wywołać ją w sposób jawny.

Domyślnie za pomocą operatora porównania i metod Equals(), EqualsReference() porównywane są referencje obiektów. Można jednak zmienić ich działanie, przeciążając metodę Equals() lub operator ==.

Przeciążać można także inne operatory porównania (parami) oraz operatory arytmetyczne i bitowe.

Pytania sprawdzające

0x08 graphic

Pytania sprawdzające wiedzę zdobytą podczas tych zajęć:

  1. Czym się różnią operatory binarne od unarnych?

  2. Kiedy stosujemy jawną konwersję typów?

  3. Jakie jest domyślne działanie operatora porównywania stosowanego do obiektów?

  4. Na czym polega przeciążanie operatorów?

  5. Jakie operatory można przeciążać?

Laboratorium

0x08 graphic

W pozostałym czasie studenci wykonują następujące zadania:

  1. Napisz klasę reprezentującą macierz oraz dokonaj przeciążenia odpowiednich operatorów działań na macierzach.

  2. Napisz klasę liczb złożonych (część rzeczywista i urojona) wraz z przeciążeniem odpowiednich operatorów

  3. Napisz klasę przedstawiającą ułamek w postaci licznika i mianownika wraz z przeciążeniem operatorów arytmetycznych i porównania.

L

L



Wyszukiwarka