OOPC++ - dziedziczenie1 Uwagi VS2003 Wykłady (nie na rainbow!)
OOPC++ - dziedziczenie2 Kilka ostatnio wydanych książek o C++ "C efektywnych sposobów na udoskonalenie Twoich programów"; Scott Meyers; Helion 11/2003; ("Effective C++: 50 Specific Ways to Improve Your Programs and Design"; Addison-Wesley; 2nd ed. Sep. 1997; 1st ed. Dec. 30, 1991); 248 str. "C++. Biblioteka standardowa. Podręcznik programisty"; Nicolai M. Josuttis; Helion 09/2003; ("The C++ Standard Library: A Tutorial and Reference"; Addison-Wesley; 1st ed., Aug. 12, 1999;); 728 str. C++. Inżynieria programowania; Victor Shtern; Helion 12/2003; (Core C++: A Software Engineering Approach; Prentice Hall; 1st ed. January, 2000) 1088 str. C++. Kruczki i fortele w programowaniu. Stephen C. Dewhurst; Helion 12/2003; (C++ Gotchas: Avoiding Common Problems in Coding and Design; Addison-Wesley; 1st ed. Nov. 26, 2002), 272 str. "C++. Potęga języka. Od przykładu do przykładu"; Andrew Koenig, Barbara E. Moo; Helion 1/2004; ("Accelerated C++. Practical Programming by Example"; Addison-Wesley; 1st edition Jan. 15, 2000); 432 str.
OOPC++ - dziedziczenie3 Nowe książki cd. "C++. Strategie i taktyki. Vademecum profesjonalisty"; Robert B. Murray; Helion 12/2003 (C++ Strategies and Tactics; Addison- Wesley; Mar. 1993); 240 str. "C++. Styl i technika zaawansowanego programowania"; James O. Coplien; Helion 1/2004; (Advanced C++ Programming Styles and Idioms; Addison-Wesley; Sep. 1991); 480 str. "C++. Styl programowania"; Tom Cargill; Helion 12/2003; (C++ Programming Style, Addison- Wesley; 1st ed. Aug. 1992); 224 str. "Istota języka C++. Zwięzły opis"; Stanley B. Lippman; WNT 1/2004; ("Essential C++"; Addison-Wesley; 1st edition Oct. 26, 1999); 326 str. ============================== "C++. Szablony. Vademecum profesjonalisty"; David Vandevoorde, Nicolai M. Josuttis; Helion 7/2003; (C++ Templates The Complete Guide; Addison-Wesley; 1st ed. Oct. 26, 1999); 480 str.
OOPC++ - dziedziczenie4 Dziedziczenie (derivation) Klasa bazowa - nadklasa, klasa pochodna - podklasa. class A { public:..... // dostępne wszędzie protected:..... // dostępne w podklasach, prywatne na zewnątrz private:..... // niedostępne ani w podklasach, ani na zewnątrz }; class B: public A {// wszyscy wiedzą, że B dziedziczy po A //.... }; Zgodność typów A aa; B bb; aa = bb;// dozwolone, ale kopiuje się tylko tyle ile jest w A // Uwaga (Java, Delphi, C#): typem aa nadal jest A! bb = aa;// nielegalne (o ile nie B::operator=(const A&) A * ap;// wskaźnik do obiektu klasy A B * bp; // wskaźnik do obiektu klasy B ap = bp;// poprawne (polimorfimz!) bp = ap;// niedozwolone! Ale o ile na zmiennej ap jest // faktycznie obiekt klasy B to... bp = (B*) ap; //... dozwolone (przestarzałe), bp = dynamic_cast (ap); //... dozwolone (współczesne) Operator dynamic_cast jeśli się nie powiedzie daje 0 (wskaźniki) lub zgłasza bad_cast (referencje).
OOPC++ - dziedziczenie5 Funkcje wirtualne Funkcje wirtualne zachowują się tak, jak metody w Smalltalku. Wywołanie funkcji wirtualnej p -> f () powoduje poszukiwanie tej funkcji, począwszy od klasy obiektu wskazywanego przez wskaźnik p. class A { public: virtual void f ( );... }; class B : public A { public: void f ( ); }; A ax, *p; A ax; p = new A; x ->f (); // będzie wywołana funkcja f z klasy A delete p; p = new B; x -> f ( ); // będzie wywołana funkcja f z klasy B delete p; p = &ax;// p - wskaźnik do obiektu klasy A p -> f ( );// wywołuje się f z klasy A p = &bx;// p - wskaźnik do obiektu klasy B p -> f ( );// wywołuje się f z klasy B (pomimo, że p // jest zadekl. jako wskaźnik do A) Funkcje wirtualne muszą mieć (praktycznie) identyczne nagłówki. Funkcje czysto-wirtualne. class A {// klasa abstrakcyjna public: virtual void f ( ) = 0; // ta funkcja musi być zdefiniowana // w podklasie };
OOPC++ - dziedziczenie6 class punkt { public: punkt (int xx, int yy) { x = xx; y = yy; } private: int x, y; }; class ksztalt {// klasa abstrakcyjna protected: punkt srodek; public: punkt gdzie ( ) { return srodek; } void przesun (punkt& p) { srodek = p; rysuj ( ); } virtual void obrot (int kat) = 0; // czysto wirtualna funkcja virtual void rysuj ( ) = 0;// czysto wirtualna funkcja //.... ksztalt(punkt p): srodek(p) {} // koniecznie na liście ini. virtual ~ksztalt(){} // B. ważne! }; class okrag : public ksztalt { protected: int promien; public: okrag (punkt sr, int r ) : ksztalt(sr) { promien = r ;} void obrot (int kat) { } void rysuj ( ); }; class wielokat : public ksztalt { protected: int liczba, promien; public: wielokat (int l, int r, punkt sr): ksztalt(sr) { liczba = l; promien = r; } void obrot (int kat); void rysuj (); // inne funkcje składowe };
OOPC++ - dziedziczenie7 void okrag :: rysuj () {.... } void wielokat :: rysuj () {... } void wielokat :: obrot (int kat) {.... } void main () { ksztalt * f; f = new okrag(punkt (100, 100), 50); f -> rysuj (); //..... delete f; f = new wielokat (6, 50, punkt (300, 300)); f -> rysuj (); f -> obrot (30); //..... delete f; } ksztalt kwadrat okragwielokat ksztalt * x; ksztalt * y; x -> rysuj ( ); y -> rysuj ( ); x y
OOPC++ - dziedziczenie8 class pracownik { protected: char* nazwisko; int dzial; public: virtual void print(); }; class sekretarka: public pracownik { //.... }; class kierownik: public pracownik { protected: pracownik * grupa; int poziom; public: void print (); }; void pracownik :: print () { cout << nazwisko << << dzial << \n; } void kierownik :: print () { pracownik :: print ();// wywołanie wyższej funkcji cout << poziom << poziom << \n; }
OOPC++ - dziedziczenie9 Wyrażenia class Wyrazenie { public: virtual float oblicz_dla (float p) = 0; virtual Wyrazenie* pochodna () = 0; float calka (float start, float stop, int lprzedz); }; float Wyrazenie :: calka (float start, float stop, int lprzedz) { float suma = 0.0; float krok = (stop - start) / lprzedz; float x; for (x = start; x < stop; x += krok) suma += krok * oblicz_dla (x); return suma; }; class Wyrazenie_Dwuarg: public Wyrazenie { protected: Wyrazenie * arg1, *arg2; public: Wyrazenie_Dwuarg (Wyrazenie * w1, Wyrazenie *w2) { arg1 = w1; arg2 = w2; } }; class Iloczyn : public Wyrazenie_Dwuarg { public: float oblicz_dla ( float p); Wyrazenie *pochodna (); }; float Iloczyn :: oblicz_dla (float p) { return (arg1 -> oblicz_dla (p)) * (arg2 -> oblicz_dla (p)); } // i Iloczyn::pochodna()
OOPC++ - dziedziczenie10 class KlasaA { private: vector x, y; int liczba_elementow; public: KlasaA (int rozmiar);// konstruktor dla KlasaA virtual ~KlasaA (){};// destruktor }; Definicja (nie deklaracja!) konstruktora dla KlasaA musi też uwzględniać wywołanie konstruktorów dla atrybutów obiektu (x i y). KlasaA :: KlasaA (int rozmiar) : x (rozmiar), y (rozmiar) {..... } Konstruktory i destruktory - cd przekazanie argumentów dla konstruktorów klasy table class bazowa { public: bazowa (char * p, int t){...}; virtual ~bazowa(){}; }; class pochodna : public bazowa { public: pochodna (char *c); ~pochodna (){}; }; pochodna :: pochodna (char * p) : bazowa(p, 10) {... } Kolejność wykonywania konstruktorów: bazowa, składniki, pochodna Kolejność wykonywania destruktorów: pochodna, składniki, bazowa
OOPC++ - dziedziczenie11 Funkcje i klasy zaprzyjaźnione Funkcja zadeklarowana jako zaprzyjaźniona w jakiejś klasie nie jest jej funkcją składową, ale może używać jej prywatnych i chronionych atrybutów. class X { int a; friend void friend_set (X*, int); public: void member_set (int); }; void friend_set (X* p, int i) { p -> a = i; } void X :: member_set (int i) { a = i;} void f () { X obj; friend_set (&obj, 10); obj.member_set (10); } Funkcja składowa jakiejś klasy może być funkcją zaprzyjaźnioną innej klasy. Wszystkie funkcje z klasy X mogą być zaprzyjaźnionymi funkcjami klasy Y (mogą używać jej atrybutów prywatnych). class Y { friend class X;... }; Uwaga: jest to mechanizm łamiący hermetyzację danych i ochronę atrybutów, nie należy go nadużywać.