23
Programowanie obiektowe III rok EiT dr inż. Jerzy Kotowski Wykład X

Programowanie obiektowe III rok EiT

  • Upload
    kirk

  • View
    44

  • Download
    1

Embed Size (px)

DESCRIPTION

Programowanie obiektowe III rok EiT. dr inż. Jerzy Kotowski Wykład X. Program wykładu. Język C++ Klasy, c.d. Wskaźnik this Klasy z konstruktorem i destruktorem Przykład problemu Podstawy języka JAVA Klasówka. Literatura. - PowerPoint PPT Presentation

Citation preview

Page 1: Programowanie obiektowe III rok EiT

Programowanie obiektoweIII rok EiT

dr inż. Jerzy KotowskiWykład X

Page 2: Programowanie obiektowe III rok EiT

Program wykładu

• Język C++– Klasy, c.d.

•Wskaźnik this•Klasy z konstruktorem i destruktorem

• Przykład problemu• Podstawy języka JAVA

•Klasówka

Page 3: Programowanie obiektowe III rok EiT

Literatura

• C++ for C programmers, Ira Pohl, The Benjamin/Cummings Publishing Company, Inc.

• Symfonia C++, Jerzy Grębosz, Oficyna Kallimach, Kraków 1999

Page 4: Programowanie obiektowe III rok EiT

Wskaźnik this

• Słowo kluczowe this oznacza niejawnie deklarowany self-referential poiner.

• Jednym z obszarów wykorzystania this jest tworzenie konstrukorów i destruktorów zawierających wprowadzane przez programistę funkcje do alokacji pamięci

• Używanie wskaźnika this może spowodować wzrost efektywności programu

• Przykład użycia:

sztuka dla sztuki

class X{ char c;public: void init(char b) {c=b;} char valc() {return(this->c);} char val() {return c;}};

• Wygoda: return *this;

• Typ wskaźnika: X const *

• To znaczy: this pokazuje na obiekty klasy X ale nie wolno nim poruszać. Jest to stały wskaźnik.

Page 5: Programowanie obiektowe III rok EiT

Konstruktory i destruktory - start• Aby klasa, czyli typ użytkownika przypominała typy wbudowane (J.

Grębosz) wymyślono:– Konstruktor i destruktor,– Funkcje składowe przeładowujące operatory,– Operatory konwersji.

• Konstruktor jest to member function, której nazwa jest identyczna z nazwa klasy. Tworzy on obiekty swojej klasy. Ten proces może uruchamiać procedury inicjalizacji data members i alokacji pamięci z wykorzystaniem operatora new.

• Destruktor jest to member function, której nazwa jest identyczna z nazwą klasy z poprzedzającym ją znakiem tilde (~). Zwykle jego funkcja polega na zniszczeniu obiektu swojej klasy, najczęściej poprzez wykorzystanie operatora delete.

• Konstruktor może być przeciążany a destruktor nie.• Konstruktor i destruktor nie mogą nic zwracać. Nawet nie mogą

zwracać void.• Konstruktory i destruktory mogą zawierać słowo return ale tylko w

składni return;

Page 6: Programowanie obiektowe III rok EiT

Własności konstruktora

• Konstruktor może być wywoływany do tworzenia obiektów typu const i volatile ale sam nie może być funkcją takiego typu.

• Konstruktor nie może być typu static.• Konstruktor nie może być typu virtual.• Nie można posłużyć się adresem konstruktora.• Zmienna typu klasa z konstruktorem nie może członkiem unii.

Zgoda może bowiem doprowadzić do walki pomiędzy konstruktorami.

• Konstruktor domniemany to taki, który można wywołać bez żadnego argumentu. Konstruktor domniemany jest tylko jeden.

• Konstruktor ze wszystkimi argumentami domniemanymi jest konstruktorem domniemanym. Konstruktor domniemany pozwala na array declaration.

• Jeżeli klasa nie ma żadnego konstruktora to wtedy kompilator sam generuje automatyczny konstruktor domniemany.class Complex{ float Re,Im;public: Complex(float x=0, float y=0) { Re=x; Im=y;}}a,b(-1),c(0,1),z[10];

Page 7: Programowanie obiektowe III rok EiT

Lista inicjalizacyjna konstruktora• Lista inicjalizacyjna może pojawić się w definicji konstruktora.

Deklaracja pozostaje niezmieniona.• Lista inicjalizacyjna specyfikuje jak zainicjować niestatyczne

składniki klasy.• Przykład:

było

Complex(float x=0, float y=0) { Re=x; Im=y;}

może być

Complex(float x=0, float y=0): Re(x), Im(y){}

• Elementy składni: dwukropek i przecinek.• W przykładzie mamy do czynienia z definicją inline

