ΚΛΗΡΟΝΟΜΙΚΟΤΗΤΑ ΠΟΛΥΜΟΡΦΙΣΜΟΣ

Σχετικά έγγραφα
ΠΟΛΥΜΟΡΦΙΣΜΟΣ, ΠΡΟΤΥΠΑ, ΚΑΘΙΕΡΩΜΕΝΗ ΒΙΒΛΙΟΘΗΚΗ ΠΡΟΤΥΠΩΝ. Polymorphism, Templates, Standard Template Library (STL)

Προγραμματισμός Ι. Κλάσεις και Αντικείμενα. Δημήτρης Μιχαήλ. Τμήμα Πληροφορικής και Τηλεματικής Χαροκόπειο Πανεπιστήμιο

ΠΟΛΥΜΟΡΦΙΣΜΟΣ. 4.1 Κληρονομικότητα και Αρχή της Υποκατάστασης

Σύνθεση και Κληρονομικότητα

Σύνθεση και Κληρονομικότητα

Εισαγωγή σε αντικειμενοστραφή concepts. Και λίγη C#

Προγραμματισμός Ι. Εισαγωγή στην C++ Δημήτρης Μιχαήλ. Τμήμα Πληροφορικής και Τηλεματικής Χαροκόπειο Πανεπιστήμιο

Αναφορές, είκτες και Αλφαριθμητικά

