Wykład 4

Transkrypt

Wykład 4
PROE – wykład 4
pozostałe operatory, forward declaration, dziedziczenie
dr inż. Jacek Naruniec
Dyrektywy preprocesora


Preprocesor przetwarza plik przed kompilacją.
Podmienia/interpretuje dyrektywy/bloki poprzedzone znakiem #.
#define ZMIENNA
#ifdef ZMIENNA
Cośtam cośtam
… ten kod preprocesor włączy w kod
#else
Coś innego coś innego
…tego kodu preprocesor nie włączy w kod
#endif
wynik działania preprocesora
Cośtam cośtam
… ten kod preprocesor włączy w kod
Dyrektywy preprocesora


Stała _DEBUG jest automatycznie definiowana przy wyborze trybu
kompilacji „DEBUG” w Visual Studio.
W większości środowisk definicje preprocesora globalne dla całego
projektu wpisujemy w opcjach projektu pod pojęciem „preprocesor
definitions” lub podobnym.
Terminy kolokwium



7 kwietnia – I kolokwium ( w przyszłym tygodniu
dokończenie materiału i powtórka przed kolokwium)
2 czerwca – II kolokwium
9 czerwca – kolokwium poprawkowe
Operatory post i preinkrementacji.

Jak rozróżnić operatory obiekt++ i ++obiekt?
Operatory w klasie i poza klasą

Operatory jako metody w klasie:
Realizuje operacje (Pulsometr p1, p2):
 p1 == p2
 p1 == 2
 ale nie 2==p1
Pulsometr.h
Pulsometr.cpp
Operatory w klasie i poza klasą

Operatory zadeklarowane poza klasą (nie ma dostępuj do this):
Realizuje operacje (Pulsometr p1, p2):
 p1 == p2
 p1 == 2
 2==p1
Forward declaration

Co będzie jeśli klasa Punkt będzie korzystała z klasy
Wektor a klasa Wektor z klasy Punkt?
Forward declaration