konstruktora wewnątrz klasy.• Lista inicjalizacyjna przydaje się przy przekazywaniu

argumentów klasom bazowym przy dziedziczeniu

Page 8: Programowanie obiektowe III rok EiT

Konstruktor kopiujący .. \test0.sln

• Konstruktor typu type::type(type& x) nosi nazwę konstruktora kopiującego.

• Gwarancja nietykalności wzorca: type::type(const type& x)

• Konstruktor kopiujący może być wywołany w sposób jawny: type obiekt_nowy = type(obiekt_wzór);

• Konstruktor kopiujący jest wykorzystywany do kopiowania wartości typu type do innej jeżeli:– zmienna typu type jest inicjalizowana przez wartość typu type– wartość typu type jest przekazywana jako argument funkcji– wartość typu type jest zwracana przez funkcję.

• Jeżeli w klasie nie ma konstruktora kopiującego to wtedy, gdy zajdzie jedna z sytuacji przedstawionych powyżej, kompilator generuje automatyczny konstruktor kopiujący. Kopiuje on zgodnie z zasadą „składowa po składowej”.

• Może to być przyczyną niejednej tragedii.• konstruktor kopia.cpp

Page 9: Programowanie obiektowe III rok EiT

Przykład – nowa wersja klasy stackconst int max_len=1000;enum Boolean {False,True};