public void printstatement() { System.out.println("Employee: " + name + " with salary: " + salary);

Προγραμματισμός Υπολογιστών με C++

Οντοκεντρικός Προγραμματισμός

ΚΛΗΡΟΝΟΜΙΚΟΤΗΤΑ ΚΑΙ ΠΟΛΥΜΟΡΦΙΣΜΟΣ

Κλήση Συναρτήσεων ΚΛΗΣΗ ΣΥΝΑΡΤΗΣΕΩΝ. Γεώργιος Παπαϊωάννου ( )

POINTERS, AGGREGATION, COMPOSITION

Κλάσεις και αντικείμενα #include <iostream.h<

Οντοκεντρικός Προγραμματισμός ΦΡΟΝΤΙΣΤΗΡΙΟ JAVA

Εντολές εισόδου - εξόδου. Εισαγωγή στη C++

12. ΑΛΦΑΡΙΘΜΗΤΙΚΑ. υο είδη αλφαριθµητικών Τα αλφαριθµητικά της C πίνακες τύπου char Ta αντικείµενα της κλάσης string

Προγραμματισμός Υπολογιστών με C++

ΚΑΤΑΣΚΕΥΑΣΤΕΣ ΑΝΤΙΓΡΑΦΗΣ

Διάλεξη 16-17: Πολυμορφισμός (Polymorphism) Διδάσκων: Παναγιώτης Ανδρέου

Προγραμματισμός Υπολογιστών με C++

2 Ορισμός Κλάσεων. Παράδειγμα: Μηχανή για Εισιτήρια. Δομή μιας Κλάσης. Ο Σκελετός της Κλάσης για τη Μηχανή. Ορισμός Πεδίων 4/3/2008

Προγραμματισμός Ι. Δυναμική Διαχείριση Μνήμης. Δημήτρης Μιχαήλ. Ακ. Έτος Τμήμα Πληροφορικής και Τηλεματικής Χαροκόπειο Πανεπιστήμιο

2.1 Αντικειµενοστρεφής προγραµµατισµός

Κλάσεις και Αντικείµενα

ΤΕΧΝΙΚΕΣ ΑΝΤΙΚΕΙΜΕΝΟΣΤΡΑΦΟΥΣ ΠΡΟΓΡΑΜΜΑΤΙΣΜΟΥ. Κληρονομικότητα

Δομές δεδομένων (Structures) Εισαγωγή στη C++

Πληροφορική 2. Γλώσσες Προγραμματισμού

Υπερφόρτωση τελεστών (operator(

ΤΕΧΝΙΚΕΣ ΑΝΤΙΚΕΙΜΕΝΟΣΤΡΑΦΟΥΣ ΠΡΟΓΡΑΜΜΑΤΙΣΜΟΥ. Κλάσεις και Αντικείμενα Constructors, equals, tostring

Προγραμματισμός Υπολογιστών με C++

ΟΝΤΟΚΕΝΤΡΙΚΟΣ ΠΡΟΓΡ/ΣΜΟΣ C++

Ερωτήσεις και απαντήσεις στα θέματα του κανονισμού κατάρτισης

Γ7.2 Συμβολοσειρές (Strings) Γ Λυκείου Κατεύθυνσης

Κλάσεις στη Java. Στοίβα - Stack. Δήλωση της κλάσης. ΗκλάσηVector της Java. Ηκλάση Stack

Τελικό τεστ - απαντήσεις

Προγραμματισμός Υπολογιστών με C++ Φύλλο Διαγωνίσματος Ακαδημαϊκό εξάμηνο: Χειμερινό

Εισαγωγή στον Αντικειμενοστρέφή Προγραμματισμό Διάλεξη #12

Προγραμματισμός Υπολογιστών με C++

ΒΑΣΙΚΟΙ ΤΥΠΟΙ ΚΑΙ ΠΙΝΑΚΕΣ

Δισδιάστατοι Πίνακες (2D Arrays) Εισαγωγή στη C++

Εισαγωγή στην επιστήμη των υπολογιστών

ΑΝΑΚΕΦΑΛΑΙΩΣΗ. Τα βασικά για την γλώσσα Java

Οντοκεντρικός Προγραμματισμός ΦΡΟΝΤΙΣΤΗΡΙΟ JAVA

ΤΕΧΝΙΚΕΣ ΑΝΤΙΚΕΙΜΕΝΟΣΤΡΑΦΟΥΣ ΠΡΟΓΡΑΜΜΑΤΙΣΜΟΥ. Κλάσεις και Αντικείμενα Αναφορές

ΤΕΧΝΙΚΕΣ ΑΝΤΙΚΕΙΜΕΝΟΣΤΡΑΦΟΥΣ ΠΡΟΓΡΑΜΜΑΤΙΣΜΟΥ. Κληρονομικότητα Downcasting Πολυμορφισμός Late Binding

Αρχές Τεχνολογίας Λογισμικού Εργαστήριο

Κλάσεις στη Java. Παύλος Εφραιμίδης. Java Κλάσεις στη Java 1

Εισαγωγή στον Προγραμματισμό με C++

Υπερφόρτωση (Overloading) Υπέρβαση (Overriding) - Upcasting Downcasting Final classes, methods

Αντικειμενοστρέφεια. Henri Matisse, Harmony in Red, Κωστής Σαγώνας Νίκος Παπασπύρου

Οντοκεντρικός Προγραμματισμός

(Απλή) Κληρονομικότητα

Γλώσσα Προγραμματισμού C++ Εισαγωγή - Μια πρώτη ματιά

2 using namespace s t d ; 4 { 12 int t= x ; 6 x=y ; 7 y=t ; 8 } 9 11 { 13 x= y ; 14 y=t ; 15 } {

ΚΛΗΡΟΝΟΜΙΚΟΤΗΤΑ. Σχηματική παράσταση του προγράμματος. logariasmos

Εισαγωγή στον Αντικειμενοστρέφή Προγραμματισμό Διάλεξη #13

17TimeThis.h function returns reference pointer to same object { return *this; }

class object Database Database Item Item [sub-typing and polymorphism] MusicCD Video MusicCD Video

Συµβολοσειρές - Strings

Εισαγωγή στον Προγραμματισμό

ΤΕΧΝΙΚΕΣ ΑΝΤΙΚΕΙΜΕΝΟΣΤΡΑΦΟΥΣ ΠΡΟΓΡΑΜΜΑΤΙΣΜΟΥ. Κληρονομικότητα

Οντοκεντρικός Προγραμματισμός

Εισαγωγή στον Προγραμματισμό με C++

Αντικειμενοστραφείς Γλώσσες Προγραμματισμού C++ / ROOT

Τεχνολογίες Υλοποίησης Αλγορίθµων

Συμβολοσειρές ΣΥΜΒΟΛΟΣΕΙΡΕΣ. Γεώργιος Παπαϊωάννου ( )

Abstract classes, Interfaces ΦΡΟΝΤΙΣΤΗΡΙΟ JAVA

Οντοκεντρικός Προγραμματισμός

Δομή Προγράμματος C++, Χειρισμός Μεταβλητών και Συναρτήσεις Εισόδου - Εξόδου

Ανάλυση άσκησης. Employee. SalariedEmployee CommissionEmployee HourlyEmployee. BasePlusCommissionEmployee

ΤΕΧΝΙΚΕΣ ΑΝΤΙΚΕΙΜΕΝΟΣΤΡΑΦΟΥΣ ΠΡΟΓΡΑΜΜΑΤΙΣΜΟΥ. Σύνθεση αντικειμένων

Ειδικά Θέματα Προγραμματισμού

ΣΤΟΙΧΕΙΑ ΤΗΣ ΓΛΩΣΣΑΣ C++ Constructors, Destructors, Pointers IO Streams, File Streams

ΤΕΧΝΙΚΕΣ ΑΝΤΙΚΕΙΜΕΝΟΣΤΡΑΦΟΥΣ ΠΡΟΓΡΑΜΜΑΤΙΣΜΟΥ. Αντικείμενα ως ορίσματα

Διδάσκων: Κωνσταντίνος Κώστα Διαφάνειες: Δημήτρης Ζεϊναλιπούρ

Wrapper Classes, Abstract Classes and Interfaces

3 Αλληλεπίδραση Αντικειμένων

ΤΕΧΝΙΚΕΣ ΑΝΤΙΚΕΙΜΕΝΟΣΤΡΑΦΟΥΣ ΠΡΟΓΡΑΜΜΑΤΙΣΜΟΥ. Πολυμορφισμός Αφηρημένες κλάσεις Interfaces (διεπαφές)

Αντικειμενοστρεφής Προγραμματισμός

ΥΠΟΛΟΓΙΣΤΕΣ ΙI. Άδειες Χρήσης. Συναρτήσεις II Διδάσκοντες: Αν. Καθ. Δ. Παπαγεωργίου, Αν. Καθ. Ε. Λοιδωρίκης

Διαγράμματα Κλάσεων στη Σχεδίαση

Υπερφόρτωση τελεστών

ΤΕΧΝΙΚΕΣ ΑΝΤΙΚΕΙΜΕΝΟΣΤΡΑΦΟΥΣ ΠΡΟΓΡΑΜΜΑΤΙΣΜΟΥ. Δημιουργώντας δικές μας Κλάσεις και Αντικείμενα

Εισαγωγή στην επιστήμη των υπολογιστών. Λογισμικό Υπολογιστών Κεφάλαιο 9ο Γλώσσες Προγραμματισμού

Προγραμματισμός Ι. Πίνακες, Δείκτες, Αναφορές και Δυναμική Μνήμη. Δημήτρης Μιχαήλ. Τμήμα Πληροφορικής και Τηλεματικής Χαροκόπειο Πανεπιστήμιο

ΤΕΧΝΙΚΕΣ ΑΝΤΙΚΕΙΜΕΝΟΣΤΡΑΦΟΥΣ ΠΡΟΓΡΑΜΜΑΤΙΣΜΟΥ. Πολυμορφισμός Αφηρημένες κλάσεις Interfaces (διεπαφές)

ΤΕΧΝΙΚΕΣ ΑΝΤΙΚΕΙΜΕΝΟΣΤΡΑΦΟΥΣ ΠΡΟΓΡΑΜΜΑΤΙΣΜΟΥ. Αντικείμενα ως ορίσματα Εισαγωγή στις αναφορές

Δείκτες (Pointers) Ένας δείκτης είναι μια μεταβλητή με τιμή μια διεύθυνση μνήμης. 9.8

ΑΠΛΗ ΚΛΗΡΟΝΟΜΙΚΟΤΗΤΑ

ΥΠΟΛΟΓΙΣΤΕΣ ΙI. Άδειες Χρήσης. Συναρτήσεις I Διδάσκοντες: Αν. Καθ. Δ. Παπαγεωργίου, Αν. Καθ. Ε. Λοιδωρίκης

Εισαγωγή στην C. Μορφή Προγράµµατος σε γλώσσα C

Προγραμματισμός Υπολογιστών με C++

Διδάσκων: Παναγιώτης Ανδρέου

(Διαφάνειες Νίκου Βιδάκη)

ΤΕΧΝΙΚΕΣ ΑΝΤΙΚΕΙΜΕΝΟΣΤΡΑΦΟΥΣ ΠΡΟΓΡΑΜΜΑΤΙΣΜΟΥ. Κληρονομικότητα

Προγραμματισμός Δομές Δεδομένων

Περιεχόμενα. Λίγα λόγια για αυτή την έκδοση... 23

Η εντολή if-else. Η απλή μορφή της εντολής if είναι η ακόλουθη: if (συνθήκη) { Η γενική μορφή της εντολής ifelse. εντολή_1; εντολή_2;..

Transcript:

ΚΛΗΡΟΝΟΜΙΚΟΤΗΤΑ ΠΟΛΥΜΟΡΦΙΣΜΟΣ

ΑΝΑΚΕΦΑΛΑΙΩΣΗ

Θεματολόγιο Κληρονομικότητα Παράδειγμα Κληρονομικότητα Βελτιωμένο Παράδειγμα Ενθυλάκωση : public private - protected πεδία Ενθυλάκωση : public private - protected κληρονομικότητα Ανάθεση αντικειμένων και κληρονομικότητα Ανάθεση διευθύνσεων αντικειμένων σε δείκτες και κληρονομικότητα Πέρασμα παραμέτρων και κληρονομικότητα Άλλα θέματα

Κληρονομικότητα Έχουμε μια Βασική Κλάση (Base Class) Β, με κάποια πεδία και μεθόδους. Βασική Κλάση B data x method P Θέλουμε να δημιουργήσουμε μια νέα κλάση D η οποία να έχει όλα τα χαρακτηριστικά της Β, αλλά και κάποια επιπλέον. Παράγωγη Κλάση D data y Αντί να ξαναγράψουμε τον ίδιο κώδικα δημιουργούμε μια Παράγωγη Κλάση (Derivative Class) D, η οποία κληρονομεί όλη τη λειτουργικότητα της Βασικής Κλάσης Β και στην οποία προσθέτουμε τα νέα πεδία και μεθόδους. Αυτή είναι η ιδιότητα της κληρονομικότητας method Q data x method P

Κληρονομικότητα Η κληρονομικότητα είναι χρήσιμη όταν Θέλουμε να έχουμε αντικείμενα και της κλάσης Β και της κλάσης D. Θέλουμε να ορίσουμε πολλαπλές παράγωγες κλάσεις D1, D2, που η κάθε μία επεκτείνει την Β με διαφορετικό τρόπο.

Κλάση Person First name Κλάση Employee salary Last name getdetails Κλάση Customer credit getsalary() getcredit() First name Last name First name Last name getdetails() getdetails()

class Person private: char fname[40]; char lname[40]; public: Person(char fn[], char ln[]); ~Person(); char *getpersonaldetails(); ;

Person::Person(char fn[], char ln[]) strcpy(fname, fn); strcpy(lname, ln); Person::~Person() cout << ~Person() called\n ; char *Person::getPersonalDetails() char *ret = new char [strlen(fname) + strlen(lname) +40]; sprintf(ret, 1st Name %s -Last Name %s", fname, lname); return ret;

class Employee : public Person private: int basicsalary; public: Employee(char fn[], char ln[], int sal); ~Employee(); int getsalary(); ; Employee::Employee(char fn[],char ln[],int sal):person(fn,ln) basicsalary = sal; Employee::~Employee() cout << ~Employee() called ; int Employee::getSalary() return basicsalary;

class Customer : public Person private: int credit; char credittype[10]; public: Customer(char fn[], char ln[], char ct[]); ~Customer(); void chargecredit(int amount); int getcredit(); ; Customer::Customer(char fn[], char ln[], char ct[]) : Person(fn, ln) credit = 0; strcpy(credittype, ct); Customer::~Customer() cout << ~Customer called\n ; void Customer::chargeCredit(int amount) credit -= amount; int Customer::getCredit() return credit;

int main() char fname[40]; char lname[40]; int sal; int credit; cin >> fname >> lname >> sal; Employee john(fname, lname, sal); cin >> fname >> lname; Customer pet(fname, lname, "VISA"); char *details = john.getpersonaldetails(); sal = john.getsalary(); cout << details << " - Salary : " << sal << endl; delete [] details; pet.chargecredit(250); // οι destructors εκτελούνται αντίστροφα.

Κληρονομικότητα Μπορούμε να χρησιμοποιούμε την ιδιότητα της κληρονομικότητας με διάφορους τρόπους αλλά ο πιο χρήσιμος και κατανοητός είναι για να ορίσουμε μια εξειδίκευση/επέκταση μιας κλάσης. Σχέση is-a ή is-like-a

UML διαγράμματα Person Employee Customer

protected members Για να έχει πρόσβαση στα πεδία (ή μεθόδους) της Person η κλάση Employee θα πρέπει να είναι ορισμένα ως Public, ή Protected Class Person First name Last name getdetails Class Employee: public Person salary getsalary() First name Last name class Person protected: char fname[40]; char lname[40]; public: Person(char fn[], char ln[]); ~Person(); char *getpersonaldetails(); ; getdetails()

private inheritance Η μέθοδος getdetails() της κλάσης Person, δεν είναι πλέον προσβάσιμη από αντικείμενα της κλάσης Employee Class Person First name Last name getdetails Class Employee: private Person salary getsalary() First name int main() Employee emp; // cannot call emp.getdetails() Last name getdetails()

Γιατί αυτό είναι χρήσιμο? class Array protected: int *A; int size; public: Array(int s); GetElement(int i); ~Array(); ; class SafeArray: private Array public: GetElementSafely(int i); ; SafeArray::GetElementSafely(int i) if (i < 0 i >= size) exit(1); return A[i]; H SafeArray δεν επιτρέπει την χρήση της GetElement(i)

Ανάθεση Αντικειμένων και Κληρονομικότητα Στην ανάθεση μεταξύ δύο αντικειμένων x = y πρέπει τα δύο αντικείμενα να είναι της ίδιας κλάσης ή η κλάση του αντικειμένου που ανατίθεται (y) να κληρονομεί (άμεσα ή έμμεσα) από την κλάση του αντικειμένου στο οποίο γίνεται η ανάθεση (x) Δηλαδή το y να παράγεται (έμμεσα η άμεσα) από την κλάση x Στην περίπτωση αυτή λέμε ότι κάναμε upcasting.

int main() char fname[40]; char lname[40]; int sal; int credit; cin >> fname >> lname >> sal; Employee john(fname, lname, sal); cin >> fname >> lname; Customer pet(fname, lname, VISA ); cout << john.getpersonaldetails() << "-Salary: " << john.getsalary() << endl; pet.chargecredit(250); cout << pet.getpersonaldetails() << "-Credit: " << pet.getcredit() << endl;

Person johnprivatelife = john; // upcasting Person petprivatelife = pet; // upcasting cout << johnprivatelife.getpersonaldetails() << endl; cout << petprivatelife.getpersonaldetails() << endl; // petprivatelife.chargecredit(130); // compile error.. cin >> fname >> lname; petprivatelife.setpersonaldetails(fname, lname); cout << petprivatelife.getpersonaldetails() << endl; cout << pet.getpersonaldetails() << "-Credit: " << pet.getcredit() << endl;

Ανάθεση διευθύνσεων αντικειμένων σε δείκτες και κληρονομικότητα Στην ανάθεση της διεύθυνσης ενός αντικειμένου σε ένα pointer p = & x πρέπει ο p να είναι pointer της κλάσης στην οποία ανήκει το αντικείμενο x ή pointer κλάσης από την οποία κληρονομεί η κλάση του αντικειμένου x. Το ποιες μέθοδοι μπορούν να κληθούν μέσω του pointer, καθορίζεται από τον τύπο του pointer και όχι από τον τύπο του αντικειμένου.

int main() char fname[40]; char lname[40]; int sal; int credit; cin >> fname >> lname >> sal; Employee john(fname, lname, sal); cin >> fname >> lname; Customer pet(fname, lname, VISA ); cout << john.getpersonaldetails() << "-Salary: " << john.getsalary() << endl; pet.chargecredit(250); cout << pet.getpersonaldetails() << "-Credit: " << pet.getcredit() << endl;

Person *johnprivatelife = &john; Person *petprivatelife = &pet; cout << johnprivatelife->getpersonaldetails() << endl; cout << petprivatelife->getpersonaldetails() << endl; // petprivatelife->chargecredit(130); // compile error.. cin >> fname >> lname; petprivatelife->setpersonaldetails(fname, lname); cout << petprivatelife->getpersonaldetails() << endl; cout << pet.getpersonaldetails() << "-Credit: " << pet.getcredit() << endl;

Θεματολόγιο Κληρονομικότητα Παράδειγμα Κληρονομικότητα Βελτιωμένο Παράδειγμα Ενθυλάκωση : public private - protected πεδία Ενθυλάκωση : public private - protected κληρονομικότητα Ανάθεση αντικειμένων και κληρονομικότητα Ανάθεση διευθύνσεων αντικειμένων σε δείκτες και κληρονομικότητα Πέρασμα παραμέτρων και κληρονομικότητα Υποσκέλιση (overriding) συναρτήσεων

ΠΕΡΑΣΜΑ ΠΑΡΑΜΕΤΡΩΝ ΚΑΙ ΚΛΗΡΟΝΟΜΙΚΟΤΗΤΑ

Πέρασμα παραμέτρων και Κληρονομικότητα Είδαμε στα προηγούμενα παραδείγματα ότι Σε ένα αντικείμενο βασικής κλάσης μπορεί να ανατεθεί ένα αντικείμενο παραγόμενης κλάσης Σε ένα δείκτη σε αντικείμενα βασικής κλάσης μπορεί να ανατεθεί η διεύθυνση ενός αντικειμένου παραγόμενης κλάσης Η δυνατότητα του upcasting αποκτά εξαιρετική χρησιμότητα στην περίπτωση που το αντικείμενο ή ο δείκτης βασικής κλάσης είναι παράμετρος σε μια άλλη συνάρτηση ή μέθοδο του προγράμματος μας. Η συνάρτηση μας μπορεί να εκτελεστεί επιτυχημένα χωρίς καμία αλλαγή για αντικείμενα οποιασδήποτε κλάσης παράγεται από τη βασική κλάση. => η συνάρτηση μας είναι επαναχρησιμοποιήσιμη

Έστω ότι στο πρόγραμμά μας θέλουμε να προσθέσουμε την επιπλέον δυνατότητα να μετατρέπει τις πληροφορίες που διαχειρίζεται για τους πελάτες και τους υπαλλήλους σε html σελίδες και να τις εκτυπώνει.

Πέρασμα δια τιμής void HTMLFormattedPrint( Person p ) cout << "<HTML>" << p.getpersonaldetails() << "</HTML>" << endl; p.setpersonaldetails(, ); για να δούμε τη διαφορά περάσματος δια τιμής, και περάσματος με δείκτη ή αναφορά

Πέρασμα δια τιμής int main() char fname[40]; char lname[40]; int sal; int credit; H ίδια συνάρτηση καλείται για Customers και Employees μέσω upcasting cin >> fname >> lname >> sal; Employee john(fname, lname, sal); cin >> fname >> lname; Customer pete(fname, lname, VISA ); HTMLFormattedPrint(pete); HTMLFormattedPrint(john); cout << pete.getpersonaldetails() << " - Credit : " << pete.getcredit() << endl; return 0; Το αντικείμενο περνάει δια τιμής οι αλλαγές δεν είναι εμφανείς στη main ()

Πέρασμα δείκτη void HTMLFormattedPrint( Person *p ) cout << "<HTML>" << p->getpersonaldetails() << "</HTML>" << endl; p->setpersonaldetails(, );

Πέρασμα δείκτη int main() char fname[40]; char lname[40]; int sal; int credit; cin >> fname >> lname >> sal; Employee john(fname, lname, sal); cin >> fname >> lname; Customer pete(fname, lname, VISA ); HTMLFormattedPrint(&pete); HTMLFormattedPrint(&john); cout << pete.getpersonaldetails() << " - Credit : " << pete.getcredit() << endl; return 0; Το αντικείμενο περνάει δια τιμής οι αλλαγές είναι εμφανείς στη main ()

Λόγω της κληρονομικότητας, μια μόνο επιπλέον συνάρτηση μας αρκεί για να υλοποιήσουμε την επιπλέον δυνατότητα τόσο για τους πελάτες όσο και για τους υπάλληλους του καταστήματος.

Παρόλα αυτά το πρόγραμμά μας μπορεί να μετατρέψει σε html μόνο τις πληροφορίες που περιλαμβάνονται σαν χαρακτηριστικά στη βασική κλάση Person. ΓΙΑΤΙ?? Τι γίνεται αν θέλουμε να τυπώνουμε και τα επιμέρους χαρακτηριστικά που περιλαμβάνουν οι κλάσεις Employee και Customer?

METHOD OVERRIDING ΚΑΙ ΠΟΛΥΜΟΡΦΙΣΜΟΣ

using namespace std; class Person private: char fname[40]; char lname[40]; public: Person(char fn[], char ln[]); char *getpersonaldetails(); void setpersonaldetails(char fn[], char ln[]); ;

class Employee : public Person private: int basicsalary; public: Employee(char fn[], char ln[], int sal); int getsalary(); ; class Customer : public Person private: int credit; char credittype[10]; public: Customer(char fn[], char ln[], char ct[]); void chargecredit(int amount); int getcredit(); char *getcredittype(); ;

Person::Person(char fn[], char ln[]) strcpy(fname, fn); strcpy(lname, ln); void Person::setPersonalDetails(char fn[], char ln[]) strcpy(fname, fn); strcpy(lname, ln); char *Person::getPersonalDetails() char *ret = new char [strlen(fname) + strlen(lname) +40]; sprintf(ret, 1st Name %s - Last Name %s", fname, lname); return ret;

Employee::Employee(char fn[], char ln[], int sal) : Person(fn, ln) basicsalary = sal; int Employee::getSalary() return basicsalary;

Customer::Customer(char fn[], char ln[], char ct[]) : Person(fn, ln) credit = 0; strcpy(credittype, ct); void Customer::chargeCredit(int amount) credit -= amount; int Customer::getCredit() return credit; char *Customer::getCreditType() return credittype;

int main() char fname[40]; char lname[40]; int sal; int credit; cin >> fname >> lname >> sal; Employee john(fname, lname, sal); cin >> fname >> lname; Customer pete(fname, lname, "VISA"); pete.chargecredit(250); cout << john.getpersonaldetails() << " " << john.getsalary() << endl; cout << pete.getpersonaldetails() << " " << pete.getcredittype() << " " << pete.getcredit() << endl; return 0;

Η σχεδίαση του κώδικα μας δεν είναι πλέον καλή γιατί χρειαζόμαστε διαφορετικές εντολές για να τυπώσουμε τα στοιχεία αντικειμένων από διαφορετικές κλάσεις. Μια νέα παραγόμενη κλάση θα δημιουργούσε επιπλέον προβλήματα. Θέλουμε μια μοναδική συνάρτηση που να μας δίνει τα στοιχεία του αντικειμένου.

Method Overriding Σε κάθε μία από τις παραγόμενες κλάσεις θα επανα-ορίσουμε την μέθοδο getpersonaldetails() O ορισμός στην παραγόμενη κλάση υποσκελίζει (overrides) τον ορισμό στη βασική κλάση.

# include <iostream> # include <cstring> using namespace std; class Person private: char fname[40]; char lname[40]; public: Person(char fn[], char ln[]); char *getpersonaldetails(); void setpersonaldetails(char fn[], char ln[]); ;

class Employee : public Person private: int basicsalary; public: Employee(char fn[], char ln[], int sal); int getsalary(); char *getpersonaldetails(); ; class Customer : public Person private: int credit; char credittype[10]; public: Customer(char fn[], char ln[], char ct[]); void chargecredit(int amount); int getcredit(); char *getcredittype(); char *getpersonaldetails(); ;

Person::Person(char fn[], char ln[]) strcpy(fname, fn); strcpy(lname, ln); void Person::setPersonalDetails(char fn[], char ln[]) strcpy(fname, fn); strcpy(lname, ln); char *Person::getPersonalDetails() char *ret = new char [strlen(fname) + strlen(lname)+ 40]; sprintf(ret, 1st Name %s - Last Name %s", fname, lname); return ret;

Employee::Employee(char fn[], char ln[], int sal) : Person(fn, ln) basicsalary = sal; int Employee::getSalary() return basicsalary; char *Employee::getPersonalDetails() char *name = Person::getPersonalDetails(); char * ret = new char [strlen(name) + 10]; sprintf(ret, "%s %d", name, basicsalary); return ret; Εδώ καλείται και η μέθοδος που επανα-ορίσαμε. Για να μην έχουμε αναδρομή, καθορίζουμε ότι καλούμε τη μέθοδο που κληρονομούμε από την Person

Customer::Customer(char fn[], char ln[], char ct[]): Person(fn, ln) credit = 0; strcpy(credittype, ct); void Customer::chargeCredit(int amount) credit -= amount; int Customer::getCredit() return credit; char *Customer::getCreditType() return credittype; char *Customer::getPersonalDetails() char *name = Person::getPersonalDetails(); char * ret = new char [strlen(name) + strlen(credittype) + 10]; sprintf(ret, "%s %s %d", name, credittype, credit); return ret;

int main() char fname[40]; char lname[40]; int sal; int credit; cin >> fname >> lname >> sal; Employee john(fname, lname, sal); cin >> fname >> lname; Customer pete(fname, lname, "VISA"); pete.chargecredit(250); cout << john.getpersonaldetails() << endl; cout << pete.getpersonaldetails() << endl; return 0;

Πιο περίπλοκο παράδειγμα int main() Person *all[10]; for (int i = 0; i < 10; i++) char fname[40]; char lname[40]; int sal; char choice; cin >> choice; if (choice == p ) cin >> fname >> lname; all[i] = new Person(fname, lname); if (choice == e ) cin >> fname >> lname >> sal; all[i] = new Employee(fname, lname, sal); if (choice == c ) cin >> fname >> lname; all[i] = new Customer(fname, lname, "VISA"); for (int i = 0; i < 10; i++) cout << all[i]->getpersonaldetails() << endl; Τι output θα πάρουμε?

Πιο περίπλοκο παράδειγμα int main() Person *all[10]; for (int i = 0; i < 10; i++) char fname[40]; char lname[40]; int sal; char choice; cin >> choice; if (choice == p ) cin >> fname >> lname; all[i] = new Person(fname, lname); if (choice == e ) cin >> fname >> lname >> sal; all[i] = new Employee(fname, lname, sal); if (choice == c ) cin >> fname >> lname; all[i] = new Customer(fname, lname, "VISA"); for (int i = 0; i < 10; i++) cout << all[i]->getpersonaldetails() << endl; Θέλω να καλώ την επανα-ορισμένη μέθοδο της αντίστοιχης παραγόμενης κλάσης Καλείται η μέθοδος της Person

Εξήγηση Στη C++ αν έχω: μια βασική κλάση Α και παραγόμενες κλάσεις Β, Γ οι οποίες επανα-ορίζουν μια μέθοδο f() της Α κώδικα (συνάρτηση, μέθοδο, κλπ.) στον οποίο χρησιμοποιείται ένας δείκτης p βασικής κλάσης Α που μπορεί να δείχνει σε αντικείμενα των κλάσεων Α, Β, ή Γ μέσω του δείκτη καλείται η μέθοδος f() στο αντικείμενο στο οποίο δείχνει ο δείκτης p η υλοποίηση της μεθόδου f() που θα καλεστεί καθορίζεται από τον τύπο του δείκτη δηλαδή καλείται η υλοποίηση της μεθόδου f() της βασικής κλάσης Α η επιλογή γίνεται από τον compiler κατά τη διάρκεια της μετάφρασης του προγράμματος (early binding)

Virtual Methods and Late Binding Για να κάνουμε την επιλογή της μεθόδου f() που θα καλεστεί να καθορίζεται από τον τύπο του αντικειμένου στο οποίο δείχνει ο δείκτης p (δηλαδή να καλείται η υλοποίηση της μεθόδου f() των παραγόμενων κλάσεων Β, Γ) πρέπει η μέθοδος f() να δηλωθεί στην κλάση A ως virtual μέθοδος. Στην περίπτωση των virtual μεθόδων δίνεται η οδηγία στον compiler ότι η επιλογή της υλοποίησης της f() δεν θα γίνει κατά τη μετάφραση του προγράμματος, με βάση τον τύπο του δείκτη, αλλά κατά την εκτέλεση του προγράμματος με βάση τον τύπο του αντικειμένου στο οποίο δείχνει ο δείκτης κάθε φορά που εκτελείται ο κώδικας (late binding).

# include <iostream> # include <cstring> using namespace std; class Person private: char fname[40]; char lname[40]; public: Person(char fn[], char ln[]); virtual char *getpersonaldetails(); void setpersonaldetails(char fn[], char ln[]); ;

class Employee : public Person private: int basicsalary; public: Employee(char fn[], char ln[], int sal); int getsalary(); char *getpersonaldetails(); ; class Customer : public Person private: int credit; char credittype[10]; public: Customer(char fn[], char ln[], char ct[]); void chargecredit(int amount); int getcredit(); char *getcredittype(); char *getpersonaldetails(); ;

Person::Person(char fn[], char ln[]) strcpy(fname, fn); strcpy(lname, ln); void Person::setPersonalDetails(char fn[], char ln[]) strcpy(fname, fn); strcpy(lname, ln); char *Person::getPersonalDetails() char *ret = new char [strlen(fname) + strlen(lname) +40]; sprintf(ret, 1st Name %s - Last Name %s", fname, lname); return ret;

Employee::Employee(char fn[],char ln[],int sal):person(fn, ln) basicsalary = sal; int Employee::getSalary() return basicsalary; char *Employee::getPersonalDetails() // εδώ καλείται και η μέθοδος που επανα-ορίσαμε char *name = Person::getPersonalDetails(); char * ret = new char [strlen(name) + 10]; sprintf(ret, "%s %d", name, basicsalary); return ret;

Customer::Customer(char fn[], char ln[], char ct[]): Person(fn, ln) credit = 0; strcpy(credittype, ct); void Customer::chargeCredit(int amount) credit -= amount; int Customer::getCredit() return credit; char *Customer::getCreditType() return credittype; char *Customer::getPersonalDetails() char *name = Person::getPersonalDetails(); char * ret = new char [strlen(name) + strlen(credittype)+ 10]; sprintf(ret, "%s %s %d", name, credittype, credit); return ret;

int main() Person *all[10]; Καλείται η μέθοδος του αντίστοιχου αντικειμένου for (int i = 0; i < 10; i++) char fname[40]; char lname[40]; int sal; char choice; cin >> choice; if (choice == p ) cin >> fname >> lname; all[i] = new Person(fname, lname); if (choice == e ) cin >> fname >> lname >> sal; all[i] = new Employee(fname, lname, sal); if (choice == c ) cin >> fname >> lname; all[i] = new Customer(fname, lname, "VISA"); for (int i = 0; i < 10; i++) cout << all[i]->getpersonaldetails() << endl;

Πέρασμα δείκτη void HTMLFormattedPrint( Person *p ) cout << "<HTML>" << p->getpersonaldetails() << "</HTML>" << endl; Τι θα παίρναμε αν δεν είχαμε ορίσει την virtual μέθοδο? Με τη virtual μέθοδο, η συνάρτηση πλέον δουλεύει για οποιοδήποτε αντικείμενο κλάσης Person, Employee, Customer και τυπώνει σωστά τα αντίστοιχα πεδία. Η συνάρτηση HTMLFormattedPrint είναι πλέον επαναχρησιμοποιήσιμη για οποιαδήποτε παράγωγη κλάση της Person.

Πολυμορφισμός Τα παραπάνω είναι παραδείγματα πολυμορφισμού. Τι είναι πολυμορφισμός? (πολυμορφισμός = πολλές μορφές. Η χρήση μιας μεθόδου με διαφορετικούς τρόπους). Δύο είδη πολυμορφισμού: Στατικός Πολυμορφισμός (compile time early binding) Method Overloading Method Overriding Δυναμικός Πολυμορφισμός (run time late binding) Virtual methods που αποφασίζονται δυναμικά με βάσει το αντικείμενο.

ΠΟΛΥΜΟΡΦΙΣΜΟΣ ΚΑΙ ΑΦΗΡΗΜΕΝΕΣ ΚΛΑΣΕΙΣ

Έστω ότι στο πρόγραμμά μας θέλουμε να προσθέσουμε μια μέθοδο που μετατρέπει τις πληροφορίες που διαχειρίζεται για τους πελάτες και τους υπαλλήλους σε html σελίδες και να τις εκτυπώνει. Η μέθοδος παίρνει μία παράμετρο που παίρνει τιμή 1, ή 2: Με την επιλογή 1, τυπώνει μόνο τα βασικά χαρακτηριστικά της κλάσης Person Με την επιλογή 2, τυπώνει μόνο τα οικονομικά επιμέρους χαρακτηριστικά που περιλαμβάνουν οι κλάσεις Employee και Customer

# include <iostream> # include <cstring> using namespace std; class Person private: char fname[40]; char lname[40]; public: Person(char fn[], char ln[]); char *getpersonaldetails(); virtual char* getfinancialdetails(); // εικονική μέθοδος χωρίς υλοποίηση void setpersonaldetails(char fn[], char ln[]); ;

class Employee : public Person private: int basicsalary; public: Employee(char fn[], char ln[], int sal); int getsalary(); char *getfinancialdetails(); ; class Customer : public Person private: int credit; char credittype[10]; public: Customer(char fn[], char ln[], char ct[]); void chargecredit(int amount); int getcredit(); char *getcredittype(); char *getfinancialdetails(); ;

Person::Person (char fn[], char ln[]) strcpy(fname, fn); strcpy(lname, ln); void Person::setPersonalDetails(char fn[], char ln[]) strcpy(fname, fn); strcpy(lname, ln); char *Person::getPersonalDetails() char *ret = new char [strlen(fname) + strlen(lname) + 40]; sprintf(ret, 1st Name %s - Last Name %s", fname, lname); return ret; char* getfinancialdetails() return NULL;

Employee::Employee(char fn[], char ln[], int sal) : Person(fn, ln) basicsalary = sal; int Employee::getSalary() return basicsalary; char *Employee::getFinancialDetails() char * ret = new char [30]; sprintf(ret, " Basic Salary %d ", basicsalary); return ret;

Customer::Customer(char fn[], char ln[], char ct[]) : Person(fn, ln) credit = 0; strcpy(credittype, ct); void Customer::chargeCredit(int amount) credit -= amount; int Customer::getCredit() return credit; char *Customer::getCreditType() return credittype; char *Customer::getFinancialDetails() char * ret = new char [strlen(credittype) + 40]; sprintf(ret, "Credit Type %s Credit %d", credittype, credit); return ret;

void HTMLFormattedPrint (Person *p, int choice) if(choice == 1) cout << "<HTML>" << p->getpersonaldetails() << "</HTML>" << endl; else if(choice == 2) cout << "<HTML>" << p->getfinancialdetails() << "</HTML>" << endl;

int main() char fname[40]; char lname[40]; int sal; int credit; cin >> fname >> lname >> sal; Employee john(fname, lname, sal); cin >> fname >> lname; Customer pete(fname, lname, "VISA"); pet.chargecredit(250); HTMLFormattedPrint (&pete, 1); HTMLFormattedPrint (&john, 1); HTMLFormattedPrint (&pete, 2); HTMLFormattedPrint (&john, 2); return 0;

Εικονικές μεθόδοι Στην ουσία κατασκευάσαμε μια βασική κλάση που περιλαμβάνει μια τετριμμένη εικονική μέθοδο getfinancialdetails μόνο και μόνο για να μπορούμε να την επανα-ορίσουμε στις παραγόμενες κλάσεις και να την καλούμε στην μέθοδο HTMLFormattedPrint Η τετριμμένη μέθοδος όμως επιστρέφει NULL και είναι αρκετά επικίνδυνη Κανείς δεν μπορεί να εγγυηθεί ότι ένας προγραμματιστής που θα επεκτείνει την κλάση Person θα επανα-ορίσει την getfinancialdetails αν δεν επανα-ορίστει η μέθοδος, η NULL τιμή που επιστρέφει μπορεί να δημιουργήσει προβλήματα. Θέλουμε να εξασφαλίσουμε ότι η getfinancialdetails πάντα θα επανα-ορίζεται και δεν θα χρησιμοποιείται ποτέ η τετριμένη μέθοδος

Αφηρημένες βασικές κλάσεις Για να εξασφαλίσουμε ότι όσοι επεκτείνουν την κλάση Person θα επανα-ορίσουν την τετριμμένη μέθοδο getfinancialdetails ορίζουμε μια αφηρημένη βασική κλάση. Μια κλάση ονομάζεται αφηρημένη αν περιέχει τουλάχιστον μια εικονική μέθοδο που δεν περιλαμβάνει υλοποίηση δηλώνεται ως virtual methodname() = 0; Η αφηρημένη κλάση λειτουργεί σαν καλούπι για την κατασκευή παραγόμενων που προσφέρουν εναλλακτικές υλοποιήσεις στις εικονικές μεθόδους. Η δημιουργία αντικειμένων αφηρημένης κλάσης ΔΕΝ επιτρέπεται από τον compiler Η μη υλοποίηση εικονικών μεθόδων ΔΕΝ επιτρέπεται από τον compiler

# include <iostream> # include <cstring> using namespace std; class Person private: char fname[40]; char lname[40]; public: Person(char fn[], char ln[]); char *getpersonaldetails(); virtual char* getfinancialdetails() = 0; // γνησια εικονική μέθοδος χωρίς υλοποίηση void setpersonaldetails(char fn[], char ln[]); ;

class Employee : public Person private: int basicsalary; public: Employee(char fn[], char ln[], int sal); int getsalary(); char *getfinancialdetails(); ; class Customer : public Person private: int credit; char credittype[10]; public: Customer(char fn[], char ln[], char ct[]); void chargecredit(int amount); int getcredit(); char *getcredittype(); char *getfinancialdetails(); ;

Person::Person(char fn[], char ln[]) strcpy(fname, fn); strcpy(lname, ln); void Person::setPersonalDetails(char fn[], char ln[]) strcpy(fname, fn); strcpy(lname, ln); char *Person::getPersonalDetails() char *ret = new char [strlen(fname) + strlen(lname) +40]; sprintf(ret, 1st Name %s - Last Name %s", fname, lname); return ret; // Δεν υπάρχει υλοποιηση της getfinancialdetails // ούτε καν τετριμένη!!!

Employee::Employee(char fn[], char ln[], int sal) : Person(fn, ln) basicsalary = sal; int Employee::getSalary() return basicsalary; char *Employee::getFinancialDetails() char * ret = new char [30]; sprintf(ret, " Basic Salary %d ", basicsalary); return ret; // Αν δεν ορίσουμε την getfinancialdetails θα έχουμε error

Customer::Customer(char fn[], char ln[], char ct[]) : Person(fn, ln) credit = 0; strcpy(credittype, ct); void Customer::chargeCredit(int amount) credit -= amount; int Customer::getCredit() return credit; char *Customer::getCreditType() return credittype; char *Customer::getFinancialDetails() char * ret = new char [strlen(credittype) + 40]; sprintf(ret, "Credit Type %s Credit %d", credittype, credit); return ret; // Αν δεν ορίσουμε την getfinancialdetails θα έχουμε error

void HTMLFormattedPrint (Person *p, int choice) if(choice == 1) cout << "<HTML>" << p->getpersonaldetails() << "</HTML>" << endl; else if(choice == 2) cout << "<HTML>" << p->getfinancialdetails() << "</HTML>" << endl;

int main() char fname[40]; char lname[40]; int sal; cin >> fname >> lname >> sal; Employee john(fname, lname, sal); cin >> fname >> lname; Customer pete(fname, lname, "VISA"); pete.chargecredit(250); // Person mary(fname, lname) θα δώσει compile error! HTMLFormattedPrint (&pete, 1); HTMLFormattedPrint (&john, 1); HTMLFormattedPrint (&pete, 2); HTMLFormattedPrint (&john, 2); return 0;

ΑΛΛΑ ΘΕΜΑΤΑ

Πολλαπλή κληρονομικότητα Μία κλάση μπορεί να κληρονομεί (να παράγεται) από πολλαπλές άλλες κλάσεις Employee class Employee. Student class Student. WorkingStudent class WorkingStudent: public Employee, public Student.

Επίπεδα κληρονομικότητας Μπορούμε επίσης να έχουμε πολλά επίπεδα κληρονομικότητας Person Employee Customer Manager FloorEmp VIP VIP

Και συνδυασμό των δύο Person class Person. Employee class Employee: public Person. Student class Student: public Person. WorkingStudent class WorkingStudent: public Employee, public Student.

Πολλαπλή Κληρονομικότητα - Αμφισημία class Base1 public: void f(); ; class Base2 public: void f(); ; main() Derived d; d.f(); // υπάρχει αμφισημία! class Derived: public Base1, public Base2...

Πολλαπλή Κληρονομικότητα - Αμφισημία class Base1 public: void f(); ; class Base2 public: void f(); ; main() Derived d; d.base1::f(); d.base2::f(); class Derived: public Base1, public Base2...