Οντοκεντρικόσ Προγραμματιςμόσ Ενότθτα 6: C++ ΚΛΑΕΙ, ΚΛΗΡΟΝΟΜΙΚΟΣΗΣΑ, ΠΟΛΤΜΟΡΦΙΜΟ Πολυμορφιςμόσ Ιωάννθσ Χατηθλυγεροφδθσ Πολυτεχνικι χολι Σμιμα Μθχανικϊν Η/Τ & Πλθροφορικισ
Πολυμορφιςμόσ
Πολυμορφιςμόσ Ειςαγωγι o Απαιτείται θ φπαρξθ μιασ ιεραρχίασ κλάςεων o Χρθςιμοποιοφμε αντικείμενα που ανικουν ςτθν ίδια ιεραρχία κλάςεων ωσ να ιταν όλα αντικείμενα τθσ κλάςθσ βάςθσ o Εικονικζσ ςυναρτιςεισ + δυναμικι ςφνδεςθ (Virtual functions + dynamic binding) Σεχνολογίεσ που υλοποιοφν τον πολυμορφιςμό o Επιτρζπει τθν αποτελεςματικι επζκταςθ των προγραμμάτων Νζεσ κλάςεισ μποροφν εφκολα να προςτεκοφν και να υποςτοφν επεξεργαςία όπωσ και οι υπάρχουςεσ 3/23
Παράδειγμα Κλάςθ βάςθσ: Animal Παραγόμενεσ κλάςεισ: Fish, Frog, Bird Η μζκοδοσ move() είναι κοινι, αλλά υλοποιείται διαφορετικά για κάκε είδοσ Animal. Μια εφαρμογι κρατά ζναν πίνακα από αντικείμενα των παραγόμενων κλάςεων και κάκε 1sec ςτζλνει ζνα μινυμα move ςε κάκε αντικείμενο. Κάκε αντικείμενο τφπου Animal που δζχεται το μινυμα γνωρίηει πωσ κα πρζπει να αντιδράςει. Σο ίδιο μινυμα που ςτζλνεται ςε διαφορετικά αντικείμενα (του ίδιου βαςικοφ τφπου Animal) ζχει πολλζσ μορφζσ αποτελεςμάτων πολυμορφιςμόσ Πόςο εφκολο είναι να προςκζςουμε μια νζα κλάςθ Turtle? 4/23
Παράδειγμα class Animal{ public: Animal(char* n):name(n){ void print() const{ cout << "-------------------\n"; cout << name << " is an animal"; private: char* name; ; class Dog : public Animal{ public: Dog(char* n):animal(n){ void print() const{ Animal::print(); cout << ", and a dog." << endl; ; class Cat : public Animal{ public: Cat(char* n):animal(n){ void print() const{ Animal::print(); cout << ", and a cat." << endl; ; class Bird : public Animal{ public: Bird(char* n):animal(n){ void print() const{ Animal::print(); cout << ", and a bird." << endl; ; Τπερκάλυψθ τθσ μεκόδου print ςτισ παράγωγεσ κλάςεισ int main() { Dog d("pluto"); d.print(); Cat c("tom"); c.print(); Bird b("twitty"); b.print(); Animal *animalpointer = &d; animalpointer->print(); ------------------- Pluto is an animal, and a dog. ------------------- Tom is an animal, and a cat. ------------------- Twitty is an animal, and a bird. ------------------- Pluto is an animal Ανάκεςθ αντικειμζνου παράγωγθσ κλάςθσ ςε δείκτθ τθσ κλάςθσ βάςθσ. Η μζκοδοσ που κα κλθκεί εξαρτάται από τθν κλάςθ του δείκτθ, (εδϊ είναι τφπου Animal) Διαφορετικι ςυμπεριφορά από τθν Java 5/23
Παράδειγμα - virtual class Animal{ public: Animal(char* n):name(n){ virtual void print() const{ cout << "-------------------\n"; cout << name << " is an animal"; private: char* name; ; class Dog : public Animal{ public: Dog(char* n):animal(n){ void print() const{ Animal::print(); cout << ", and a dog." << endl; ; class Cat : public Animal{ public: Cat(char* n):animal(n){ void print() const{ Animal::print(); cout << ", and a cat." << endl; ; class Bird : public Animal{ public: Bird(char* n):animal(n){ void print() const{ Animal::print(); cout << ", and a bird." << endl; ; Αλλαγι τθσ προκακοριςμζνθσ ςυμπεριφοράσ με virtual διλωςθ int main() { Dog d("pluto"); d.print(); Cat c("tom"); c.print(); Bird b("twitty"); b.print(); Animal *animalpointer = &d; animalpointer->print(); ------------------- Pluto is an animal, and a dog. ------------------- Tom is an animal, and a cat. ------------------- Twitty is an animal, and a bird. ------------------- Pluto is an animal, and a dog. Η μζκοδοσ που κα κλθκεί εξαρτάται από τθν πραγματικι κλάςθ του αντικειμζνου (δθμιουργικθκε ωσ Dog) 6/23
Δείκτθσ παραγόμενθσ κλάςθσ ςε αντικείμενο τθσ κλάςθσ βάςθσ το προθγοφμενο παράδειγμα είδαμε o Δείκτθσ κλάςθσ βάςθσ ςε αντικείμενο τθσ παραγόμενθσ κλάςθσ Dog is an Animal Δείκτθσ παραγόμενθσ κλάςθσ ςε αντικείμενο τθσ κλάςθσ βάςθσ o Compiler error Animal is not a Dog Η κλάςθ Dog μπορεί να διακζτει ιδιότθτεσ/λειτουργίεσ που δεν διακζτει θ κλάςθ Animal Μποροφμε να κάνουμε cast τθ διεφκυνςθ του αντικειμζνου τθσ κλάςθσ βάςθσ ςε δείκτθ παραγόμενθσ κλάςθσ Ονομάηεται downcasting Επιτρζπει τθν προςπζλαςθ λειτουργικότθτασ τθσ παραγόμενθσ κλάςθσ int main() { Animal a("unknown"); Dog d("pluto"); Animal* animalpointer = &d; Dog* dogpointer = &a; 7/23
Κλιςθ μεκόδων παραγόμενθσ κλάςθσ μζςω δείκτθ κλάςθσ βάςθσ Χριςθ δείκτθ/αναφοράσ o Δείκτθσ κλάςθσ βάςθσ μπορεί να δείχνει ςε αντικείμενο τθσ παραγομζνθσ κλάςθσ Μπορεί όμωσ να καλζςει μόνο τισ μεκόδουσ τθσ κλάςθσ βάςθσ o Η κλιςθ μεκόδων τθσ παραγόμενθσ κλάςθσ ςυνιςτά λάκοσ Μζκοδοι που δεν ορίηονται ςτθ κλάςθ βάςθσ Ο τφποσ δεδομζνων ενόσ/μιασ δείκτθ/αναφοράσ προςδιορίηουν τι μεκόδουσ μποροφμε να καλζςουμε 8/23
Εικονικζσ Συναρτιςεισ (Virtual Functions) Ο κανόνασ είναι ο τφποσ του δείκτθ να κακορίηει τι μζκοδοι μποροφν να κλθκοφν Οι virtual functions μποροφν να τον αλλάξουν o το αντικείμενο (και όχι ο δείκτθσ) να κακορίηει τι μζκοδοι μποροφν να κλθκοφν 9/23
Εικονικζσ Συναρτιςεισ (Virtual Functions) Δθλϊνουμε τθν print ωσ virtual ςτθν κλάςθ βάςθσ o Τπερκαλφπτουμε τθ print ςε κάκε παραγόμενθ κλάςθ ςαν να τθν ξαναορίηουμε, αλλά ι νζα ςυνάρτθςθ πρζπει να ζχει ακριβϊσ τθν ίδια υπογραφι με αυτι τθσ κλάςθσ βάςθσ o Εάν δθλϊςουμε μια ςυνάρτθςθ virtual ςτθν κλάςθ βάςθσ virtual void print() const; είναι virtual ςε όλεσ τισ παραγόμενεσ κλάςεισ Είναι καλι πρακτικι να δθλϊνουμε ρθτά ωσ virtual τισ ςυναρτιςεισ και ςτισ παραγόμενεσ κλάςεισ (program clarity) Δυναμικι ςφνδεςθ (Dynamic binding) o Επιλογι κλιςθσ τθσ κατάλλθλθσ ςυνάρτθςθσ κατά το χρόνο εκτζλεςθσ o υμβαίνει μόνο με τθ χριςθ δεικτϊν/αναφορϊν Εάν θ ςυνάρτθςθ κλθκεί με χριςθ ονόματοσ αντικειμζνου (π.χ. dogobject.print()), τότε χρθςιμοποιείται θ ςυνάρτθςθ του αντικειμζνου (static binding) 10/23
Χριςθ πεδίου για τφπο αντικειμζνων και εντολισ switch Ζνασ τρόποσ να προςδιορίςουμε τθν κλάςθ ενόσ αντικειμζνου o Βάηουμε ςτθν κλάςθ βάςθσ ζνα πεδίο shapetype ςτθν κλάςθ Shape o Χρθςιμοποιοφμε μια switch για να καλζςουμε τθ ςωςτι print ςυνάρτθςθ Πολλά προβλιματα o Μπορεί να ξεχάςουμε τον ζλεγχο κάποιασ περίπτωςθσ ςτθν switch o Εάν προςκζςουμε/αφαιρζςουμε μια κλάςθ πρζπει να ενθμερϊςουμε τθν switch Χρονοβόρο και επιρρεπζσ ςε λάκθ Καλφτερα με πολυμορφιςμό o απλοφςτερα προγράμματα, λιγότερο debugging 11/23
Abstract Classes Abstract class o κοπόσ: να αποτελζςει μια base class (abstract base class) o Ελλιπισ υμπλθρϊνεται με τισ παραγόμενεσ κλάςεισ o Δεν καταςκευάηουμε αντικείμενα από μια abstract class Μποροφμε να ζχουμε δείκτεσ και αναφορζσ Concrete classes o Μποροφμε να καταςκευάςουμε αντικείμενα o Τλοποιοφμε όλεσ τισ ςυναρτιςεισ που περιζχουν 12/23
Abstract Classes Είναι χριςιμεσ, όχι υποχρεωτικζσ Για να ορίςουμε μια abstract class o Δεν υπάρχει το keyword abstract όπωσ ςτθν Java o Θζλουμε μια ι περιςςότερεσ "pure" virtual functions virtual void print() const = 0; o Regular virtual functions Ζχουν υλοποίθςθ, θ υπερκάλυψθ είναι προαιρετικι o Pure virtual functions Δεν ζχουν υλοποίθςθ, θ υπερκάλυψθ είναι υποχρεωτικι o Μια abstract class μπορεί να ζχει δεδομζνα και υλοποιθμζνεσ ςυναρτιςεισ 13/23
Παράδειγμα #include <vector> using std::vector; void virtualviareference( const Animal &baseclassref ){ baseclassref.print(); void virtualviapointer( const Animal *baseclassptr ){ baseclassptr->print(); int main() { Animal a("unknown"); Dog d("pluto"); Cat c("tom"); Bird b("twitty"); vector< Animal* > animalvector( 3 ); animalvector [ 0 ] = &d; animalvector [ 1 ] = &c; animalvector [ 2 ] = &b; cout << " VIRTUAL VIA REFERENCE" <<endl; for ( int i = 0; i < animalvector.size(); i++ ) virtualviareference( *animalvector[ i ] ); cout <<endl<<endl<< " VIRTUAL VIA POINTER" <<endl; for ( int i = 0; i < animalvector.size(); i++ ) virtualviapointer( animalvector[ i ] ); 14/23
Virtual Destructors Δείκτθσ κλάςθσ βάςθσ ςε αντικείμενο τθσ παραγόμενθσ κλάςθσ o Εάν καταςτρζψουμε το αντικείμενο με τθν delete, θ ςυμπεριφορά είναι απροςδιόριςτθ Απλι λφςθ o Δθλϊνουμε τον destructor τθσ base-class ωσ virtual o Όταν καλείται θ delete καλείται και ο κατάλλθλοσ destructor Όταν καταςτρζφουμε ζνα αντικείμενο μιασ παραγόμενθσ κλάςθσ o Πρϊτα εκτελείται ο destructor τθσ παραγόμενθσ κλάςθσ o Μετά εκτελείται ο destructor τθσ base-class Οι constructors δεν μπορεί να είναι virtual 15/23
Παράδειγμα #include <vector> #include <typeinfo> using std::vector; int main() { vector< Animal* > animalvector( 3 ); animalvector [ 0 ] = new Dog("Pluto"); animalvector [ 1 ] = new Cat("Tom"); animalvector [ 2 ] = new Bird("Twitty"); for ( int i = 0; i < animalvector.size(); i++ ){ Dog *dogptr = dynamic_cast <Dog *>( animalvector[ i ] ); if (dogptr) animalvector[i]->print(); Η dynamic_cast επιςτρζφει null αν δεν μπορεί να γίνει το casting Η typeid επιςτρζφει αντικείμενο type_info, το οποίο περιζχει πλθροφορίεσ όπωσ το όνομα του αντικειμζνου με τθν μζκοδο name() for ( int i = 0; i < animalvector.size(); i++ ){ cout <<endl<< "deleting object " << typeid (*animalvector[ i ]).name() ; delete animalvector[i]; ------------------- Pluto is an animal, and a dog. deleting object 3Dog deleting object 3Cat deleting object 4Bird 16/23
Πρόςκετο Υλικό Μελετιςτε και τα παραδείγματα από τα Κεφάλαιo 12 του βιβλίου: «C++ How to Program, 9/e Paul & Harvey Deitel» http://media.pearsoncmg.com/ph/esm/deitel/cpp_htp_9/code_examples/code_examples.zip 17/23
Χρθματοδότθςθ Σο παρόν εκπαιδευτικό υλικό ζχει αναπτυχκεί ςτo πλαίςιo του εκπαιδευτικοφ ζργου του διδάςκοντα. Σο ζργο «Ανοικτά Ακαδθμαϊκά Μακιματα ςτο Πανεπιςτιμιο Ακθνών» ζχει χρθματοδοτιςει μόνο τθν αναδιαμόρφωςθ του εκπαιδευτικοφ υλικοφ. Σο ζργο υλοποιείται ςτο πλαίςιο του Επιχειρθςιακοφ Προγράμματοσ «Εκπαίδευςθ και Δια Βίου Μάκθςθ» και ςυγχρθματοδοτείται από τθν Ευρωπαϊκι Ζνωςθ (Ευρωπαϊκό Κοινωνικό Σαμείο) και από εκνικοφσ πόρουσ. 18/23
θμείωμα Ιςτορικοφ Εκδόςεων Ζργου Σο παρόν ζργο αποτελεί τθν ζκδοςθ 1.0. 19/23
θμείωμα Αναφοράσ Copyright: Πανεπιςτιμιον Πατρϊν, Ιωάννθσ Χατηθλυγεροφδθσ, 2015. «Οντοκεντρικόσ Προγραμματιςμόσ». Ζκδοςθ: 1.0. Πάτρα 2015. Διακζςιμο από τθ δικτυακι διεφκυνςθ: https://eclass.upatras.gr/courses/ceid1105/ 20/23
θμείωμα Αδειοδότθςθσ Σο παρόν υλικό διατίκεται με τουσ όρουσ τθσ άδειασ χριςθσ Creative Commons Αναφορά, Μθ Εμπορικι Χριςθ Παρόμοια Διανομι 4.0 *1+ ι μεταγενζςτερθ, Διεκνισ Ζκδοςθ. Εξαιροφνται τα αυτοτελι ζργα τρίτων π.χ. φωτογραφίεσ, διαγράμματα κ.λ.π., τα οποία εμπεριζχονται ςε αυτό και τα οποία αναφζρονται μαηί με τουσ όρουσ χριςθσ τουσ ςτο «θμείωμα Χριςθσ Ζργων Σρίτων». [1] http://creativecommons.org/licenses/by-nc-sa/4.0/ Ωσ Μθ Εμπορικι ορίηεται θ χριςθ: που δεν περιλαμβάνει άμεςο ι ζμμεςο οικονομικό όφελοσ από τθν χριςθ του ζργου, για το διανομζα του ζργου και αδειοδόχο που δεν περιλαμβάνει οικονομικι ςυναλλαγι ωσ προχπόκεςθ για τθ χριςθ ι πρόςβαςθ ςτο ζργο που δεν προςπορίηει ςτο διανομζα του ζργου και αδειοδόχο ζμμεςο οικονομικό όφελοσ (π.χ. διαφθμίςεισ) από τθν προβολι του ζργου ςε διαδικτυακό τόπο Ο δικαιοφχοσ μπορεί να παρζχει ςτον αδειοδόχο ξεχωριςτι άδεια να χρθςιμοποιεί το ζργο για εμπορικι χριςθ, εφόςον αυτό του ηθτθκεί.
Διατιρθςθ θμειωμάτων Οποιαδιποτε αναπαραγωγι ι διαςκευι του υλικοφ κα πρζπει να ςυμπεριλαμβάνει: το θμείωμα Αναφοράσ το θμείωμα Αδειοδότθςθσ τθ διλωςθ Διατιρθςθσ θμειωμάτων το θμείωμα Χριςθσ Ζργων Σρίτων (εφόςον υπάρχει) μαηί με τουσ ςυνοδευόμενουσ υπερςυνδζςμουσ. 22/23
θμείωμα Χριςθσ Ζργων Σρίτων Οι διαφάνειεσ βαςίηονται ςτο βιβλίο «C++ How to Program, 8th Edition, Harvey M. Deitel, Paul J. Deitel, Prentice Hall.» 23/23