class stack { char s[max_len]; int top;public: void reset() { top = 0; } // definition void push(char c); // function prototype char pop() { return (s[top--]);} char pop(int n); // overloading, prototype char top_of() { return (s[top]); } Boolean empty() { return ((Boolean)(top == 0)); } Boolean empty(int n); // overloading, prototype Boolean full() { return ((Boolean)(top == max_len - 1 )); }};

enum Boolean {false,true};

class stack { char *s; int max_len; int top;public: stack(void) { s=new char[1000]; max_len=1000; top=0; } stack(int size) {s=new char[size]; max_len=size; top=0; } stack(int size, char *str); ~stack(void) { delete s; } void reset() { top = 0; } void push(char c); char pop() { return (s[top--]); } char pop(int n); char top_of() { return (s[top]); } Boolean empty() { return ((Boolean)(top == 0)); } Boolean empty(int n); Boolean full() {return((Boolean)(top == max_len - 1 )); }};

Page 10: Programowanie obiektowe III rok EiT

Nowa wersja klasy stack - różnice• Nie ma deklaracji const int max_len=1000; • Zamiast tego jest nowy data member int max_len;

• Nie ma pola char s[max_len]; • Zamiast tego jest char *s;• Klasa stack ma trzy konstruktory:

– pierwszy bez argumentów - jego działanie jest równoważne działaniu niejawnego konstruktora,

– drugi zakłada stos o rozmiarze określonym przez jego parametr,

– trzeci ma dwa argumenty - zakłada stos o rozmiarze określonym przez pierwszy i kopiuje na stos łańcuch przekazywany przez drugi argument bez znaku końca łańcucha - top jest ustawiony na ostatni element łańcucha.

• Klasa stack ma destruktor.• Interfejsy w obu wersjach pozostały identyczne

Page 11: Programowanie obiektowe III rok EiT

Klasa String z dynamiczną alokacją pamięci .. \test0.sln

• String dynamiczny.cpp

• Różnice:– Nie ma pola const int max_len=255;– Nie ma pola char s[max_len]; jest pole char *s;– Pojawiły się cztery konstruktory.

const int max_len=255;class String{ char s[max_len]; // dwa skladniki typu private int len; static Stan; // składowa statycznapublic: // cztery skladniki typu public void assign(char *st); int lenght() { return(len); } void print(); static void switch_stan(void);};

class String{char *s;int len;static Stan;

public:String(void);String(int n);String(char *p);String(String& str);~String() { delete s; }int lenght() { return(len); }void assign(char *str);void print();static void switch_stan(void);

};

Page 12: Programowanie obiektowe III rok EiT

Klasa String z dynamiczną alokacją pamięci – definicje konstruktorówString::String(void) { s=new char[81]; s[0]=0; // przerwanie łańcucha len=80; cout << "\nPracuje konstruktor domniemany:\n"; print();}

String::String(int n) { s=new char[n+1]; s[0]=0; // przerwanie łańcucha len=n; cout << "\nPracuje konstruktor z jednym argumentem:\n"; print();}

String::String(char *p) // WAŻNE{ len=(int)strlen(p); // rzutowanie s=new char[len+1]; strcpy(s,p); cout << "\nPracuje operator konwersji:\n"; print();}

String::String(String& str) { len=str.len; s=new char[len+1]; strcpy(s,str.s); cout << "\nPracuje konstruktor kopiujacy:\n"; print();}

Page 13: Programowanie obiektowe III rok EiT

Klasa vect z dynamiczną alokacją pamięci i kontrolą indeksu .. \test0.sln

• Program ilustruje sposób wykorzystania ADT do stworzenia tablicy elementów (jako klasy), w której będzie można kontrolować wykraczanie indeksów poza dopuszczalny przedział wartości.

class vect { int *p; int size;public:

int ub; // upper bound = size-1 vect() { size=10; p=new int[size]; ub=size-1; } vect(int n); // konstruktor z argumentem ~vect() { delete p; } int& element (int i);};int& vect::element(int i){ if(i<0||i>ub) { cerr << "Illegal vector indeks " << i << "\n"; exit(1);} return(p[i]);} // vect.cpp

Page 14: Programowanie obiektowe III rok EiT

Klasa vect z dynamiczną alokacją pamięci i kontrolą indeksu • Dwa pola typu private: wskaźnik do pola roboczego int *p oraz

jego rozmiar int size. • W obszarze public jest data member int ub;• Klasa ma dwa konstruktory:

– pierwszy bez argumentów deklarujący tablicę 10 elementową– drugi z jednym argumentem int n zakładający tablicę n-elementową.

• Dostęp do elementów tablicy jest poprzez funkcję element. Najciekawszy element programu.Funkcja jest self indexing - sprawdza, czy indeks nie jest spoza zakresu.

• Funkcja zwraca referencję do i-tego elementu tablicy, to znaczy udostępnia ten element. Zwracana wartość jest zatem lvalue i może być wykorzystywana jako lewy operand operatora podstawiania.

• Jest to technika stosowana w C++ jako wygodny mechanizm przy działaniach na bardziej skomplikowanych typach obiektowych.

• Można napisać: vect vv(8), uu[5];vv.element(2)=uu[3].element(8);

• Lepiej by było tak: vv[2]=uu[3][8]; to kiedyś będzie

Page 15: Programowanie obiektowe III rok EiT

Klasa multi_v

• Deklarujemy klasę multi_v do przechowywania wieku, wagi i wzrostu grupy osób.

• Klasa zawiera trzy obiekty typu vect jako swoje składowe.• Klasa ma wyłącznie elementy typu public. • Konstruktor klasy multi_v jest konstruktorem z parametrem. • Konstruktor ten ma puste wnętrze nie licząc listy

inicjalizacyjnej, na której są wywołania konstruktora obiektu typu vect. Konstruktor klasy vect jest wywoływany trzy razy z parametrem i i tworzy trzy obiekty a(i),b(i),c(i).

• W starszych kompilatorach kolejność zakładania obiektów była nieokreślona. W nowszych kompilatorach kolejność jest zgodna z listą inicjalizacyjną - od lewej do prawej.

class multi_v {public: vect a,b,c; multi_v(int i):a(i),b(i),c(i) {}};

Page 16: Programowanie obiektowe III rok EiT

Klasa vect i multi_v – kod klienta• W segmencie main zakładamy obiekt a_w_h typu multi_v. Składa

się on z trzech 5-elementowych tablic obiektów typu vect. • Zwraca uwagę sposób użycia pola ub• Pętla for(int i=0;i<=a_w_h.a.ub;i++) chodzi 5 razy.• Na koniec wykonywane są destruktory w kolejności odwrotnej do

wywołań konstruktorów. Są to destruktory elementów klasy vect.

multi_v a_w_h(5); // age, weight and heightfor(int i=0;i<=a_w_h.a.ub;i++) { a_w_h.a.element(i)=21+i; a_w_h.b.element(i)=135+i; a_w_h.c.element(i)=62+i;}for(i=0;i<=a_w_h.a.ub;i++){ cout << a_w_h.a.element(i) << " years "; cout << a_w_h.b.element(i) << " pounds "; cout << a_w_h.c.element(i) << " inches\n";}

Page 17: Programowanie obiektowe III rok EiT

Klasa matrix – uogólnienie klasy vect

• Przykład jest uogólnieniem tablicy jednowymiarowej. • Istotnym novum jest postać konstruktora i destruktora.

class matrix { int **p; int s1,s2;public: int ub1,ub2; matrix(int d1,int d2); ~matrix(); int& element(int i,int j);};

matrix::matrix(int d1,int d2){ s1=d1; s2=d2; p=new int* [s1]; for(int i=0; i<s1;i++) p[i]=new int[s2]; ub1=s1-1; ub2=s2-1;}matrix::~matrix(){ for(int i=0;i<s1;i++) delete p[i]; delete p;}

• Konstruktor zakłada wpierw s1 elementową tablicę wskaźników do wierszy.

• Destruktor dealokuje pamięć w odwrotnej kolejności.

Page 18: Programowanie obiektowe III rok EiT

Klasa matrix – funkcja element i kod klienta .. \test0.sln

• Kod klienta jest izomorficzny do kodu z programu tablica1.cpp• tablica2.cpp

int& matrix::element(int i,int j){

return (p[i][j]);}

int sz1,sz2; cout << "\nEnter two sizes: "; cin >> sz1 >> sz2; matrix A(sz1,sz2); // Istotna różnica cout << "\nEnter " << sz1 << " by " << sz2 << " ints:\n"; int i,j; for(i=0;i<sz1;i++) for(j=0;j<sz2;j++) cin >> A.element(i,j); …

Page 19: Programowanie obiektowe III rok EiT

Lista jednokierunkowa - a singly linked list

• Lista jednokierunkowa jest bardzo użytecznym obiektem ADT. Jest to prototyp wielu struktur danych, które noszą nazwę self-referential structures. Obiekty tego typu charakteryzują się w szczególności tym, że jako jedno ze swoich pól mają wskaźnik do danej tego samego typu.

• Idea listy jednokierunkowej: Elementy dodajemy na początku listy i pierwszy element listy jest jedynym, który można bezpośrednio z listy skasować.

• Każdy element listy zawiera wszystkie niezbędne informacje, wynikające ze specyfiki programu oraz adres następnego elementu na liście.

• W przykładzie element znajdujący się na liście jest skromnym obiektem typu char.

struct listelem { // element listy char data; // informacje związane z elementem listelem *next; // adres do następnego elementu};

Page 20: Programowanie obiektowe III rok EiT

Klasa list

• Oba pola w strukturze listelem są typu public. Nie ma to specjalnie znaczenia ponieważ tajny jest adres do początku listy.

• Konstruktor inicjalizuje początek listy na NULL. Jest to klasyczne oznaczenie końca listy, lub faktu, że lista jest pusta.

• Destruktor wywołuje funkcję składową.• Funkcja first zwraca adres do początku listy. Elementy listy są

deklarowane jako struktury. Mamy zatem bezpośredni dostęp do ich pól.

class list { listelem *h; // wskaźnik do początkowego elementupublic: list() { h=0; } // konstruktor ~list() {release();}// destruktor void add(char c); // dodająca nowego element na początku void del(); // kasowanie elementu z początku listy listelem *first() { return h; }// adres do 1 elementu void pr_list(); // wyprowadzanie listy void release(); //zwalnianie pamięci};

Page 21: Programowanie obiektowe III rok EiT

Funkcje składowe klasy list

void list::add(char c) // dodawanie elementu na początku listy{ listelem *temp=new listelem; // przydzielanie pamięci temp->next=h; // dołączanie do listy temp->data=c; h=temp; // aktualizacja początku listy} // zarezerwowana pamięć nie jest zwalniana

void list::pr_list() // wydruk całej listy{ listelem *temp=h; // adres do początku listy nie zmieni się while(temp!=0) // badanie końca listy { cout << temp->data << " -> "; temp=temp->next; // przejście do następnego elementu } cout << "Koniec listy.\n";}

Page 22: Programowanie obiektowe III rok EiT

Funkcje składowe klasy list - c.d.

• Funkcja release zdejmuje bieliznę ze sznurka zostawiając sznurek. Sznurek zdejmuje destruktor.

• Destruktor o treści delete h; zniszczy tylko pierwszy element na liście i popsuje listę bo nie będziemy w stanie znaleźć następnego elementu.

void list::del() // kasowanie jednego elementu z listy{ listelem *temp=h; h=h->next; delete temp; // pamięć zajmowana przez pierwszy element} // na liscie wraca do stanu 'free store'

void list::release() // kasowanie wszystkich elementów z listy{ while(h!=0) del();}

Page 23: Programowanie obiektowe III rok EiT

Klasa list - kod klienta .. \test0.sln

• lista jednokierunkowa.cpp• Segment main zawiera inner

block. Po wyjściu z niego uruchamiany jest destruktor i lista jest automatycznie kasowana.

• Przykładowy wydruk:

list *p; // wskaźnik do listy { // początek wewnętrznego bloku

list w;w.add('A');w.add('B'); // dwa elementy na liściew.pr_list();w.del(); // kasujemy pierwszyw.pr_list();p=&w;p->pr_list(); // powinien byc identyczny wydruk

} // niejawne wywołanie destruktora p->pr_list(); // lista została wyczyszczona

B -> A -> Koniec listy.A -> Koniec listy.A -> Koniec listy.Koniec listy.