Jeśli w pliku .cpp zostanie dołączony Wektor.h, to w
drugiej linijce (po #pragma once) mamy:



include „Punkt.h” -> Punkt.h będzie miał w drugiej linijce
#include „Wektor.h”
Kompilator nie wejdzie w Wektor.h, bo na początku jest
#pragma once które wymusza fakt, że nie dołączymy tego
pliku 2 razy. W rezultacie nagłówek ten będzie pominięty,
powrócimy do dalszej kompilacji Punkt.h
W przesunOWektor korzysta z klasy Wektor która jeszcze
nigdzie nie została zadeklarowana i zgłasza błąd.
Forward declaration



W pliku Wektor.cpp mamy: #include „Wektor.h”
Kompilujemy plik Wektor.cpp
W bloczkach kolejność, w której będzie zaglądał do
plików kompilator:
1
3
4
6
7
8 – błąd, bo
nigdy
nie doszliśmy do
definicji Wektor
5 – dalej nie
pójdzie, bo pragma
2 once!
Forward declaration

Zamiast dołączać Wektor.h i Punkt.h powiemy tylko
kompilatorowi, że będzie coś takiego jak Punkt i jak
Wektor (bez żadnych szczegółów):
Forward declaration
Dziedziczenie



Jedna z najważniejszych cech programowania
obiektowego!
Jest to uszczegółowienie klasy.
Uszczegóławiając klasę dodajemy jedynie te
elementy, które pojawiają się w nowym obiekcie.
Dziedziczenie

Klasa OknoProgramu (różnice także w uruchomieniu – albo
nieblokujące albo blokujące)
Okno programu
Okno dialogowe
Okno edycyjne
Rozszerzone
okno dialogowe
Okno hasła
Dziedziczenie



Okno dialogowe nie jest częścią okna programu –
jest jego uszczegółowieniem
Podobnie okno hasła nie jest częścią okna
edycyjnego
Itd…
Dziedziczenie

Okno programu stanowi „bazę” dla pozostałych okien (w
rzeczywistości będzie zawierać więcej elementów)
Te metody będą dotyczyły
każdego okna
To są zmienne, które definiują
okno każdego typu (także
dialogowe, hasła, edycyjne)
Dziedziczenie

Okno dialogowe rozszerza działanie okna o przyciski
(powinna być jeszcze zawartość itp.):
To znaczy, że
dziedziczy po klasie
OknoProgramu
Identycznie zdefiniowana
metoda jak w OknoProgramu
Dziedziczenie

Rozszerzone okno dialogowe rozszerza okno
dialogowe o możliwość ustawienia koloru tła.
Nie ma metody pokazOkno() ! – ale
będzie ona dostępna dla tej klasy (z
klasy bazowej)
Dziedziczenie

Okno edycyjne rozszerza działanie OknaProgramu o
pole edycyjne (ale nie zawiera żadnych przycisków)
Dziedziczenie

OknoHasla jest uszczegółowieniem okna
edycyjnego – kropki zamiast liter i dodatkowy
przycisk OK.
Kod aby hasło nie występowało
jawnie w pamięci.
Dziedziczenie

Klasy asortymentu sklepu internetowego:
Towar
Komputer
LCD
Telewizor
Plazma
Komórkowy
Telefon
Stacjonarny
Dziedziczenie

Klasa Detektor
Detektor
Detektor ruchu
Detektor twarzy
Detektor twarzy
Haar
Detektor twarzy
LBP
Dziedziczenie

Obiekt Detektor (bardzo ogólny)
?
Dziedziczenie

Detektor ruchu dziedziczy po detektorze i daje wyniki
w postaci maski pikseli które się poruszyły
obraz
maska ruchu
Dziedziczenie

Detektor twarzy dziedziczy po detektorze i daje wyniki w postaci tablicy
obiektów typu Twarz. Nie implementuje żadnej konkretnej metody, jest ciągle
ogólny, ale wiemy jaki wynik chcemy otrzymać.
wykryte twarze
obraz
Dziedziczenie

DetektorTwarzyHaar rozszerza działanie detektora twarzy,
implementując konkretną metodę detekcji (opartą na cechach
Haara)
Dziedziczenie

DetektorTwarzyLBP rozszerza działanie detektora twarzy,
implementując konkretną metodę detekcji (cechy Local Binary
Patterns - LBP)
Dziedziczenie

Implementacja klasy Detektor:
Dziedziczenie

Najprostsze wykorzystanie obiektu bazowego:

Po co nam taki obiekt?? – przecież on w zasadzie nic nie robi i
nie ma żadnej sensownej funkcjonalności. My przecież
chcemy mieć narzędzie do detekcji
Dziedziczenie

Implementacja klasy DetektorTwarzy, zaczniemy od
konstruktora:
Te zmienne dotyczą
wszystkich detektorów więc
chcemy też z nich
korzystać!
Rozwiązaniem jest trzeci tryb dostępu (przy private i public) – tryb chroniony, czyli
protected
Dziedziczenie

Sekcja protected oznacza, że z metod i zmiennych
mogą korzystać klasy pochodne, ale nie można
korzystać z nich z zewnątrz:
Dziedziczenie

Przy dostępie do zmiennych protected:
tutaj nie ma problemu
Tu zgodnie z założeniem
nie można tego zrobić
Dziedziczenie

Od tego momentu wszystkie składowe klasy (czyli
zwykle większość, jeśli nie wszystkie) które chcemy
aby były dziedziczone umiejscawiamy w sekcji
protected.
Tu w sumie zbędne (bo „dalej” nie ma
dziedziczenia), ale nie zaszkodzi 
Dziedziczenie

Proste wykorzystanie obiektów:
Dziedziczenie

Najważniejsza cecha dziedziczenia – polimorfizm.
Dziedziczenie

Polimorfizm:
Słowo virtual określa, że funkcja zachowuje się „inteligentnie”,
tzn. wywołuje się funkcja odpowiadająca klasie stworzonego
obiektu a nie klasy wskaźnika.
Dziedziczenie

Polimorfizm

Przy virtual (funkcje wirtualne) uruchamiana jest
funkcja najbardziej odpowiadająca danej klasie.
Jest to jeden z najistotniejszych elementów
dziedziczenia.

Dziedziczenie

A co jeśli w DetektorTwarzyHaar nie ma
zdefiniowanej funkcji uruchom?

Uruchomi się najbliższa możliwa, czyli:
Detektor
virtual bool uruchom
DetektorTwarzy
bool uruchom
DetektorTwarzyHaar
uruchom()
Funkcja wirtualna, szukamy dalej
Funkcja wirtualna, szukamy dalej
Nie znaleziono, więc wywoła się
funkcja z klasy DetektorTwarzy
Dziedziczenie


Metody i klasy abstrakcyjne.
Metoda abstrakcyjna to funkcja, której nazwa i
parametry są zadeklarowane a jej definicja (ciało) już
nie.
Oznacza to, że funkcja jest
wirtualna ale nie jest
zdefiniowana w klasie Detektor
(ale jest zdefiniowana w klasach
pochodnych)
Dziedziczenie

Efekt posiadania funkcji wirtualnej:

Klasa która ma metody(choćby jedną) abstrakcyjne staje
się klasą abstrakcyjną, której obiektu nie da się
utworzyć.
Dziedziczenie

Mimo, że nie można utworzyć klasy Detektor, to
można utworzyć wskaźnik na obiekt klasy Detektor:
Dziedziczenie

Tak samo nie ma sensu definicja funkcji w klasie
DetektorTwarzy:
To też będzie metoda
i klasa abstrakcyjna.
Nie ma słowa virtual, bo wirtualność jest dziedziczona – jeśli funkcja była
wirtualna w klasie Detektor to będzie i tutaj.
Dziedziczenie

Nasz main obecnie:
Dziedziczenie

Analogicznie można tworzyć wskaźniki na
DetektorTwarzy:
Dziedziczenie

Konstruktory/desktruktory

Konstruktory uruchamiają się od klasy bazowej do klas
pochodnych, destruktory odwrotnie
W rezultacie, w tym przypadku, z trzech konstruktorów otrzymujemy
jeden obiekt.

Dziedziczenie


Każda klasa powinna dbać o własną „czystość
pamięci”.
Jeśli klasa DetektorTwarzy tworzy jakąś tablicę przez
new to i w tej klasie powinno być jej usunięcie (a nie
w bazowej ani innej!).:
Dziedziczenie

Usunięcie obiektu z wykorzystaniem polimorfizmu:
Brakuje dwóch destruktorów!
Dziedziczenie

Aby umożliwić usunięcie obiektu z wykorzystaniem
polimorfizmu, destruktor musi być wirtualny:
Dziedziczenie

Można także bezpośrednio odwoływać się do funkcji
klasy bazowej danego obiektu, np.:
Dziedziczenie

Co jeśli funkcja jest zdefiniowana w klasie
pochodnej, nie ma jej w klasie bazowej a my mamy
wskaźnik na klasę bazową (uffff. ;-))?
Detektor nie ma funkcji
zmienParametryHaar!
Dziedziczenie

