Pracownia specjalistyczna. Materiały przygotowali: mgr inż. Wojciech Frohmberg, mgr inż. Michał Kierzynka

Podobne dokumenty
Składnia C++ Programowanie Obiektowe Mateusz Cicheński

Dariusz Brzeziński. Politechnika Poznańska, Instytut Informatyki

Laboratorium 1 - Programowanie proceduralne i obiektowe

Wprowadzenie. Programowanie Obiektowe Mateusz Cicheński

1. Które składowe klasa posiada zawsze, niezależnie od tego czy je zdefiniujemy, czy nie?

Składnia C++ Programowanie Obiektowe Mateusz Cicheński

Obiekt klasy jest definiowany poprzez jej składniki. Składnikami są różne zmienne oraz funkcje. Składniki opisują rzeczywisty stan obiektu.

Informacje ogólne. Karol Trybulec p-programowanie.pl 1. 2 // cialo klasy. class osoba { string imie; string nazwisko; int wiek; int wzrost;

Operatory na rzecz typu TString

Programowanie w C++ Wykład 8. Katarzyna Grzelak. 15 kwietnia K.Grzelak (Wykład 8) Programowanie w C++ 1 / 33

public: // interfejs private: // implementacja // składowe klasy protected: // póki nie będziemy dziedziczyć, // to pole nas nie interesuje

IMIĘ i NAZWISKO: Pytania i (przykładowe) Odpowiedzi

Język C++ wykład VII. uzupełnienie notatek: dr Jerzy Białkowski. Programowanie C/C++ Język C++ wykład VII. dr Jarosław Mederski. Spis.

Programowanie w C++ Wykład 9. Katarzyna Grzelak. 14 maja K.Grzelak (Wykład 9) Programowanie w C++ 1 / 30

Programowanie obiektowe w języku C++ dr inż. Jarosław Forenc

Języki i techniki programowania Ćwiczenia 3 Dziedziczenie

Programowanie obiektowe, wykład nr 6. Klasy i obiekty

Podstawy Programowania Obiektowego

Kurs programowania. Wykład 2. Wojciech Macyna. 17 marca 2016

Rozdział 4 KLASY, OBIEKTY, METODY

1. Pierwszy program. Kompilator ignoruje komentarze; zadaniem komentarza jest bowiem wyjaśnienie programu człowiekowi.

Laboratorium nr 12. Temat: Struktury, klasy. Zakres laboratorium:

TEMAT : KLASY DZIEDZICZENIE

2.4 Dziedziczenie. 2.4 Dziedziczenie Przykłady programowania w C - kurs podstawowy

Materiały do zajęć VII

Do czego służą klasy?

Programowanie obiektowe

Pola i metody statyczne. Klasy zawierające pola i metody statyczne

Programowanie obiektowe

TEMAT : KLASY POLIMORFIZM

Programowanie obiektowe w języku

Make jest programem komputerowym automatyzującym proces kompilacji programów, na które składa się wiele zależnych od siebie plików.

Diagram klas UML jest statycznym diagramem, przedstawiającym strukturę aplikacji bądź systemu w paradygmacie programowania obiektowego.

Wykład 8: klasy cz. 4

Programowanie współbieżne Wykład 8 Podstawy programowania obiektowego. Iwona Kochaoska

PROE wykład 4 pozostałe operatory, forward declaration, dziedziczenie. dr inż. Jacek Naruniec

wykład IV uzupełnienie notatek: dr Jerzy Białkowski Programowanie C/C++ Język C, a C++. wykład IV dr Jarosław Mederski Spis Język C++ - wstęp

Informatyka I. Dziedziczenie. Nadpisanie metod. Klasy abstrakcyjne. Wskaźnik this. Metody i pola statyczne. dr inż. Andrzej Czerepicki

Kurs WWW. Paweł Rajba.

Programowanie w C++ Wykład 12. Katarzyna Grzelak. 28 maja K.Grzelak (Wykład 12) Programowanie w C++ 1 / 27

