1 / 78

Είσοδος & Έξοδος στη C++ Ι

Είσοδος & Έξοδος στη C++ Ι. # include <iostream.h> void main() { cout << “Hello, World“ << endl; }. Το αρχείο iostream.h πρέπει να περιλαμβάνεται σε κάθε πηγαίο πρόγραμμα που χρησιμοποιεί λειτουργίες ροής εισόδου – εξόδου .

ramona
Télécharger la présentation

Είσοδος & Έξοδος στη C++ Ι

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. Είσοδος & Έξοδος στη C++ Ι #include <iostream.h> void main() { cout << “Hello, World“ << endl; } Το αρχείο iostream.h πρέπει να περιλαμβάνεται σε κάθε πηγαίο πρόγραμμα που χρησιμοποιεί λειτουργίες ροής εισόδου – εξόδου. Αυτό το αρχείο κεφαλίδας ορίζει μεταξύ άλλων το αντικείμενοcoutπου αναπαριστά την τυπική έξοδο. Κάθε δεδομένο που στέλνεται στο cout εμφανίζεται στο τερματικό ή στέλνεται σε αρχείο στην περίπτωση ανακατεύθυνσης της τυπικής εξόδου. Στέλνοντας στη ροή εξόδου το αντικείμενο endlτυπώνεται ο χαρακτήρας νέας γραμμής και εκκενώνεται η προσωρινή περιοχή αποθήκευσης της ροής εξόδου (stream buffer). Τμ. Πληροφορικής, Α.Π.Θ.

  2. Είσοδος & Έξοδος στη C++ ΙΙ Για να σταλούν δεδομένα στη ροή εξόδου χρησιμοποιείται ο τελεστής <<. Μπορούμε να έχουμε αλυσίδα λειτουργιών εξόδου στην ίδια ροή: cout << “The value of pi is approx. “ << 3.14159 << endl; Μπορούν τα δεδομένα αντί για την τυπική έξοδο να σταλούν σε ένα αρχείο. #include <fstream.h> ofstream os(“output.dat”); os << “The value of pi is approx. “ << 3.14159 << endl; Τμ. Πληροφορικής, Α.Π.Θ.

  3. Είσοδος & Έξοδος στη C++ ΙΙΙ Το αρχείο iostream.h ορίζει επίσης την κλάση istream και ένα αντικείμενο cin για ανάγνωση από την τυπική είσοδο (είτε πληκτρολόγιο ή από ανακατευθυνόμενο αρχείο). Ο τελεστής >> χρησιμοποιείται για την ανάγνωση δεδομένων. double x; cin >> x; Για κάθε δεδομένο που διαβάζεται με τον τελεστή >> αγνοούνται τα κενά που προηγούνται. Αν θέλουμε να διαβάσουμε ένα μόνο χαρακτήρα χωρίς να αγνοήσουμε την πιθανότητα του κενού, τότε καλούμε την get. char ch = cin.get(); Μπορούμε αν θέλουμε να «ανιχνεύσουμε» τον επόμενο χαρακτήρα χωρίς να τον καταναλώσουμε από τη ροή εισόδου: Τμ. Πληροφορικής, Α.Π.Θ.

  4. Είσοδος & Έξοδος στη C++ ΙV double x; char aChar; char ch = cin.peek(); if (isdigit(ch)) cin >> x; else cin >> aChar; Συνάρτηση που ελέγχει αν υπάρχει αποτυχία στην ανάγνωση δεδομένου από τη ροή εισόδου (α) λόγω ασυμφωνίας τύπων ή (β) λόγω τέλους αρχείου:  Τμ. Πληροφορικής, Α.Π.Θ.

  5. Είσοδος & Έξοδος στη C++V Στο παρακάτω πρόγραμμα το loop τερματίζει όταν διαβαστεί συμβολοσειρά που δεν είναι αριθμός ή στο τέλος αρχείου. double t = 0; int n = 0; while (!cin.fail()) { double x; cin >> x; if (!cin.fail()) { t += x; n++; } } if (n > 0) cout << “average: “ << t/n <<endl; Τμ. Πληροφορικής, Α.Π.Θ.

  6. Είσοδος & Έξοδος στη C++VΙ Ανάγνωση από αρχείο: #include <fstream.h> ifstream is(“input.dat”); is >> x; if (is.fail()) . . . .; Τμ. Πληροφορικής, Α.Π.Θ.

  7. Η συνάρτηση main πρωτότυπο της συνάρτησης main: void main (int argc, char* argv[]); ο αριθμός των παραμέτρων πίνακας δεικτών χαρα- κατά την κλήση του προγ/τος κτήρα που αντιστοιχούν στις συμβολοσειρές των παραμέτρων του προγ/τος Τμ. Πληροφορικής, Α.Π.Θ.

  8. Προγραμματίζετε με assertions!! H macro assert ορίζεται στο assert.h και επιτρέπει των ορισμό συνθηκών που ο έλεγχός τους έχει ως αποτέλεσμα τον εντοπισμό του αριθμού γραμμής όπου παρουσιάζεται κάποιο λάθος χρόνου εκτέλεσης. //#define NDEBUG #include <assert.h> #include <math.h> // . . . y = f(x); #ifndef NDEBUG assert (y>=0); #endif z = sqrt(y); Τμ. Πληροφορικής, Α.Π.Θ.

  9. Ορισμός Κλάσης (Τάξης) Ι ΚΑΛΗ ΠΡΑΚΤΙΚΗ ΟΡΙΣΜΟΥ ΚΛΑΣΕΩΝ (Η C++ ΔΙΝΕΙ ΚΑΙ ΑΛΛΕΣ ΔΥΝΑΤΟΤΗΤΕΣ) • ΔΗΛΩΝΕΤΕ ΤΙΣ ΛΕΙΤΟΥΡΓΙΕΣ (ΣΥΝΑΡΤΗΣΕΙΣ) ΣΤΟ PUBLIC ΜΕΡΟΣ ΤΟΥ ΟΡΙΣΜΟΥ ΤΗΣ ΚΛΑΣΗΣ • ΔΗΛΩΝΕΤΕ ΤΑ ΠΕΔΙΑ ΔΕΔΟΜΕΝΩΝ ΣΤΟ PRIVATE ΜΕΡΟΣ ΤΟΥ ΟΡΙΣΜΟΥ ΤΗΣ ΚΛΑΣΗΣ • ΓΡΑΦΕΤΕ ΤΗΝ ΥΛΟΠΟΙΗΣΗ ΤΩΝ ΛΕΙΤΟΥΡΓΙΩΝ ΑΜΕΣΩΣ ΜΕΤΑ ΤΟΝ ΟΡΙΣΜΟ ΤΗΣ ΚΛΑΣΗΣ ΠΑΡΑΔΕΙΓΜΑ οι λειτουργίες αυτές δηλώνονται class Mailbox ως public γιατί καλούνται { για αντικείμενα mailbox public: οπουδήποτε μέσα στο πρόγραμμα void add(Message); Message get_current(); void delete_current(); // . . . } Τμ. Πληροφορικής, Α.Π.Θ.

  10. Ορισμός Κλάσης (Τάξης) ΙΙ • ΣΤΗ C++ TA ANTIKEIMENA EINAI ΑΠΛΕΣ ΜΕΤΑΒΛΗΤΕΣ ΠΟΥ Ο ΤΥΠΟΣ ΤΟΥΣ ΕΙΝΑΙ Η ΚΛΑΣΗ ΑΠΟ ΤΗΝ ΟΠΟΙΑ ΕΧΟΥΝ ΔΗΜΙΟΥΡΓΗΘΕΙ κώδικας που αφαιρεί ένα ΠΑΡΑΔΕΙΓΜΑ μήνυμα από ένα mailbox Mailboxmbox; και στη συνέχεια το χρη- Message msg; σιμοποιεί msg = mbox.get_current(); msg.play(); • ΟΙ ΛΕΙΤΟΥΡΓΙΕΣ ΜΠΟΡΕΙ ΝΑ ΚΑΛΟΥΝΤΑΙ ΜΕ ΠΑΡΑΜΕΤΡΟΥΣ ΠΑΡΑΔΕΙΓΜΑ mbox.add(msg); Τμ. Πληροφορικής, Α.Π.Θ.

  11. Ορισμός Κλάσης (Τάξης) ΙΙI • ΚΛΗΣΗ ΛΕΙΤΟΥΡΓΙΑΣ ΓΙΑ ΕΝΑ ΑΝΤΙΚΕΙΜΕΝΟ–ΣΥΝΤΑΞΗ: αντικείμενο.λειτουργία(παράμετροι); • ΔΗΛΩΣΗ ΠΕΔΙΩΝ ΔΕΔΟΜΕΝΩΝ ΣΤΗΝ ΚΛΑΣΗ: ΠΑΡΑΔΕΙΓΜΑ class Dateδηλώνονται στο private μέρος του { ορισμού της κλάσης για να διασφαλι- public: στεί ότι θα είναι προσβάσιμες μόνο // . . . από τις λειτουργίες της κλάσης Date private: και από πουθενά αλλού int _day; λέμε ότι ο ορισμός της κλάσης int _month; δίνει μια μη ολοκληρωμένη πε- int _year; ριγραφή της κατάστασης αντικει } μένων Στην πραγματικότητα το σύνολο των σωστών καταστάσεων των αντικειμένων της Date είναι ένα υποσύνολο του συνόλου των καταστάσεων που περιγράφεται στον ορισμό της κλάσης (πρέπει π.χ. _day <= 31) Τμ. Πληροφορικής, Α.Π.Θ.

  12. Ορισμός Κλάσης (Τάξης) ΙV • Η κλάση Date είναι παρόμοια με τον ορισμό της στη C ως structure struct { int day; int month; int year; }; • Παρόλα αυτά τα structures στη C δεν παρέχουν τη δυνατότητα ελέγχου πρόσβασης στα δεδομένα. Αυτά μπορούν να αλλάξουν από οπουδήποτε μέσα στο πρόγραμμα: struct date birthday = {31, 3, 1961}; // . . . birthday.day = birthday.day + 1; Τμ. Πληροφορικής, Α.Π.Θ.

  13. Ορισμός Κλάσης (Τάξης) V • Ο αντίστοιχος κώδικας στη C++ απλά δεν θα μεταφραζόταν: Date birthday; birthday._day = birthday._day + 1; //ERROR • Αλλαγή ημερομηνίας μπορεί να γίνει στη C++ μόνο με κλήση της κατάλληλης λειτουργίας που έχει γράψει ο συγγραφέας της κλάσης Date. Μπορεί δηλαδή να γίνει μόνο με ελεγχόμενο τρόπο. • Πως γράφουμε την υλοποίηση λειτουργιών; Τμ. Πληροφορικής, Α.Π.Θ.

  14. Ορισμός Κλάσης (Τάξης) VΙ • Έστω ότι θέλουμε να αλλάξουμε την τιμή μιας ημερομηνίας b με μία άλλη πουαντιστοιχεί σε 30 ημέρες μετά. Αυτό γίνεται με την κλήση της b.advance(30); αλλά προφανώς πρέπει να έχει δηλωθεί και η κατάλληλη συνάρτηση στον ορισμό της κλάσης class Date { public: void advance(int nday); // . . . }; Τμ. Πληροφορικής, Α.Π.Θ.

  15. Ορισμός Κλάσης (Τάξης) VΙI και στη συνέχεια ακολουθεί η υλοποίηση της συνάρτησης τελεστής εμβέλειας void Date::advance(int nday) {//μετατροπή σε Ιουλιανή ημερομηνία long j = dat2jul(_day, _month, _year); //πρόσθεση n ημερών j += nday; //μετατροπή από Ιουλιανή ημερομηνία jul2dat(j, _day, _month, _year); } Ο τελεστής εμβέλειας χρησιμοποιείται για να καθορίσει σε ποια κλάση ανήκει η λειτουργία advance Τμ. Πληροφορικής, Α.Π.Θ.

  16. Ορισμός Κλάσης (Τάξης) VΙIΙ • ΤΟ ΣΗΜΑΝΤΙΚΟ ΔΕΝ ΕΙΝΑΙ ΟΙ ΛΕΠΤΟΜΕΡΕΙΕΣ ΤΗΣ ΥΛΟΠΟΙΗΣΗΣ ΑΛΛΑ ΤΟ ΓΕΓΟΝΟΣ ΟΤΙ ΜΕ ΤΗΝ ΚΛΗΣΗ ΤΗΣ Η ΣΥΝΑΡΤΗΣΗ advance ΑΛΛΑΖΕΙ ΤΙΣ ΤΙΜΕΣ ΤΩΝ _day, _month, _year. ΠΟΙΕΣ ΤΙΜΕΣ ΟΜΩΣ ΤΕΛΙΚΑ ΑΛΛΑΖΕΙ ΑΝ ΛΑΒΟΥΜΕ ΥΠΟΨΗ ΟΤΙ ΜΠΟΡΕΙ ΝΑ ΥΠΑΡΧΟΥΝ ΠΟΛΛΑ ΑΝΤΙΚΕΙΜΕΝΑ Date; Η ΣΥΝΑΡΤΗΣΗ ΑΛΛΑΖΕΙ ΤΙΣ ΤΙΜΕΣ ΠΟΥ ΑΝΗΚΟΥΝ ΣΤΟ ΑΝΤΙΚΕΙΜΕΝΟ ΓΙΑ ΤΟ ΟΠΟΙΟ ΚΑΛΕΙΤΑΙ Η ΛΕΙΤΟΥΡΓΙΑ: b.advance(30); • ΣΤΗ C++ ΠΑΝΤΑ ΟΙ ΛΕΙΤΟΥΡΓΙΕΣ ΕΦΑΡΜΟΖΟΝΤΑΙ ΣΕ ΚΑΠΟΙΟ ΑΝΤΙΚΕΙΜΕΝΟ ΠΟΥ ΟΥΣΙΣΤΙΚΑ ΑΠΟΤΕΛΕΙ ΤΗΝ ΥΠΟΝΟΟΥΜΕΝΗ ΠΑΡΑΜΕΤΡΟ ΤΗΣ ΛΕΙΤΟΥΡΓΙΑΣ. ΜΙΑ ΛΕΙΤΟΥΡΓΙΑ ΟΜΩΣ ΜΠΟΡΕΙ ΝΑ ΕΧΕΙ ΚΑΙ ΦΑΝΕΡΕΣ ΠΑΡΑΜΕΤΡΟΥΣ ΚΑΙ ΣΤΟ ΠΑΡΑΔΕΙΓΜΑ ΜΑΣ ΜΙΑ ΤΕΤΟΙΑ ΕΙΝΑΙ ΤΟ 30. • ΣΤΗ C++ ΟΙ ΠΡΟΓΡΑΜΜΑΤΙΣΤΕΣ ΑΠΟΚΑΛΟΥΝ ΤΙΣ ΛΕΙΤΟΥΡΓΙΕΣ ΣΥΝΑΡΤΗΣΕΙΣ ΜΕΛΗ ΚΑΙ ΤΑ ΠΕΔΙΑ ΔΕΔΟΜΕΝΩΝ ΤΑ ΑΠΟΚΑΛΟΥΝ ΔΕΔΟΜΕΝΑ ΜΕΛΗ. Ο ΤΕΛΕΣΤΗΣ . ΧΡΗΣΙΜΟΠΟΙΕΙΤΑΙ ΓΙΑ ΠΡΟΣΒΑΣΗ ΕΙΤΕ ΣΤΙΣ ΣΥΝΑΡΤΗΣΕΙΣ ΜΕΛΗ ΕΙΤΕ ΣΤΑ ΔΕΔΟΜΕΝΑ ΜΕΛΗ. Τμ. Πληροφορικής, Α.Π.Θ.

  17. Ορισμός Κλάσης (Τάξης) ΙX • CONSTANT ΛΕΙΤΟΥΡΓΙΕΣ class Date { public: void advance(int); void print() const; // . . . }; σημαίνει ότι η συγκεκριμένη λειτουργία δεν αλλάζει την κατάσταση του αντικειμένου αλλά χρησιμοποιείται μόνο για πρόσβαση στα δεδομένα του void Date::print() const { // . . . } Τμ. Πληροφορικής, Α.Π.Θ.

  18. Ορισμός Κλάσης (Τάξης) X • ΣΥΝΑΡΤΗΣEIΣ ΑΠΛΗΣ ΠΡΟΣΠΕΛΑΣΗΣ ΠΕΔΙΩΝ ΔΕΔΟΜΕΝΩΝ class Date { public: int month() const; // . . . private: int _day; int _month; είναι συναρτήσεις που απλά int _year; επιστρέφουν την τιμή μιας // . . . private μεταβλητής }; int Date::month() const { return _month; } Τμ. Πληροφορικής, Α.Π.Θ.

  19. Ορισμός Κλάσης (Τάξης) XI • Για το συγγραφέα της κλάσης είναι κάποιος επιπλέον κόπος η συγγραφή τόσο του private δεδομένου μέλους όσο και της αντίστοιχης public συνάρτησης προσπέλασης της τιμής του. • Για τον προγραμματιστή που χρησιμοποιεί την κλάση αντί να γράψει d._month γράφει d.month(). • Το σημαντικό είναι ότι με αυτόν τον τρόπο η τιμή του δεδομένου μέλους έχει γίνει read only για το υπόλοιπο πρόγραμμα εκτός της κλάσης. Σε περίπτωση λάθους δε χρειάζεται να ερευνηθεί όλο το πρόγραμμα, αλλά μόνο οι συναρτήσεις της κλάσης. • H C++ απαιτεί ένα πεδίο δεδομένων να έχει διαφορετικό όνομα από τη συνάρτηση προσπέλασης και γι΄ αυτό το λόγο χρησιμοποιείται το _. Γράφουμε δηλαδή _month για να διακρίνεται από το month(). Τμ. Πληροφορικής, Α.Π.Θ.

  20. Ορισμός Κλάσης (Τάξης) XIΙ • ΣΥΝΑΡΤΗΣEIΣ ΓΙΑ ΑΛΛΑΓΗ ΠΕΔΙΩΝ ΔΕΔΟΜΕΝΩΝ void Date::set_month(int m) { if (1<=m && m<=12) _month = m; } • Η συνάρτηση set_month δεν δηλώνεται ως const για να μπορεί να αλλάξει τιμή δεδομένου μέλους. Ονομάζεται συνάρτηση αλλαγής δεδομένου μέλους. • Όταν χρησιμοποιούμε συναρτήσεις προσπέλασης και αλλαγής πεδίων δεδομένων, αν χρειαστεί να γίνουν αλλαγές στη δομή της κλάσης τότε ο αλλαγές αυτές επηρεάζουν μόνο τις δύο αυτές κατηγορίες συναρτήσεων, που εύκολα μπορούμε να εντοπίσουμε και δεν επηρεάζουν όλο το υπόλοιπο πρόγραμμα. Τμ. Πληροφορικής, Α.Π.Θ.

  21. Ορισμός Κλάσης (Τάξης) XIΙΙ • Οι συναρτήσεις αλλαγής πεδίων δεδομένων μπορούν να κάνουν έλεγχο για λάθος τιμές. Έτσι, θα μπορούσε για παράδειγμα στην κλήση b.set_month(13) να γίνει ο σχετικός έλεγχος για λάθος τιμή κάτι που δεν είναι εφικτό αν απλά γράφαμε b._month=13. • Το παράδειγμα της κλάσης Date είναι μια καλή περίπτωση κλάσης στην οποία δεν είναι καλή ιδέα να ορίσουμε συναρτήσεις αλλαγής τιμής για κάθε ένα δεδομένο μέλος. Θεωρείστε τις κλήσεις: d.set_day(31); d.set_month(3); d.set_year(1961); Αν η προηγούμενη τιμή του d ήταν 1 Φεβρουαρίου, τότε η κλήση της πρώτης συνάρτησης θέτει στο αντικείμενο d την μη επιτρεπτή τιμή 31 Φεβρουαρίου. Αυτό σημαίνει ότι θα είχαμε καλύτερο έλεγχο της ορθότητας της κατάστασης των αντικειμένων Date αν η συνάρτηση αλλαγής ήταν μία και η κλήση της είχε τη μορφή d.set_date(31,3,1961); Τμ. Πληροφορικής, Α.Π.Θ.

  22. Ορισμός Κλάσης (Τάξης) XIV • ΣΥΝΑΡΤΗΣEIΣ INLINE Αν μας ενδιαφέρει η ταχύτητα εκτέλεσης και η συνάρτηση που θέλουμε να γράψουμε είναι απλή τότε μπορούμε να τη δηλώσουμε ως inline π.χ. inline int square(int x) {return x*x;} Αυτή η δήλωση θα έχει ως αποτέλεσμα να μεταφράζει ο μεταγλωττιστής το square(expr) απευθείας σε expr*exprυπό τον όρο ότι πρόκειται για απλή έκφραση χωρίς παράπλευρες επιπτώσεις (π.χ. αλλαγή διεύθυνσης μνήμης). Αν η τιμή της έκφρασης είναι προσωρινά αποθηκευμένη στην temp τότε γίνεται απευθείας υπολογισμός της temp*temp. Έχουμε πιο αποδοτική εκτέλεση κώδικα. Τμ. Πληροφορικής, Α.Π.Θ.

  23. Ορισμός Κλάσης (Τάξης) XV • ΣΥΝΑΡΤΗΣEIΣ INLINE inline int Date::month() const {return _month;} Στην περίπτωση της παραπάνω δήλωσης η κλήση d.month() μεταφράζεται ως d._month, δηλαδή έχουμε απευθείας προσπέλαση στο πεδίο δεδομένων και έτσι παράγεται ποιο αποδοτικός κώδικας. Οι inline συναρτήσεις προστατεύουν την κατάσταση των αντικειμένων της κλάσης και ταυτόχρονα αποφεύγουν το overhead που συνεπάγεται οι πολλές κλήσεις συναρτήσεων. Τμ. Πληροφορικής, Α.Π.Θ.

  24. Ορισμός Κλάσης (Τάξης) XVΙ • ΣΥΝΑΡΤΗΣEIΣ INLINE Εναλλακτικός τρόπος ορισμού inline συναρτήσεων: class Date { public: int day() const {return _day;} // . . . private: int _day; // . . . }; Γενικά ο παραπάνω τρόπος ορισμού δεν θεωρείται μια καλή πρακτική. Τμ. Πληροφορικής, Α.Π.Θ.

  25. Ορισμός Κλάσης (Τάξης) XVΙΙ • PRIVATE ΣΥΝΑΡΤΗΣΕΙΣ Αρκετά συχνά χρειάζεται να δηλώσουμε private συναρτήσεις, που χρησιμοποιούνται π.χ. Στην υλοποίηση άλλων συναρτήσεων της κλάσης. class Date { public: // . . . private: Bool is_leap_year() const; int _day; // . . . }; Σίγουρα η υλοποίηση τέτοιων συναρτήσεων επηρεάζεται από τη δομή της κλάσης, αν όμως η δομή αυτή αλλάξει τότε οι private συναρτήσεις μπορεί και να μη χρειάζονται με τη νέα δομή ή πρέπει να ξαναγραφυτούν. Τμ. Πληροφορικής, Α.Π.Θ.

  26. Ορισμός Κλάσης (Τάξης) XVΙΙΙ • ΔΙΚΑΙΩΜΑ ΠΡΟΣΠΕΛΑΣΗΣ ΣΕ ΔΙΑΦΟΡΕΤΙΚΑ ΣΤΙΓΜΙΟΤΥΠΑ ΚΛΆΣΗΣ Στη C++ οι συναρτήσεις μέλη έχουν το δικαίωμα προσπέλασης στα ιδιωτικά μέλη κάθε αντικειμένου της κλάσης πράγμα που δεν ισχύει με όλες τις αντικειμενοστρεφείς γλώσσες προγραμματισμού. ΠΑΡΑΔΕΙΓΜΑ int Date::compare(Date b) const { int d = _year – b._year; if (d != 0) return d; d = _month – b._month; if (d != 0) return d; return _day – b.d_day; } Τμ. Πληροφορικής, Α.Π.Θ.

  27. Δομητές (Constructors) I • Οι ΔΟΜΗΤΕΣ είναι ειδικές συναρτήσεις που ΚΑΛΟΥΝΤΑΙ ΑΥΤΟΜΑΤΑ κατά τη δημιουργία των αντικειμένων. Οι δομητές ΈΧΟΥΝ ΤΟ ΙΔΙΟ ΟΝΟΜΑ ΜΕ ΤΟ ΌΝΟΜΑ ΤΗΣ ΚΛΑΣΗΣ. class Date { public: Date(int d, int m, int y); // . . . }; Date::Date(int d, int m, int y) : _day(d), _month(m), _year(y) { } Τμ. Πληροφορικής, Α.Π.Θ.

  28. Δομητές (Constructors) II • Οι ΔΟΜΗΤΕΣ αρχικοποιούν τα πεδία δεδομένων του αντικειμένου. Ο συμβολισμός _day(d) είναι ισοδύναμος με την ανάθεση _day = d. Επειδή δεν απαιτείται κάτι άλλο από το δομητή το σώμα της συνάρτησης δεν περιέχει κάποια επιπλέον εντολή. Επίσης, οι δομητές δεν επιστρέφουν τιμές. • Ο δομητής του παραδείγματος καλείται αυτόματα με τη δήλωση ενός αντικειμένου date: Date d(31, 3, 1961); • ΔΙΑΦΟΡΕΣ ΔΟΜΗΤΩΝ ΑΠΟ ΤΙΣ ΥΠΟΛΟΙΠΕΣ ΣΥΝΑΡΤΗΣΕΙΣ • Ο δομητής καλείται μόνο μία φορά κατά τη δημιουργία του αντικειμένου. Δεν μπορεί να κληθεί δεύτερη φορά για να «επαναρχικοποιήσει» το αντικείμενο • Ο δομητής δεν μπορεί να κληθεί για ένα ήδη υπαρκτό αντικείμενο • Ο δομητής δεν μπορεί να κληθεί φανερά όπως οι άλλες συναρτήσεις. Καλείται αυτόματα από τη C++ κατά τη δήλωση του αντικειμένου. Τμ. Πληροφορικής, Α.Π.Θ.

  29. Δομητές (Constructors) III • Μεγάλο πλεονέκτημα των ΔΟΜΗΤΩΝ είναι το ότι η ύπαρξή τους απομακρύνει την πιθανότητα μη αρχικοποιημένων μεταβλητών. Αν οριστεί ΔΟΜΗΤΗΣ αποκλείεται να οριστούν αντικείμενα τα οποία δεν θα αρχικοποιούνται. έτσι αν έχει δηλωθεί η Date(int, int, int) τότε η Date d; είναι λάθος • Στις κλάσεις μπορεί να ορίζονται περισσότεροι από ένας δομητές αλλά μόνο ένας από αυτούς θα είναι ο πρoκαθορισμένος (default) Τμ. Πληροφορικής, Α.Π.Θ.

  30. Δομητές (Constructors) IV class Date { public: Date(); Date(int d, int m, int y=0); Date(String); // . . . }; Date::Date(int d, int m, int y) : _day(d), _month(m), _year(y) { if (_year == 0) _year = current year} Τμ. Πληροφορικής, Α.Π.Θ.

  31. Ανώνυμα αντικείμενα • Οι δομητές μπορούν να χρησιμοποιηθούν στη δημιουργία αντικειμένων που χρησιμοποιούνται σε υπολογισμούς και μετά δεν μας χρειάζονται: όπως θα γράφαμε στη C int y = x + 10; μπορούμε στη C++ να γράψουμε Date d = Date(31, 3, 1961).advance(x); Τμ. Πληροφορικής, Α.Π.Θ.

  32. Δομητές για αντικείμενα μέλη αντικειμένων • Όλα τα αντικείμενα μιας κλάσης πρέπει να δημιουργηθούν ακόμη και αυτά που περιλαμβάνονται ως μέλη σε άλλες κλάσεις. Employee::Employee(String n, int hd, int hm, int hy) : _name(n), _hiredate(hd, hm, hy) { } Ο δομητής αυτός περνάει παραμέτρους στους δομητές των υποαντικειμένων. Τα πεδία που δεν αναφέρονται ρητά στη λίστα αρχικοποίησης όπως π.χ. το _address αρχικοποιούνται από τον προκαθορισμένο δομητή της κλάσης τους. Τα πεδία που ανήκουν σε κλάση που δεν έχει προκαθορισμένο δομητή πρέπει να αρχικοποιηθούν ρητά, αλλιώς ο μεταγλωττιστής θα βγάλει λάθος. Τμ. Πληροφορικής, Α.Π.Θ.

  33. Ο καλός προγραμματιστής . . . • Κάνει πάντα τα δεδομένα μέλη private • Τα πεδία δεδομένων προτιμάει να είναι κλάσεις και όχι απλοί τύποι παράδειγμα κακής σχεδίασης: class Emplyee { public: // . . . private: String _lname; String _fname; char _middle_initial; String _street; String _city; String _state; long _zip; // . . . }; Τμ. Πληροφορικής, Α.Π.Θ.

  34. Ο καλός προγραμματιστής . . . παράδειγμα καλής σχεδίασης class Name { public: // . . . private: String _lname; String _fname; char _middle_initial; // . . . }; class Address class Employee { { public: public: // . . . // . . . private: private: String _street; Name _name; String _city; Address _address; String _state; Date _hiredate; long _zip; // . . . // . . . }; }; Τμ. Πληροφορικής, Α.Π.Θ.

  35. Ο καλός προγραμματιστής . . . • Δεν είναι απαραίτητες συναρτήσεις προσπέλασης και αλλαγής τιμής για όλα τα πεδία. • Να δηλώνονται οι συναρτήσεις προσπέλασης ως const. • Να υιοθετείται ένα standard στυλ ορισμού κλάσεων για να επιτυγχάνεται ικανοποιητική αναγνωσιμότητα. Π.χ. βάζουμε πρώτα το public μέρος, μετά το private μέρος, στο public μέρος αναφέρουμε πρώτα τους δομητές, μετά τις συναρτήσεις αλλαγής τιμής και τέλος τις συναρτήσεις προσπέλασης τιμής και στο private μέρος βάσουμε πρώτα τις συναρτήσεις και μετά τα δεδομένα μέλη • Δεν παραλείπει ποτέ να δηλώσει έναν προκαθορισμένο δομητή • Δημιουργεί όλα τα υποαντικείμενα πριν από το σώμα του δομητή. Τμ. Πληροφορικής, Α.Π.Θ.

  36. Κληρονομικότητα Ι Παράδειγμα class Point { public: Point(double x=0, double y=0); void move(int dx, int dy); void scale(Point center, double scalefactor); double x() const; double y() const; void plot(GraphicsContext&) const; void print(ostream&) const; // . . . private: double _x; double _y;} Τμ. Πληροφορικής, Α.Π.Θ.

  37. Κληρονομικότητα ΙI class Polygon { public: Polygon(int); void set_vertex(int i, Point p); void move(double dx, double dy); void scale(Point center, double s); void plot(GraphicsContext& gc) const; Point vertex(int) const; // . . . private: Array<Point> _vertex; }; Τμ. Πληροφορικής, Α.Π.Θ.

  38. Κληρονομικότητα ΙII class Triangle : public Polygon { public: Triangle(Point, Point, Point); }; βασική κλάση από την οποία κληρονομεί παράγωγη κλάση Τμ. Πληροφορικής, Α.Π.Θ.

  39. Κληρονομικότητα ΙII Triangle::Triangle(Point a, Point b, Point c) : Polygon(3) { set_vertex(1,a); set_vertex(2, b); set_vertex(3, c); }; • Η παράγωγη κλάση μπορεί να κληρονομήσει τη συνάρτηση B::f() χωρίς αλλαγή. • Η παράγωγη κλάση μπορεί να αντικαταστήσει την B::f() με τη συνάρτηση D::f() που θα κάνει μια διαφορετική λειτουργία. • Η παράγωγη κλάση μπορεί να επεκτείνει την B::f() με την D::f() να καλεί την B::f() και να κάνει και κάποιες επιπλέον λειτουργίες. Τμ. Πληροφορικής, Α.Π.Θ.

  40. Κληρονομικότητα ΙV Επέκταση συνάρτησης – παράδειγμα void ScalableText::scale(Point center, double s) { Text::scale(center, s); _size = _size * s; } Αντικατάσταση συνάρτησης - παράδειγμα class Triangle : public Polygon { public: Triangle(Point, Point, Point); void print(ostream& os) const; }; void Triangle::print(ostream& os) const { . . . . . . . . . } Τμ. Πληροφορικής, Α.Π.Θ.

  41. Πολλαπλή κληρονομικότητα Ι int GetRadius(){ return radius; } int GetXCenter(){ return X_center; } int GetYCenter(){ υπερφόρτωση return Y_center; τελεστή ++ } void Paint(){ circle(X_center, Y_center, radius); } void operator++(){ radius++; X_center++; Y_center++; } }; //Παράδειγμα πολλαπλής κληρονομικότητας #include <graphics.h> class Circle { int X_center, Y_center; int radius; public: Circle(int x, int y, int r=20){ X_center=x; Y_center=y; radius=r; } void SetCenter(int x, int y){ X_center=x; Y_center=y; } void SetRadius(int r){ radius=r;} Τμ. Πληροφορικής, Α.Π.Θ.

  42. Πολλαπλή κληρονομικότητα ΙΙ class ColorCircle:public Circle, Color { public: ColorCircle(int x, int y, int r=20, COLORS c=RED): Circle(x, y, r), Color(c); {} void Paint(){ setcolor(GetCol()); Circle::Paint(); } }; //Παράδειγμα (ΣΥΝΕΧΕΙΑ) enum COLORS { BLACK, BLUE, GREEN, CYAN, ..., WHITE}; class Color { COLORS color; public: Color(COLORS c=BLACK){ color=c; } COLORS GetCol(){ return color; } void SetCol(COLORS c){ color=c; } COLORS operator++(){ color= COLORS((color+1)%getmaxcolor()); } }; Circle Color ColorCircle Τμ. Πληροφορικής, Α.Π.Θ.

  43. Πολλαπλή κληρονομικότητα ΙΙI A A class A; class B1: public A; class B2: public A; class C: public B1, public B2; B1 B2 Ο μεταγλωττιστής δημιουργεί δύο αντίγραφα της κλάσης A. Πρόβλημα: αν στην κλάση A υπάρχει ο ορισμός public: int data; τότε για να προσπελασθεί η data μέσα από τη C θα πρέπει να αναφερθεί ως B1::data, αλλιώς η έκφραση θα είναι ασαφής C Τμ. Πληροφορικής, Α.Π.Θ.

  44. Πολλαπλή κληρονομικότητα ΙV A class A; class B3: virtual public A; class B4: virtual public A; class C: public B3, public B4; B3 B4 ΠΑΡΑΔΕΙΓΜΑΤΑ: D Person Person Person Professor Author Man Woman Professor-Author Married Couple Τμ. Πληροφορικής, Α.Π.Θ.

  45. Σχέση κληρονομικότητας Ένα αντικείμενο κλάσης A έχει ένα αντικείμενο κλάσης Β. Τοαντικείμενο κλάσης Β δηλώνεται ως μέλος της κλάσης Α. Ένα αντικείμενο κλάσης Β είναι κλάσης Α. Η κλάση Β κληρονομεί από την κλάση Α. ΠΑΡΑΔΕΙΓΜΑΤΑ: Ένα τετράγωνο είναι παραλληλόγραμμο. Η γενέθλια ημερομηνία είναι μία ημερομηνία. Ένα άτομο έχει μία διεύθυνση και μία γενέθλια ημερομηνία. Τμ. Πληροφορικής, Α.Π.Θ.

  46. Κανόνες συμβατότητας τύπων I Δύο μεταβλητές είναι συμβατές κατά τύπο αν το όνομα των τύπων και των δύο είναι το ίδιο. Εξαίρεση: ένας δείκτης σε υπερκλάση είναι συμβατός με οποιοδήποτε δείκτη σε κλάση που προέρχεται από αυτή (υποκλάση). #include <iostream.h> void main() { typedef struct { char first; char second;} twoChars; twoChars state1; twoChars state2; state1.first=‘M’; state1.second=‘N’; state2=state1; //σωστό: οι μεταβλητές είναι του ίδιου τύπου state2.second++; cout << “Original structure: “ << state1.first << state1.second << endl << “Changed structure: ” << state2.first << state2.second << endl; } Τμ. Πληροφορικής, Α.Π.Θ.

  47. Κανόνες συμβατότητας τύπων IΙ #include <iostream.h> void main() { struct { char first; char second;} state1; struct { char first; char second;} state2; state1.first=‘M’; state1.second=‘N’; state2=state1; //λάθος: οι μεταβλητέςδεν είναι του ίδιου τύπου state2.second++; cout << “Original structure: “ << state1.first << state1.second << endl << “Changed structure: ” << state2.first << state2.second << endl; } Τμ. Πληροφορικής, Α.Π.Θ.

  48. Κανόνες συμβατότητας τύπων IΙΙ #include <iostream.h> void main() { struct { char first; char second;} state1, state2; state1.first=‘M’; state1.second=‘N’; state2=state1; //σωστό: οι μεταβλητέςείναι του ίδιου τύπου state2.second++; cout << “Original structure: “ << state1.first << state1.second << endl << “Changed structure: ” << state2.first << state2.second << endl; } Τμ. Πληροφορικής, Α.Π.Θ.

  49. Κανόνες συμβατότητας τύπων IV void main() { StateCode* pState1; TwoChars* pState2; pState1=new StateCode(‘C’, ‘A’); pState2=new TwoChars(‘H’, ‘I’); pState2=pState1; // ΛΑΘΟΣ pState1=pState2; // ΛΑΘΟΣ } class TwoChars { char first; char second; public: TwoChars(char f,char s){ first=f; second=s; } }; class StateCode { char first; char second; public: StateCode(char f,char s){ first=f; second=s; } }; Τμ. Πληροφορικής, Α.Π.Θ.

  50. Κανόνες συμβατότητας τύπων V void main() { StateCode* pState1; TwoChars* pState2; pState1=new StateCode(‘C’, ‘A’); pState2=new TwoChars(‘H’, ‘I’); pState2=pState1; // ΣΩΣΤΟ pState1=pState2; // ΛΑΘΟΣ pState2=new StateCode(‘A’, ‘R’); } class TwoChars { char first; char second; public: TwoChars(char f,char s){ first=f; second=s; } }; class StateCode:public TwoChars { public: StateCode(char f,char s): TwoChars(f, s) {} }; Τμ. Πληροφορικής, Α.Π.Θ.

More Related