Możemy rzutować wskaźnik Detektor na wskaźnik
klasy pochodnej, wtedy mamy dostęp do jej funkcji:
Dziedziczenie

Wirtualne funkcje:

Okno
programu

Okno
dialogowe
Okno
edycyjne
Rozszerzone
okno
dialogowe
Okno hasła
pokazOkno
wirtualny destruktor?
Dziedziczenie

Okna Windows (np. w MFC):



Akcje na oknach wywołują pewne funkcje.
Jeśli mamy swoją klasę okna możemy przedefiniować te
funkcje (bo są wirtualne).
Przykłady funkcji witualnych:




OnOk()
OnCancel()
OnClick(Button &b)
OnMove()
Dziedziczenie

Ćwiczenie:
Obiekt bazowy (OB)
void funkcja1()
virtual void funkcja2()
Obiekt pochodny 1 (OP1)
virtual void funkcja1()
Obiekt pochodny 3 (OP3)
void funkcja1()
Obiekt pochodny 2
(OP2)
void funkcja2()
Które funkcje się
uruchomią jeśli
mamy:
- Wskaźnik na
klasę OB.,
- Wskaźnik na
klasę OP1, OP2,
OP3
- Obiekt klasy OB
- Obiekt klasy OP1
- Obiekt klasy OP3
Za każdym razem
wywołujemy
funkcja1 i funkcja 2
Dziedziczenie

Które konstruktory/destruktory i w jakiej kolejności
się uruchomią?
Obiekt bazowy 1(OB1)
Obiekt pochodny 1 (OP1)
Obiekt bazowy 2(OB2)
Obiekt pochodny 2
(OP2)
Dziedziczenie


Możliwe jest także dziedziczenie wielokrotne (np.
Laptop dziedziczy po komputerze i urządzeniu).
Najważniejsze w dziedziczeniu jest:


Polimorfizm
Możliwość rozszerzania klas bazowych – oszczędność
kodu
Paradygmaty programowania obiektowego

Paradygmat (za Wikipedią) - zbiór pojęć i teorii
tworzących podstawy danej nauki.

Abstrakcja – dysponujemy abstrakcyjnymi obiektami,
które mają określone działanie – nie musimy wnikać w
sposób tego działania (tylko w część publiczną)
Hermetyzacja (inaczej enkapsulacja) – chronimy obiekt
aby nie został zmieniony w sposób nieprzewidziany
(sekcje prywatne, chronione)
Polimorfizm – zachowanie odpowiednie dla typu
stworzonego obiektu, wielopostaciowość – przeciążanie
funkcji
Dziedziczenie – możliwość rozszerzania istniejących
obiektów



Paradygmaty programowania obiektowego

Większość języków obiektowych je spełnia, ale nie
wszystkie, np. Python:


nie ma sekcji prywatnych, publicznych
zakłada, że użytkownik wie co robi i nie będzie psuł
nieprzewidzianych do modyfikacji elementów

Podobne dokumenty