1 / 23

Programowanie obiektowe III rok EiT

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.

kirk
Download Presentation

Programowanie obiektowe III rok EiT

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. Programowanie obiektoweIII rok EiT dr inż. Jerzy Kotowski Wykład X

  2. 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

  3. Literatura • C++ for C programmers, Ira Pohl, The Benjamin/Cummings Publishing Company, Inc. • Symfonia C++, Jerzy Grębosz, Oficyna Kallimach, Kraków 1999

  4. 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.

  5. 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;

  6. 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{ floatRe,Im; public: Complex(float x=0, float y=0) { Re=x; Im=y;} }a,b(-1),c(0,1),z[10];

  7. 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

  8. 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

  9. Przykład – nowa wersja klasy stack constint 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; } voidreset() { 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 )); } };

  10. Nowa wersja klasy stack - różnice • Nie ma deklaracji const int max_len=1000; • Zamiast tego jest nowy data memberint 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 - topjest ustawiony na ostatni element łańcucha. • Klasa stack ma destruktor. • Interfejsy w obu wersjach pozostały identyczne

  11. Klasa String z dynamiczną alokacją pamięci .. \test0.sln constint max_len=255; class String { char s[max_len]; // dwa skladniki typu private int len; static Stan; // składowa statyczna public: // cztery skladniki typu public void assign(char *st); int lenght() { return(len); } void print(); staticvoid 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(); staticvoid switch_stan(void); }; • 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.

  12. Klasa String z dynamiczną alokacją pamięci – definicje konstruktorów String::String(void) { s=newchar[81]; s[0]=0; // przerwanie łańcucha len=80; cout << "\nPracuje konstruktor domniemany:\n"; print(); } String::String(int n) { s=newchar[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=newchar[len+1]; strcpy(s,p); cout << "\nPracuje operator konwersji:\n"; print(); } String::String(String& str) { len=str.len; s=newchar[len+1]; strcpy(s,str.s); cout << "\nPracuje konstruktor kopiujacy:\n"; print(); }

  13. Klasa vectz 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=newint[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

  14. Klasa vectz dynamiczną alokacją pamięci i kontrolą indeksu • Dwa pola typu private: wskaźnik do pola roboczego int *poraz jego rozmiar int size. • W obszarze public jest data memberint 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

  15. 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){} };

  16. 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 height for(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"; }

  17. 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=newint* [s1]; for(int i=0; i<s1;i++) p[i]=newint[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.

  18. 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); …

  19. 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 };

  20. 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 elementu public: 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 };

  21. 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"; }

  22. Funkcje składowe klasy list - c.d. • Funkcja releasezdejmuje 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(); }

  23. Klasa list - kod klienta .. \test0.sln list *p; // wskaźnik do listy { // początek wewnętrznego bloku list w; w.add('A'); w.add('B'); // dwa elementy na liście w.pr_list(); w.del(); // kasujemy pierwszy w.pr_list(); p=&w; p->pr_list(); // powinien byc identyczny wydruk } // niejawne wywołanie destruktora p->pr_list(); // lista została wyczyszczona • lista jednokierunkowa.cpp • Segment main zawiera inner block. Po wyjściu z niego uruchamiany jest destruktor i lista jest automatycznie kasowana. • Przykładowy wydruk: B -> A -> Koniec listy. A -> Koniec listy. A -> Koniec listy. Koniec listy.

More Related