Wykład 5 Okna MDI i SDI, dziedziczenie

PARADYGMATY PROGRAMOWANIA Wykład 4

Podstawy języka C++ Maciej Trzebiński. Instytut Fizyki Jądrowej Polskiej Akademii Nauk. Praktyki studenckie na LHC IVedycja,2016r.

Informatyka I. Klasy i obiekty. Podstawy programowania obiektowego. dr inż. Andrzej Czerepicki. Politechnika Warszawska Wydział Transportu 2018

Podczas dziedziczenia obiekt klasy pochodnej może być wskazywany przez wskaźnik typu klasy bazowej.

KLASA UCZEN Uczen imię, nazwisko, średnia konstruktor konstruktor Ustaw Wyswietl Lepszy Promowany

Programowanie w C++ Wykład 11. Katarzyna Grzelak. 13 maja K.Grzelak (Wykład 11) Programowanie w C++ 1 / 30

Operator przypisania. Jest czym innym niż konstruktor kopiujący!

Programowanie w C++ Wykład 1. Katarzyna Grzelak. 26 luty K.Grzelak (Wykład 1) Programowanie w C++ 1 / 28

Enkapsulacja, dziedziczenie, polimorfizm

Podstawowe elementy proceduralne w C++ Program i wyjście. Zmienne i arytmetyka. Wskaźniki i tablice. Testy i pętle. Funkcje.

Aplikacje w środowisku Java

Polimorfizm. dr Jarosław Skaruz

Programowanie Obiektowe i C++

Podstawy programowania skrót z wykładów:

Programowanie obiektowe - 1.

Programowanie obiektowe. Materiały przygotował: mgr inż. Wojciech Frohmberg

Definicje klas i obiektów. Tomasz Borzyszkowski

Programowanie obiektowe Wykład 6. Dariusz Wardowski. dr Dariusz Wardowski, Katedra Analizy Nieliniowej, WMiI UŁ 1/14

Wstęp do programowania obiektowego. WYKŁAD 3 Dziedziczenie Pola i funkcje statyczne Funkcje zaprzyjaźnione, this

Programowanie obiektowe

KLASY cz.1. Dorota Pylak

Do czego służą klasy?

Przekazywanie argumentów wskaźniki

Programowanie w C++ Wykład 6. Katarzyna Grzelak. kwiecień K.Grzelak (Wykład 6) Programowanie w C++ 1 / 40

KLASA UCZEN Uczen imię, nazwisko, średnia konstruktor konstruktor Ustaw Wyswietl Lepszy Promowany

Mechanizm dziedziczenia

WPROWADZENIE. Programowanie Obiektowe Mateusz Cicheński

Wstęp do programowania

Programowanie Obiektowo Zorientowane w języku c++ Przestrzenie nazw

Programowanie komputerowe. Zajęcia 1

Dokumentacja do API Javy.

Zaawansowane programowanie w języku C++ Programowanie obiektowe

Programy użytkowe (utilities)

Wstęp do Programowania 2

PHP 5 język obiektowy

znajdowały się różne instrukcje) to tak naprawdę definicja funkcji main.

1. Wartość, jaką odczytuje się z obszaru przydzielonego obiektowi to: a) I - wartość b) definicja obiektu c) typ oboektu d) p - wartość

Programowanie obiektowe

Programowanie Proceduralne

Definiowanie własnych klas

Aplikacje w środowisku Java

Wykład 1. Program przedmiotu. Programowanie Obiektowe (język C++) Literatura. Program przedmiotu c.d.:

Automatyczne tworzenie operatora = Integer2& operator=(const Integer& prawy) {

Zaawansowane programowanie w języku C++ Klasy w C++

JAVA W SUPER EXPRESOWEJ PIGUŁCE

Wprowadzenie do języka Java

Programowanie obiektowe Wykład 7. Dariusz Wardowski. dr Dariusz Wardowski, Katedra Analizy Nieliniowej, WMiI UŁ 1/20

Wprowadzenie w dziedziczenie. Klasa D dziedziczy klasę B: Klasa B klasa bazowa (base class), klasa D klasa pochodna (derived class).

Język C++ Różnice między C a C++

Paostwowa Wyższa Szkoła Zawodowa w Płocku Dariusz Wardowski

Programowanie w Internecie. Java

Wprowadzenie do programowanie obiektowego w języku C++

Wstęp do programowania. Wykład 1

Obszar statyczny dane dostępne w dowolnym momencie podczas pracy programu (wprowadzone słowem kluczowym static),

.NET Klasy, obiekty. ciąg dalszy

Kurs programowania. Wstęp - wykład 0. Wojciech Macyna. 22 lutego 2016

Java. język programowania obiektowego. Programowanie w językach wysokiego poziomu. mgr inż. Anna Wawszczak

Programowanie w C++ Wykład 8. Katarzyna Grzelak. 7 maja K.Grzelak (Wykład 8) Programowanie w C++ 1 / 31

Transkrypt:

Pracownia specjalistyczna Materiały przygotowali: mgr inż. Wojciech Frohmberg, mgr inż. Michał Kierzynka

Obiektowość na przykładzie języka C++ Paradygmat funkcyjny Zorientowanie Na algorytmy Na dane Algorytm Funkcja Metoda Dostęp algorytmu do danych Typ danych Hermetyzacja Inicjalizacja wartości Skorzystanie z algorytmu Rozszerzanie algorytmu Pozostawianie otwartych fragmentów algorytmu Poprzez zmienne globalne lub parametry funkcji Struktura* lub w skrajnym przypadku zestaw zmiennych o typach prymitywnych (primitive data types) Brak gwarancji korzystania z typu danych wejściowych do algorytmu zgodnie z założeniem programisty Poprzez wartości domyślne Wywołanie funkcji Wywołanie funkcji wewnątrz nowej funkcji, choć nie zawsze daje zamierzony efekt Korzystanie ze wskaźników na funkcje Paradygmat obiektowy Preferowany dostęp poprzez własności (properties) obiektów Klasa Istnieją metody wymuszania poprawnego korzystania z typu Poprzez konstruktor Wywołanie metody, skorzystanie z przeciążonego operatora bądź użycie własności (property)** Korzystanie z mechanizmu dziedziczenia Korzystanie z mechanizmu abstrakcji... Tabela 1. Programowanie zorientowane funkcyjnie kontra programowanie obiektowe * W kompilatorach C++ struktury mają podobne możliwości jak klasy ** Przykładowo w C# skorzystanie z własności może powodować (i w ogólnym przypadku powoduje) wywołanie odpowiedniej metody get bądź set. Klasa vs struktura. Z punktu widzenia języka C++ jedyna różnica między strukturą a klasą tkwi tylko i wyłącznie w domyślnych specyfikatorach widoczności danych i dziedziczenia. Domyślnie elementy struktury są widziane przez świat zewnętrzny (mają specyfikator public: ) natomiast elementy klasy są widziane tylko przez nią samą (mają specyfikator private: ).

części opcjonalne części domyślne Składnia definicji struktury struct etykieta : [public/protected/private] etykieta_przodka { public: // pola i metody dostepne globalnie protected: // pola i metody dostepne tylko przez metody struktury oraz // struktur z niej dziedziczacych private: // pola i metody dostepne tylko przez metody struktury mozliwa_deklaracja_zmiennych; Składnia definicji klasy class etykieta : [specyfikator] etykieta_przodka { private: // pola i metody dostepne tylko przez metody klasy public: // pola i metody dostepne globalnie protected: // pola i metody dostepne tylko przez metody klasy oraz // klas z niej dziedziczacych mozliwa_deklaracja_zmiennych; Ograniczanie widoczności pól i metod przodka. public: protected: private: public public: protected: private: protected protected: protected: private: private private: private: private: Tabela 1. Widoczność pól i metod klasy nadrzędnej po zastosowaniu specyfikatora dziedziczenia Definicja pól. typ edykieta1, etykieta2, ; UWAGA! Standard ISO zabrania w definicji pola określać wartości domyślnej!

Definicja pól statycznych. static typ etykieta1, etykieta2, ; Powyższa uwaga dotyczy również pól statycznych. Do zdeklarowania wartości pola statycznego potrzebna jest deklaracja. Definicja metod. virtual typ etykieta(typ parametr1, typ parametr2, ) = 0; = 0 daje możliwość definiowania metod abstrakcyjnych. Nie może ono jednak wystąpić bez słowa kluczowego virtual. W drugą stronę to nie działa innymi słowy każda abstrakcyjna metoda jest również metodą wirtualną, ale nie każda metoda wirtualna jest metodą abstrakcyjną. Metody abstrakcyjne nie powinny posiadać zaimplementowanego ciała w typie, z którego się wywodzą. Późne wiązanie. Metody wirtualne będą mogły posiadać swoje odpowiedniki w klasach potomnych, które będą wywoływane w przypadku wywołania metody nawet gdy obiekt widziany jest jakby był swoją nadrzędną klasą. Własność tą nazywamy późnym wiązaniem. Przykład: #include <iostream> using namespace std; class A { public: virtual void foo() { cout << "A::foo()" << endl; ; class B : public A { virtual void foo() { cout << "B::foo()" << endl; ; int main() { A* a = new B(); a >foo(); // wypisze B::foo() Dla przykładu posłużyliśmy się definicją z jednoczesną deklaracją metod funkcji. W ogólności ten mechanizm jest niezalecany. Zaleca się oddzielenie definicji struktury/klasy i jej elementów od ich deklaracji. Definicje umieszcza się w plikach nagłówkowych, natomiast wszelkie deklaracje w plikach.cpp. Definicja metody statycznej. static typ etykieta(typ parametr1, typ parametr2, );

Elementy statyczne vs elementy niestatyczne. Różnica między elementami statycznymi i niestatycznymi danego typu mieści się w przynależności elementów do obiektów owego typu. Należy zwrócić uwagę, że obiektów typu może być dużo. Każdy z nich ma dostępną własną pamięć, a zatem zmiany wartości jego pól będą niewidoczne dla innych obiektów jego typu. W przypadku, gdy chcemy uwidocznić taką zmianę mamy do dyspozycji mechanizm pól statycznych. Pole statyczne ma przydzieloną pamięć do klasy a nie do obiektu. Pamięć tą przydzielamy przy deklaracji pola. Należy zwrócić uwagę, że pola statyczne należy dodatkowo zadeklarować, tym samym przydzielając pamięć na też pole. Deklaracja statycznych pól. typ etykieta_pn::etykieta_ks::etykieta_pola = wartosc_domyslna; gdzie etykieta_pn to etykieta przestrzeni nazw jeśli klasa w takowej się znajduje, a etykieta_ks to etykieta klasy bądź struktury. Deklaracja metod. typ etykieta_pn::etykieta_ks::etykieta_metody() { // Tutaj powinno znalezc sie cialo metody. // Mozliwe jest tu wykorzystanie zmiennej this, ktora // jest wskaznikiem na obiekt, na ktorym metoda zostala // wywolana. Przykladowo: this >pole_calkowitoliczbowe = 2; Deklaracja metod statycznych. typ etykieta_pn::etykieta_ks::etykieta_metody() { // Tutaj powinno znalezc sie cialo metody. // W przypadku metod statycznych nie mozna stosowac // zmiennej this, gdyz metoda nie musi byc wywolywana na // konkretnej instancji klasy (obiekcie). Możliwe wywołania metod. Zarówno metody statyczne jak i niestatyczne możemy wywoływać w podobny sposób: etykieta_instancji.etykieta_metody(parametr, parametr, ); lub też: etykieta_wskaznika >etykieta_metody(parametr, parametr, ); Należy jednak zwrócić uwagę, że istnieje alternatywny sposób wywołania metod statycznych: etykieta_pn::etykieta_ks::etykieta_metody(parametr, parametr, ); Jest to o ważne z punktu widzenia implementowania metod statycznych. Metod tych możemy używać wtedy i tylko wtedy, gdy nie chcemy dostawać się do pól

instancji obiektów. Należy jeszcze zwrócić uwagę że nie istnieje w większości języków programowania coś takiego jak wirtualne metody statyczne. Dlatego zastosowanie metod statycznych z punktu widzenia stricte obiektowego programowania jest bardzo wąskie i ogranicza się do paru przypadków. Np. gdy chcemy skorzystać z tzw. wzorca projektowego Singleton. Deklaracje vs definicje. Jak już wcześniej wspomniano dobrym zwyczajem jest oddzielenie definicje elementów struktury/klasy od ich deklaracji. Przykład zgodnego z tym zwyczajem oddzielenia nagłówków od deklaracji: Plik car.h : #ifndef _CAR_H_ #define _CAR_H_ 1 #include <string> #include "vehicle.h" using namespace std; class Car : public Vehicle { protected: string doorsstate; public: virtual void opendoors(); ; #endif /*_CAR_H_*/ Plik car.cpp : #include "car.h" void Car::openDoors() { this >doorsstate = "opened"; Należy zwrócić uwagę że plik car.cpp nie ma zdeklarowanej funkcji main. Takiego pliku nie możemy skompilować do pliku wykonywalnego a jedynie do biblioteki, którą następnie należy trzeba będzie dodać na etapie linkowania do pliku, który to posiada funkcję main i korzysta z biblioteki. Kompilowanie biblioteki. g++ c nazwa_pliku.cpp o nazwa_pliku_biblioteki.o W przypadku, gdy nie podamy nazwy pliku biblioteki domyślnie biblioteka dostanie nazwę pliku.cpp ale z rozszerzeniem.o.

ZADANIA Zad. 1. Utwórz plik main.cpp i dodaj w nim definicję struktury Car z polami: driver, passenger1, passenger2, passenger3 wszystkie typu string. Z poziomu funkcji main wczytaj wartości do utworzonej instancji obiektu struktury Car (skorzystaj z funkcji getline). Zad. 2. Stwórz tablicę 10 instancji obiektu typu Car. Również do nich wczytaj w/w pola. Jak najłatwiej poradzić z problemem wielokrotnego wczytywania zmiennych dla poszczególnych instancji? Znajdź i zaimplementuj najprostsze rozwiązanie. Zad. 3. Zmień typ Car tak żeby był strukturą. Jakie za sobą konsekwencje to ciągnie? Zad. 4. Przenieś definicje klasy do pliku nagłówkowego car.h, który to też dodaj do bibliotek pliku main.cpp. Utwórz również plik car.cpp z deklaracją metody z zadania 2. Skompiluj plik car.cpp do biblioteki car.o, a następnie zlinkuj z plikiem main.cpp następująco: g++ main.cpp car.o o main.o Zad. 5. Utwórz plik porsche.h i porsche.cpp. Utwórz klasę Porsche dziedziczącą z klasy Car dodając pole passenger4 i passenger5. Utwórz późne wiązanie do metody wczytującej dane klasy. Zmień nazwę metody wczytującej na read(). W pliku main.cpp ciało funkcji main utwórz analogicznie: int main() { Car* cars[10]; for (int i = 0; i < 10; i++) if (i % 2 == 0) cars[i] = new Car(); else cars[i] = new Porsche(); for (int i = 0; i < 10; i++) cars[i] >read(); UWAGA! Pamiętaj o skompilowaniu i dolinkowaniu biblioteki porsche.o.

Pliki Makefile. Jak łatwo zauważyć przy rosnącej liczbie bibliotek łatwo pogubić się w tym co należy przekompilować po zmianie jakiegoś pliku źródłowego bądź nagłówkowego. Powiązania te dalej będziemy nazywać zależnościami. Na pierwszy rzut oka wydawać by się mogło że warto w tym momencie przekompilować wszystkie biblioteki. W rzeczywistych rozwiązaniach kompilowane programy mogą okazać się zbyt duże do tego by przy nawet drobnej zmianie kompilować je od początku (w przypadku dużej aplikacji może to trwać nawet godzinę, a w przypadku całego Windowsa proces ten trwa podobno nawet ponad dobę!). Zależności możemy rozumieć jako graf skierowany z wierzchołkami w plikach i potrzebie przekompilowania jako łuku wychodzącego z pliku, którego modyfikacja musi ciągnąć za sobą zmianę pliku, do którego łuk wchodzi. Przykład grafu zależności: planet.cpp planet.h earth.cpp earth.h mars.cpp mars.h main.cpp main.h planet.o earth.o mars.o main.o planetarium W przypadku zmiany dokonanej w pliku earth.cpp przekompilowaniy zostanie plik earth.o zmieniony plik planetarium: planet.cpp planet.h earth.cpp earth.h mars.cpp mars.h main.cpp main.h planet.o earth.o mars.o main.o planetarium

Dla tego grafu najgorszym przypadkiem jest jednak gdy zmieniony zostanie plik planet.h, gdyż wszystkie pliki cpp include'ują go (bezpośrednio lub też pośrednio include'ując plik który go include'uje). planet.cpp planet.h earth.cpp earth.h mars.cpp mars.h main.cpp main.h planet.o earth.o mars.o main.o planetarium W większości realnych przypadków nie będzie jednak takiej sytuacji i tylko część plików.cpp będzie include'owała plik nagłówkowy. Składnia plików Makefile. Jak już wspomniano wcześniej pliki Makefile służą zautomatyzowaniu procesu kompilacji. Żeby jednak plik Makefile działał poprawnie należy wszystkie zależności kompilacji przepisać na język tychże plików. W ogólności plik Makefile składa się z warunków i reguł wykonania: etykieta_wymagania: etykieta_zaleznosci etykieta_zalezności reguła wykonania Należy zwrócić uwagę że przed regułą wykonania należy (w nowej linii) umieścić znak tabulacji. Dla przykładu plik Makefile programu planetarium mógłby wyglądać następująco: all: planetarium planetarium: planet.o earth.o mars.o main.o g++ planet.o earth.o mars.o main.o o planetarium planet.o: planet.cpp planet.h g++ c planet.cpp o planet.o earth.o: earth.cpp earth.h planet.h g++ c earth.cpp o earth.o mars.o: mars.cpp mars.h planet.h g++ c mars.cpp o mars.o main.o: g++ c main.cpp o main.o clean: rm f *.o planetarium

UWAGA! Dla poprawnie podanych zależności program make automatycznie wykrywa, które pliki zależności zostały zmienione i ustala ścieżkę kompilacji. Użycie pliku Makefile. W przypadku, gdy plik będzie miał jedną ze standardowych nazw (Makefile, makefile) zostanie automatycznie rozpoznany w bieżącej lokalizacji i pierwsza jego reguła zostanie potraktowana jako ta do wykonania. Wystarczy wtedy wpisać polecenie: make W przypadku gdy nazwiemy plik inaczej lub mamy kilka plików Makefile należy podać programowi make który plik ma wczytać: make f Makefile10 W przypadku gdy chcemy wywołać konkretną regułę pliku Makefile wystarczy podać etykietę reguły. Przykładowo: make clean lub make f Makefile clean Będzie starało się wykonać regułę oznaczoną etykietą clean w pliku Makefile. ZADANIA Zad. 1. Utwórz plik Makefile do zadania 5 z poprzedniej części skryptu. Usuń wszystkie pliki *.o i wykonaj komendę make. Zad. 2. Utwórz skrypt bashowy configure który utworzy plik Makefile dla dowolnej liczby plików cpp w bieżącym katalogu i utworzy program podany jako zmienna zdefiniowana na początku pliku configure. Np.: #!/bin/bash prog=planetarium Skorzystaj do tego celu z przełącznika MM kompilatora g++, podającego informacje na temat zależności konkretnego pliku cpp (patrz manual).