Programowanie obiektowe

Transkrypt

Programowanie obiektowe
Programowanie obiektowe
Materiały przygotował:
mgr inż. Wojciech Frohmberg
Konstruktor
Konstruktor w językach zorientowanych obiektowo pełni podwójną rolę:
– przydziela pamięć na obiekt, zdefiniowany klasą
– inicjuje wartości zmiennych dając możliwość wykonania instrukcji inicjalizujących
Składnia deklaracji konstruktora (plik nagłówkowy):
//...
class EtykietaKlasy : public EtykietaKlasyNadrzednej {
public:
int pole;
//...
EtykietaKlasy();
//...
};
//...
Składnia definicji konstruktora (plik źródłowy):
#include "plik_nagłówkowy.h"
//...
EtykietaKlasy::EtykietaKlasy()
: pole(wartość),
//inicjalizacja wartości pól,
EtykietaKlasyNadrzednej() //jawne wywołanie konstruktorów
{
//instrukcje inicjalizujące
}
//...
Jawne wywołanie konstruktorów ma na celu określenie z którego spośród konstruktorów program powinien korzystać w przypadku gdy jest kilka przeciążeń konstruktorów z różnymi parametrami. W przypadku, gdy jawne wywołanie konstruktora nie jest podane kompilator skorzysta z domyślnego bezparametrowego konstruktora klasy nadrzędnej.
UWAGA!
W przypadku jednak gdy konstruktor domyślny nie istnieje, tj. gdy w klasie nadrzędnej został zdefiniowany konstruktor parametryczny a nie został zdefiniowany konstruktor bezparametrowy kompilator będzie wymagał jawnego wywołania konstruktora klasy nadrzędnej. Podobnie w przypadku gdy bezparametrowy konstruktor klasy nadrzędnej jest określony jako private.
Zadanie 1. Utwórz hierarchię klas:
Car
+doorsCount: int
+producerName: string
Porsche
+vintage: int
+mileage: int
a) Zainicjuj wartości pól w konstruktorze klasy Car jak i Porsche.
b) Zweryfikuj czy możesz inicjalizować wartości pól klasy Car w klasie Porsche, zarówno w przypadku gdy klasa Car inicjalizuje pola jak i przypadku przeciwnym. c) Sprawdź czy można inicjować pola wartościami pochodzącymi z parametru konstruktora
d) Sprawdź czy można inicjować pola polami klasy nadrzędnej oraz polami klasy bieżącej
e) Korzystając ze zdobytej wiedzy z podpunktu d) zaproponuj metodę badania kolejności inicjalizacji pól (od lewej do prawej, czy od prawej do lewej) następnie ją przetestuj
Jednoargumentowy konstruktor konwersji
Specyficznym rodzajem konstruktora jest konstruktor jednoargumentowy. Szczególną cechą takiego konstruktora jest to w jakich momentach jest wywoływany. Jest bowiem wykorzystywany do konwersji z typu argumentu konstruktora na typ klasy, która taki konstruktor posiada. Przykładowo jeśli zdefiniujemy jednoargumentowy konstruktor z parametrem typu int będziemy mogli:
a) podstawiać za instancje danej klasy wartości typu int (mając na względzie że w tym momencie tworzymy nowy obiekt tego typu)
b) przekazywać wartości typu int do metod/funkcji które przyjmują jako parametr typ naszej klasy.
Szczególnym przykładem jednoargumentowego konstruktora konwersji jest konstruktor kopiowania. W tym wypadku typ argumentu naszego konstruktora powinien być taki jak typ naszej klasy. Konstruktor ten bywa przydatny gdy płytkie kopiowanie obiektu domyślnie używane przez kompilator nie jest wystarczające.
Zadanie 2.
Utwórz klasę CiagZnakow z niezbędnymi prywatnymi polami. Zaimplementuj jednoargumentowy konstruktor który jako argument przyjmuje: const char *, int, char, float, double, bool. Spraw by każdy z tych konstruktorów powodował zapamiętanie w klasie ciągu znaków odpowiadającej podanemu parametrowi. Dla tak zdefiniowanej klasy zaimplementuj metodę wypisz(), wypisującą dany ciąg znaków na ekran. Przetestuj czy wszystko działa jak należy.
Zadanie 3.
Usuń konstruktor z argumentem typu const char * z klasy CiagZnakow. Zaimplementuj za to konstruktor który przyjmuje argument typu string (poznany na poprzednich zajęciach znajdujący się w bibliotecę STL <string>). Zwróć uwagę że klasa string posiada zaimplementowany konstruktor z argumentem typu const char *. Zweryfikuj czy nadal możesz korzystać z podstawiania wartości typu const char * do obiektów typu CiagZnakow.
Zadanie 4.
Utwórz konstruktor kopiowania dla klasy CiagZnakow. Przetestuj podstawianie obiektów typu CiagZnakow pod instancje obiektów tegoż samego typu.
Dostęp do zmiennej przez adres, referencję i przez wartość
Dostęp do obiektu celem w wypadku gdy chcemy nadpisać jego wartość możemy zapewnić w dwojaki sposób. Poprzez adres na miejsce w pamięci w którym znajduje się ten obiekt (operator &) lub poprzez referencję (etykieta obiektu). Mechanizmy te są o tyle przydatne że pozwalają przekazać wartości przechowywane przez instancję obiektu bez ich kopiowania (poprzez np. konstruktor kopiowania) do funkcji/metody, w której chcemy mieć do nich dostęp. Przykład parametru funkcji będącego wskaźnikiem do obiektu:
void wypisz(CiagZnakow *ciagZnakow) { … }
Przykład parametru funkcji będącego referencją do obiektu:
void wypisz(CiagZnakow &ciagZnakow) { … }
W pierwszym przypadku do obiektu ciag znaków musimy odwoływać się przez adres tzn. gdy na przykład chcemy odwołać się do metody/pola zawartej w obiekcie musimy skorzystać z operatora ­> np.:
ciagZnakow­>wypisz();
natomiast w przykadku gdy chcemy coś zapisać do obiektu musimy skorzystać z jawnego wyłuskania referencji spod adresu tj. operatora * np.:
(*ciagZnakow)="ciag który chcemy wpisać do obiektu do którego mamy wskaźnik";
Do obiektu będącego referencją odwołujemy się poprzez operator . w przypadku gdy chcemy odwoływać się do jego pól/metod oraz zwyczajnie przez etykietę gdy chcemy coś doń podstawić.
Zadanie 5. Zaimplementuj funkcje wypisz z przykładu. Przeciążenie operatorów
Język C++ pozwala na definiowanie akcji, które mają się wykonywać w przypadku użycia przez programistę operatora na wybranej przez użytkownika klasie. Akcje te mogą być definiowane statycznie poza klasą np. w danym namespace'ie jako funkcje, jako metody statyczne wewnątrz danej klasy dla której operator chcemy przeciążyć lub też jako dynamiczne metody obiektu. Lista operatorów które mogą zostać przeciążone:
+
~
++
+=
<<=
-
!
--=
>>=
*
,
<<
/=
[ ]
/
=
>>
%=
( )
%
<
==
^=
->
^
>
!=
&=
->*
&
<=
&&
|=
new
|
>=
||
*=
delete
Nie mogą zostać przeciążone operatory ::, ., .* oraz ?:.
Przeciążenia operatorów mogą zwracać dowolny typ (nawet void). Nie ma jednak możliwości zmiany kolejności wykonywania operatorów. W przypadku gdy operator ma być przeciążony przez statyczną funkcję bądź metodę dla danego typu TYP składnia deklaracji jest następująca:
typ_zwracany operator tutaj_znak_operatora (TYP etykieta [, TYP2 etykieta2]);
UWAGA!!!
Należy zwrócić uwagę, że powyższą deklarację należy poprzedzić słówkiem kluczowym static w przypadku gdy ma ona być statyczną metodą danej klasy. Deklaracja argumentu etykieta2 występuje tylko w przypadku operatorów binarnych.
W przypadku gdy operator ma być przeciążony przez dynamiczną metodę klasy pomija się pierwszy parametr operatora.
Dobrą praktyką jest zwracanie referencji do obiektu w przypadku przeciążania operatorów z grupy podstawiania i nawiasów kwadratowych.
Zadanie 6.
Dokonaj przeciążenia podstawowych operatorów dla rozsądnych dla ciągów znaków dla klasy CiagZnakow.
Zadanie 7.
Dokonaj przeciążenia operatora << dla klasy obiektu cout tak, by można było wypisywać na standardowe wyjście obiekty typu CiagZnakow. Zwróć uwagę jaki powinien być typ wartości zwracanej przez ten operator. Tematy projektów
1. Proste konsolowe środowisko do wykonywania obliczeń macierzowych.
Środowisko powinno mieć możliwość deklarowania zmiennych macierzowych, wektorowych i skalarnych. Powinno dawać możliwość mnożenia zmiennych przez siebie (z uwzględnieniem ograniczeń wynikających np. z wielkości macierzy) oraz zapisywania rezultatu takich operacji do zmiennych lub wypisywania ich na ekran. Można skorzystać do tego celu ze składni Matlaba, czy Octave'a – darmowej jego alternatywy jednak nie jest to obowiązkowe. Dodatkowo środowisko powinno zapewniać możliwość zapisywania wszystkich zmiennych aktualnie przechowywanych w pamięci programu do pliku oraz odczytywanie takiego zrzutu zmiennych z pliku.
2. Konsolowy „Mistrz klawiatury”
Program do nauki bezwzrokowego pisania na klawiaturze. Program powinien posiadać opcję kont użytkownika uwierzytelnianych logowaniem. Powinien dodatkowo przechowywać rozległe statystyki użytkownika, dające obraz nad czym użytkownik powinien popracować – szybkością wpisywania tekstu czy też poprawnością wstukiwanych literek. Program powinien posiadać wbudowaną bazę tekstów do nauki bezwzrokowego pisania na klawiaturze, ale również dawać możliwość poszerzania tej bazy o dodatkowe pliki tekstowe (z poziomu konsoli).
3. Konsolowy program „tajny kod”
Program do bezpiecznego przechowywania haseł użytkownika. Program powinien posiadać opcję kont użytkownika uwierzytelnianych logowaniem. Hasła użytkownika powinny być szyfrowane za pomocą hasła którym użytkownik loguje się do systemu. Po zalogowaniu użytkownik powinien mieć możliwość przeglądania słownika haseł poprzez podanie jakie hasło użytkownik chce podejrzeć np. show komputer_dom oraz zapisywania haseł w słowniku (z jednoczesnym bezpiecznym zapisaniem hasła w pliku tak by hasło było dostępne po wylogowaniu) np. store komputer_dom kwiatki. Zwróć uwagę że powinna być udostępniona wprowadzania spacji zarówno do hasła jak i do słowa pod którym hasło się kryje. Dodatkowo ma istnieć możliwość wypisywania wszystkich słów pod którymi kryją się hasła.
Proszę wybrać jeden z w/w projektów i realizować go w parach bądź też w pojedynkę. Na ocenę będzie wpływać czytelność kodu, poprawne wykorzystanie mechanizmów programowania obiektowego (takich jak przeciążenie operatorów, wyrzucanie i łapanie wyjątków itp.), wyczerpujące okomentowanie kodu jak i prezentacja programu przy prowadzącym. Wstępny termin oddania projektu to 11.11.11.

Podobne dokumenty