Αντικειμενοστρεφής Προγραμματισμός ΚΛΑΣΕΙΣ ΙΙ
Υπερφόρτωση (Overloading) Όταν το ίδιο όνομα συνάρτησης (μεθόδου) χρησιμοποιείται για περισσότερες από μία συναρτήσεις (μεθόδους) τότε το όνομα θεωρείται υπερφορτωμένο. Στη C++ τα ονόματα των συναρτήσεων μπορεί να υπερφορτωθούν, δεδομένου ότι οι τύποι των παραμέτρων είναι διαφορετικοί. Για παράδειγμα μπορείτε να δηλώσετε δύο συναρτήσεις: void print(Employee e) /*……………*/ void print(Time t)/*……………*/ Όταν καλείται η συνάρτηση print(x) ο μεταγλωττιστής αποφασίσει βάσει του τύπου των ορισμάτων ποια συνάρτηση θα καλέσει. Αν και είναι καλό να χρησιμοποιούνται διαφορετικά ονόματα για τις μεθόδους μιας κλάσης, η υπερφόρτωση είναι αναγκαία στην περίπτωση πολλών κατασκευαστών. Επιπλέον στη C++ υπάρχει η δυνατότητα υπερφόρτωσης τελεστών (+, ==, <<) αρκεί ένας από τους τελεστέους να είναι αντικείμενο κάποιας κλάσης.
Σταθερά (const) αντικείμενα και μέθοδοι Principle of least priviledge -Στα αντικείμενα πρέπει να δίνονται μόνο τα δικαιώματα που χρειάζονται, και όχι περισσότερα (π.χ. ορισμένα αντικείμενα πρέπει να είναι τροποποιήσιμα και άλλα όχι) Προσδιοριστής const -Προσδιορίζει ότι ένα αντικείμενο δεν μπορεί να τροποποιηθεί - Οποιαδήποτε απόπειρα τροποποίησης είναι συντακτικό λάθος - Παράδειγμα: const Time noon( 12, 0, 0 ); Δηλώνει ένα σταθερό (const) αντικείμενο noon της κλάσης Time και το αρχικοποιεί - Οι μεταγλωττιστές της C++ δεν επιτρέπουν οποιαδήποτε κλήση σε const αντικείμενα, εκτός μέσω μεθόδων που είναι δηλωμένες const
Σταθερά (const) αντικείμενα και μέθοδοι const αντικείμενα απαιτούν const μεθόδους - Οι μέθοδοι που είναι δηλωμένες const δεν μπορούν να τροποποιήσουν το αντικείμενό τους - Ο προσδιοριστής const πρέπει να προστεθεί στη δήλωση της μεθόδου και στον ορισμό της - Πρωτότυπο: ReturnType FunctionName(param1,param2…) const; -Ορισμός: ReturnType FunctionName(param1,param2…) const { …} –Παράδειγμα: int A::getValue() const {return privateDataMember }; Επιστρέφει την τιμή ενός μέλους δεδομένων αλλά δεν τροποποιεί τίποτα και κατά συνέπεια δηλώνεται const - Οι κατασκευαστές δεν μπορούν να είναι const - Χρειάζεται να αρχικοποιούν μεταβλητές και κατά συνέπεια να τις τροποποιούν
Σύνηθες Σφάλμα Όλες οι μέθοδοι πρόσβασης θα πρέπει να δηλώνονται const class Product {... void print() const;... }; Αν δεν τηρηθεί αυτός ο κανόνας πιθανόν να δημιουργηθούν κλάσεις που δεν μπορούν να επαναχρησιμοποιηθούν. Έστω ότι η print δεν δηλώνεται const και κάποιος άλλος προγραμματιστής χρησιμοποιεί την Product: class Order { public: void print() const; private: string customer; Product article; }; void Order::print() const { cout << customer << “\n”; article.print(); //Error if Product:print not const }
Φιλικές Συναρτήσεις (Friend Functions) Φιλικές ( friend) συναρτήσεις και φιλικές κλάσεις – Μπορούν να προσπελάσουν private (και protected) μέλη μιας άλλης κλάσης –Οι friend συναρτήσεις δεν είναι μέθοδοι της κλάσης – Δηλώνονται έξω από το πεδίο εμβέλειας μιας κλάσης – Μπορούν να βελτιώσουν σε ορισμένες περιπτώσεις την ταχύτητα (π.χ. μία φιλική κλάση μπορεί να διατρέξει τα αντικείμενα μιας περικλείουσας (container) κλάσης Ιδιότητες της ‘’φιλίας’’ – Η φιλία παρέχεται, δεν αποκτάται – Μη συμμετρική (αν B είναι friend της A, η A δεν είναι κατ’ ανάγκη friend της B ) – Μή μεταβατική (αν A είναι friend της B, B είναι friend της C, A δεν είναι κατ’ ανάγκη friend της C )
Φιλικές Συναρτήσεις (Friend Functions) Δήλωση φιλικών κλάσεων/συναρτήσεων – Για να δηλωθεί μία friend συνάρτηση Εισαγωγή της δεσμευμένης λέξης friend πριν το πρωτότυπο της συνάρτησης στην κλάση που παρέχει τη φιλία friend int myFunction( int x ); –Για να δηλωθεί μία friend κλάση Εισαγωγή του friend class Classname στην κλάση που παρέχει τη φιλία αν η ClassOne παρέχει φιλία στην ClassTwo, friend class ClassTwo; θα πρέπει να εμφανίζεται στον ορισμό της ClassOne – Για πολλούς στην ΟΟ-κοινότητα, η ‘’φιλία’’ θεωρείται ότι καταστρέφει την ενσωμάτωση και την απόκρυψη πληροφορίας μειώνοντας την αξία του αντικειμενοστραφούς σχεδίου
Στατικά (static) Μέλη Κάθε αντικείμενο μιας κλάσης έχει τα δικά του αντίγραφα των μελών δεδομένων Σε ορισμένες περιπτώσεις ένα μόνο αντίγραφο πρέπει να μοιράζεται μεταξύ όλων των αντικειμένων Video Game with Martians -κάθε Martian γίνεται ‘’δειλός’’ αν οι Martians γίνουν λιγότεροι από 5 - συνεπώς, κάθε Martian πρέπει να γνωρίζει το martianCount - σπατάλη χρόνου/χώρου αν κάθε αντικείμενο Martian έχει δικό του αντίγραφο της martianCount - στην περίπτωση αυτή η martianCount είναι αποδοτικό να δηλωθεί static
Στατικά (static) Μέλη - Παρόλο που μοιάζουν με καθολικές μεταβλητές έχουν πεδίο εμβέλειας την κλάση – Αρχικοποιούνται μία μόνο φορά σε file scope (έξω από οποιαδήποτε συνάρτηση) – Υφίστανται ακόμη και αν δεν υπάρχουν αντικείμενα της κλάσης – Τόσο μεταβλητές όσο και συναρτήσεις μπορεί να είναι static –Μπορούν να είναι public, private ή protected –public static variables Μπορούν να προσπελαστούν χρησιμοποιώντας τον scope resolution operator( :: ) Employee::count –private static variables Αν δεν υπάρχει αντικείμενο της κλάσης, μπορούν να προσπελαστούν μόνο μέσω public static μεθόδου –Για την κλήση μιας public static μεθόδου συνδυάζεται το όνομα της κλάσης, ο τελεστής :: και το όνομα της μεθόδου Employee::getCount()
1 // An employee class 2 #ifndef EMPLOY1_H 3 #define EMPLOY1_H 4 #include 5using namespace std; 6class Employee { 7public: 8 Employee( string, string ); // constructor 9 ~Employee(); // destructor 10 string getFirstName() const; // return first name 11 string getLastName() const; // return last name // static member function 14 static int getCount(); // return # objects instantiated 15 16private: 17 string firstName; 18 string lastName; // static data member 21 static int count; // number of objects instantiated 22}; 23 24#endif Δήλωση static μεθόδου και μεταβλητής
25// Fig. 7.9: employ1.cpp 26// Member function definitions for class Employee 27#include 28 29using std::cout; 30using std::endl; 31 32#include 33 34#include "employ1.h" 35 36// Initialize the static data member 37int Employee::count = 0; 38 39// Define the static member function that 40// returns the number of employee objects instantiated. 41int Employee::getCount() { return count; } 42 43// Constructor dynamically allocates space for the 44// first and last name and uses strcpy to copy 45// the first and last names into the object 46Employee::Employee( string first, string last ) 47{ 48 firstName = first; lastName = last; count; // increment static count of employees 54 cout << "Employee constructor for " << firstName 55 << ' ' << lastName << " called." << endl; 56} Αρχικοποίηση static ιδιότητας count σε file scope (απαιτείται). static ιδιότητα count τροποποιείται όταν καλείται ο constructor
// Return first name of employee 72string Employee::getFirstName() const 73{ 74 return firstName; 75} // Return last name of employee 81string Employee::getLastName() const 82{ 83 return lastName; 84} 85 86
88// Fig. 7.9: fig07_09.cpp 89// Driver to test the employee class 90#include 91 92using std::cout; 93using std::endl; 94 95#include "employ1.h" 96 97int main() 98{ 99 cout << "Number of employees before instantiation is " 100 << Employee::getCount() << endl; // use class name Employee e1( "Susan", "Baker" ); 103 Employee e2( "Robert", "Jones" ); cout << "Number of employees after instantiation is " 106 << e1.getCount(); cout << "\n\nEmployee 1: " 109 << e1.getFirstName() 110 << " " << e1.getLastName() 111 << "\nEmployee 2: " 112 << e2.getFirstName() 113 << " " << e2.getLastName() << "\n\n"; 114 Αν δεν υπάρχουν αντικείμενα Employee η getCount πρέπει να προσπελαστεί με το όνομα της κλάσης και ( :: ). Number of employees before instantiation is 0 e2.getCount() ή Employee::getCount() θα δούλευε επίσης. Employee constructor for Susan Baker called. Employee constructor for Robert Jones called. Number of employees after instantiation is 2Employee 1: Susan Baker Employee 2: Robert Jones count αυξάνεται λόγω της κλήσης του constructor
return 0; 124} Number of employees before instantiation is 0 Employee constructor for Susan Baker called. Employee constructor for Robert Jones called. Number of employees after instantiation is 2 Employee 1: Susan Baker Employee 2: Robert Jones
Σύνθεση: Αντικείμενα ως μέλη δεδομένων Σύνθεση -Μία κλάση μπορεί να έχει αντικείμενα άλλων κλάσεων ως ιδιότητες Παράδειγμα class Date { public: Date(int day, int month, int year); void print() const; private: int month; int day; int year; }; class Employee { public: Employee(string name, int bDay, int bMonth, int bYear); private: string lastName; const Date birthDate; }; Employee::Employee(string name, int bDay,int bMonth, int bYear): birthDate(bDay, bMonth, bYear) { lastName = name; }