10. ΥΠΕΡΦΟΡΤΩΣΗ ΤΕΛΕΣΤΩΝ (OPERATOR OVERLOADING) Ο όρος υπερφόρτωση τελεστών αναφέρεται στην πρόσθετη έννοια που δίνουµε στους συνήθεις τελεστές της C++, όπως οι +,*,<=,+=, όταν εφαρµόζονται σε τύπους οριζόµενους από τον χρήστη. H µετατροπή τύπων δεδοµένων επίσης, είναι στενά συνδεµένη µε την υπερφόρτωση τελεστών. d3.addobjects(d1,d2) d3=d1.addobjects(d2) => d3=d1+d2; 1. Υπερφόρτωση µονοµελών τελεστών (προθέµατος ++, --) c1.inc_count() => ++c1 // 32 Count.cpp class Counter unsigned int count; Counter() : count(0) Counter(int c):count(c) unsigned int get_count() return count; ; void operator ++()//λίστα ορισµάτων - κενή ++count; Counter c1, c2; cout << "\nc1="<< c1.get_count(); cout << "\nc2="<< c2.get_count()<< endl; ++c1; ++c2; ++c2; cout << "\nc1="<< c1.get_count(); cout << "\nc2="<< c2.get_count()<< endl; Ελάττωµα: c1=++c2; // error, γιατί o operator ++ επιστρέφει void => το αλλάζω σε: Counter operator ++() ++count; Counter temp; // προσωρινό αντικείµενο temp.count = count; return temp; ή και κατευθείαν Counter operator ++() VK - page 39
++count; return Counter (count) ; //ανώνυµο αντικείµενο -απαιτεί συνάρτηση δόµησης µε παράµετρο. //ή και return Counter (++count) ; Ή και Counter& operator ++() //ΣΥΝΗΘΩΣ επιστρέφετε αποτέλεσµα κατ αναφορά από //υπερφορτωµένους τελεστές ΑΠΟ ΟΣΗΣ ΤΙΜΗΣ ++count; //χρησιµοποιώντας το *this (για να µην κάνετε και άλλο αντικείµενο) return *this;.//αυτή η παράσταση είναι το ίδιο το αντικείµενο, που επιστρέφεται κατ αναφορά παρεµβολή για ΕΠΙΣΤΡΟΦΗ κατ ΑΝΑΦΟΡΑ : αναντικατάστατο στο OVERLOAD int& change(int x) return x; //επιστρέφει τιµή που θα τροποποιηθεί int main() int i=3; i = change(i); change(i) = 92; λόγοι 1)αποφυγή αντιγραφής µεγάλου αντικειµένου 2)κλήση συνάρτησης στα αριστερά του = 2. Υπερφόρτωση µονοµελών τελεστών (επιθέµατος ++, --) // 33 CountPostfix.cpp class Counter unsigned int count; Counter() : count(0) Counter(int c):count(c) unsigned int get_count()const return count; /*void operator ++()//λίστα ορισµάτων - κενή ++count; */ Counter operator ++() //ΠΡΟΘΕΜΑΤΙΚΗ return Counter(++count); ; Counter operator ++(int) //ΕΠΙΘΕΜΑΤΙΚΗ - ΤΟ ΙΝΤ ΕΝ ΕΙΝΑΙ ΟΡΙΣΜΑ //ειναι σήµα για να δηµιουργηθεί η επιθεµατική εκδοχή return Counter(count++); Counter c1, c2; cout << "\nc1="<< c1.get_count(); cout << "\nc2="<< c2.get_count()<< endl; ++c1; c2=++c1; cout << "\nc1="<< c1.get_count(); VK - page 40
cout << "\nc2="<< c2.get_count()<< endl; c2=c1++; cout << "\nc1="<< c1.get_count(); cout << "\nc2="<< c2.get_count()<< endl; 3.Υπερφόρτωση διµελών τελεστών (+,-,..) // 34 Distance.cpp class Distance int feet; //Eνα πόδι 12 ίντζες float inches; Distance() : feet(0), inches(0.0) Distance(int ft,float in) : feet(ft), inches(in) void getdist() cout << "\nenter feet: "; cin >> feet; cout << "Enter inches: "; cin >> inches; void showdist(void) const cout << feet << "\'-" << inches << '\"'; ; Distance operator + (Distance)const; Distance Distance::operator + (Distance d2) const int f = feet + d2.feet; float i = inches + d2.inches; if(i >= 12.0) i -= 12.0; //µείωση ιντζών κατά 12 f++; //αύξηση ποδιών κατά 12 return Distance(f, i); //επιστροφή ανωνύµου Distance dist1, dist3, dist4; dist1.getdist(); Distance dist2(11, 6.25); //Το όρισµα αριστερά του τελεστή είναι το αντικείµενο του οποίου ο τελεστής είναι µέλος δηλαδή το dist1. dist3 = dist1 + dist2; VK - page 41
dist4 = dist1 + dist2 + dist3; cout << "\ndist1 = "; dist1.showdist(); cout<< endl; cout << "dist2 = " ; dist2.showdist(); cout<< endl; cout << "\ndist3 = "; dist3.showdist(); cout<< endl; cout << "dist4 = " ; dist4.showdist(); cout<< endl; 4.Υπερφόρτωση τελεστών σύγκρισης (<,==, ) bool operator < (Distance d2) const float bf1 = feet + inches / 12 ; float bf2 = d2.feet + d2.inches / 12 ; return (bf1 < bf2)? true : false; main. cout << "\ndist1 = " ; dist1.showdist(); cout << "\ndist2 = " ; dist2.showdist(); if (dist1 < dist2) cout << "\ndist1 is less than dist2\n"; else cout << "\ndist1 is greater than (or equal to) dist2\n"; 5. Αριθµητικοί συντελεστές απόδοσης τιµής (+=, -=,..) void operator += (Distance d2) feet +=d2.feet; inches +=d2.inches; if (inches>= 12.0) inches -=12; feet++; main. cout << "\ndist1 = " ; dist1.showdist(); cout << "\ndist2 = " ; dist2.showdist(); dist1 += dist2 ; cout << "\ndist1 after addition "; dist1.showdist();.. 6. O τελεστής αριθµοδείκτη [] // 35 Array.cpp παράδειγµα αν δεν υπερφόρτωνα.. #include <process.h> const int LIMIT = 100; class Safearay VK - page 42
int arr[limit]; void putel(int n, int elvalue) if(n < 0 n >= LIMIT) cout << "\nindex out of bounds"; exit(1); arr[n] = elvalue; ; int getel(int n) const if(n < 0 n >= LIMIT) cout << "\nindex out of bounds"; exit(1); return arr[n]; Safearay sa1; int j; for(j = 0; j < LIMIT; j++) sa1.putel(j, j * 10); for(j = 0; j < LIMIT; j++) int temp = sa1.getel(j); cout << "Element "<< j<< " is "<< temp<< endl; Μπορούµε να χρησιµοποιήσουµε την ίδια συνάρτηση µέλος για να προσθέτουµε και να διαβάζουµε δεδοµένα στον ασφαλή πίνακα, επιστρέφοντας την τιµή από την συνάρτηση κατ αναφορά. // 36 ArrayRef.cpp #include <process.h> //για την exit() const int LIMIT = 10; class Safearay int arr[limit]; int& access(int n) //& έχω την κλήση της συνάρτησης αριστερά του = if(n < 0 n >= LIMIT) cout << "\nindex out of bounds"; exit(1); return arr[n]; VK - page 43
; Safearay sa1; int j; for(j = 0; j < LIMIT; j++) sa1.access(j)= j * 10;// κλήση αριστερά του = for(j = 0; j < LIMIT; j++) int temp = sa1.access(j); //κανονική κλήση cout << "Element "<< j<< " is "<< temp<< endl; Υπερφόρτωση του αριθµοδείκτη κατ αναφορά // 36 ArrayRefOper.cpp #include <process.h> //για την exit() const int LIMIT = 100; class Safearay int arr[limit]; int& operator [](int n) if(n < 0 n >= LIMIT) cout << "\nindex out of bounds"; exit(1); return arr[n]; ; Safearay sa1; for(int j = 0; j < LIMIT; j++) sa1[j]=j * 10; for(int j = 0; j < LIMIT; j++) int temp = sa1[j]; cout << "Element "<< j<< " is "<< temp<< endl; Μετατροπές µεταξύ βασικών τύπων π.χ. intvar=static_cast<int>(floatvar) //ρητή µετατροπή Μετατροπές µεταξύ αντικειµένων και βασικών τύπων π.χ. µετατροπή του τύπου Distance σε float // 37 ConvDistance.cpp VK - page 44
class Distance const float MTF; int feet; float inches; Distance() : feet(0),inches(0.0),mtf(3.280833f) //χωρίς ορίσµατα Distance(float meters) : MTF(3.280833F) //ένα όρισµα float fltfeet = MTF * meters; feet = int(fltfeet); inches = 12 * (fltfeet - feet); //δυο ορίσµατα Distance (int ft,float in) : feet(ft),inches(in), MTF(3.280833F) void getdist() //λήψη µήκους από τον χρήστη cout << "\nenter feet: "; cin >> feet; cout << "Enter inches: "; cin >> inches; void showdist() const //εµφάνιση απόστασης cout << feet << "\'-"<< inches<< '\"'; ; operator float() const float fracfeet = inches / 12; //µετατροπή Distance σε float fracfeet += static_cast<float>(feet); return fracfeet / MTF; float mtrs; Distance dist1 = 2.35F; cout << "\ndist1 = "; dist1.showdist(); mtrs = static_cast<float>(dist1); cout << "\ndist1 = "<< mtrs<< " meters\n"; Distance dist2(5, 10.25); mtrs = dist2; cout << "\ndist2 = "<< mtrs<< " meters\n"; Ρουτίνα µετατροπής που βρίσκεται στην κλάση προέλευσης π.χ. από 24ωρο 23:59 σε 12ωρο 11:59pm // 38 Times12.cpp #include <string> class Time12 VK - page 45
bool pm; int hrs; int mins; Time12() : pm(true),hrs(0), mins(0) Time12(bool ap, int h, int m) : pm(ap),hrs(h), mins(m) ; void display()const // µορφή 11:59 p.m cout << hrs << ':'; if(mins < 10) cout << '0';//επιπλέον µηδενικό για το "01" cout << mins << ' '; string am_pm = pm? "p.m." : "a.m."; cout << am_pm; class Time24 int hours; int minutes; int seconds; Time24() : hours(0), minutes(0), seconds(0) Time24(int h, int m, int s) : hours(h), minutes(m), seconds(s) void display()const // µορφή 23:15:01 if(hours < 10) cout << '0'; cout << hours << ':'; if(minutes < 10) cout << '0'; cout << minutes << ':'; if(seconds < 10) cout << '0'; cout << seconds; ; operator Time12()const;//τελεστής µετατροπής Time24::operator Time12()const int hrs24 = hours; bool pm = hours < 12? false : true; // εύρεση am/pm int roundmins = seconds < 30? minutes : minutes + 1; //κρατούµενο στα λεπτά if(roundmins == 60) roundmins = 0; ++hrs24; if(hrs24 == 12 hrs24 == 24)//κρατούµενο στις ώρες pm = (pm == true)? false : true; // εναλλαγή µεταξύ am/pm int hrs12 = (hrs24 < 13)? hrs24 : hrs24-12; if(hrs12 == 0) // 00 είναι 12 a.m VK - page 46
hrs12 = 12; pm = false; return Time12(pm, hrs12, roundmins); int h, m, s; char ch; while(true) cout << "Enter 24-hour time: Hours, Mins, Secs\n"; cout << " Hours(0-23): "; cin >> h; // Λήψη ώρας από τον χρήστη σε 24ωρη µορφή if(h > 23) //τερµατισµός αν οι ώρες >23 return(1); cout << " Minutes : "; cin >> m; cout << " Seconds : "; cin >> s; Time24 t24(h, m, s);//δηµιουργία ώρας σε µορφή Time24 cout << "You entered "; t24.display();//εµφάνιση σε Time24 Time12 t12 = t24;// Μετατροπή από time24 σε time12 cout << "\n12hour time ";// Εµφάνιση ισοδύναµης ώρας t12.display(); cout << "\n\n"; cout<<"kai ALLH METATROPH (y/n)?:"; cin>>ch; if (ch=='n') break; εν µπορούν να υπερφορτωθούν όλοι οι τελεστές: τελεία(.), επίλυσης εµβέλειας(::), συνθήκης(?:),δείκτης µέλους(->) εν µπορούν να δηµιουργηθούν νέοι τελεστές και να υπερφορτωθούν κατόπιν. VK - page 47
11. ΚΛΗΡΟΝΟΜΙΚΟΤΗΤΑ (ΙΝΗΕΡΙΤΑΝCE) H πιο ισχυρή λειτουργία του ΑΠ, είναι η διαδικασία της δηµιουργίας νέων κλάσεων, που καλούνται παράγωγες κλάσεις (derived) από τις υπάρχουσες ή βασικές κλάσεις(base). Eπιτρέπει την ανακύκλωση του κώδικα. Ευκολία στη διανοµή ββλιοθηκών κλάσεων. //41 CountBase.cpp class Counter //base class protected: unsigned int count; Counter() : count(0) Counter(int c) : count(c) unsigned int get_count() const return count; ; Counter operator ++()//προθεµατική return Counter(++count); class CountDn : public Counter //derived class CountDn() : Counter() CountDn(int c) : Counter(c) ; CountDn operator --() return CountDn(--count); CountDn c1; CountDn c2(100); cout << "\nc1="<< c1.get_count(); cout << "\nc2="<< c2.get_count()<< endl; ++c1;++c1;++c1; cout << "\nc1="<< c1.get_count(); --c2;--c2; cout << "\nc2="<< c2.get_count()<< endl; CountDn c3 = --c2; // ηµιουργία c3 από c2 cout << "\nc3="<< c3.get_count()<< endl; VK - page 48
Προσδιοριστικό στην στην δηµόσια έξω από ιδιωτικά έξω Πρόσβασης κλάση του παράγωγη κλάση παράγωγη public ναι ναι ναι ναι όχι protected ναι ναι όχι ναι όχι private ναι όχι όχι όχι όχι Οι συναρτήσεις στις παράγωγες κλάσεις µπορούν να προσπελάσουν προστατευόµενα και δηµόσια µέλη της βασικής κλάσης. Τα αντικείµενα της παράγωγης κλάσης δεν µπορούν να προσπελάσουν προστατευόµενα και ιδιωτικά µέλη της βασικής κλάσης. Τα αντικείµενα της παράγωγης κλάσης που παράγονται δηµόσια µπορούν να προσπελάσουν δηµόσια µέλη της βασικής κλάσης Τα αντικείµενα της παράγωγης κλάσης που παράγονται ιδιωτικά δεν µπορούν να προσπελάσουν δηµόσια µέλη της βασικής κλάσης. // 42 Staken.cpp - ΥΠΕΡΣΚΕΛΙΣΗ ΣΥΝΑΡΤΗΣΕΩΝ ΜΕΛΩΝ #include <process.h> //exit () class Stack protected: enum MAX = 3; int st[max]; //στοίβα :Πίνακας ακεραίων int top; //κορυφή της στίβας Stack() top = -1; void push(int var) //βάζω αριθµό st[++top] = var; VK - page 49
; int pop() //βγάζω αριθµό return st[top--]; class Stack2 : public Stack void push(int var) cout<<var<<endl; if(top >= MAX - 1) cout << "\nerror: stack"<< " is full\n"; exit(1); Stack::push(var); ; int pop() if(top < 0) cout << "\nerror: stack is" << " empty\n"; exit(1); return Stack::pop(); Stack2 s1; s1.push(11); //? Ποια push s1.push(22); s1.push(33); //s1.push(99); cout << endl << s1.pop(); cout << endl << s1.pop(); cout << endl << s1.pop(); cout << endl << s1.pop(); cout << endl; Ποια push χρησιµοποιεί ο µεταγλωτιστής? Όταν υπάρχει η ίδια συνάρτηση και στην βασική και στην παράγωγη κλάση, τότε εκτελείται η συνάρτηση της παράγωγης κλάσης. (αυτό ισχύει για τα αντικείµενα της παράγωγης κλάσης, γιατί τα αντικείµενα της βασικής δεν γνωρίζουν τίποτα για την παράγωγη κλάση). Τότε λέµε ότι η συνάρτηση της παράγωγης κλάσης υπερσκελίζει (override) την βασική. Πως µπορούν να χρησιµοποιηθεί η push της βασικής κλάσης? Stack::push(var). Με τον τελεστή επίλυσης εµβέλειας. VK - page 50
ΙΕΡΑΡΧΙΕΣ ΚΛΑΣΕΩΝ Υπάλληλοι εταιρείας κατασκευής συσκευών (εδώ έστω 3 µόνο κατηγορίες) εν ορίζεται αντικείµενο της κλάσης υπάλληλος (employee) Tην χρησιµοποιούµε ως γενική κλάση µε µόνο σκοπό να παράγει τις άλλες (η κλάση laborer -εργάτης λειτουργεί όµοια µε την employee δεν έχει επιπλέον data). Η κλάση employee ονοµάζεται αφηρηµένη (χρησιµοποιείται µόνο για να παράγει άλλες κλάσεις και δεν δηµιουργούνται αντικείµενα αυτής). ΕΠΙΠΕ Α ΚΛΗΡΟΝΟΜΙΚΟΤΗΤΑΣ π.χ. η κλάση foreman (εργοδηγός - είναι ένα είδος εργατών), παράγεται από τους εργάτες. VK - page 51
ΠΟΛΛΑΠΛΗ ΚΛΗΡΟΝΟΜΙΚΟΤΗΤΑ class employee..; class student //σχολείο, βαθµό..; class laborer: public employee..; class scientist: private employee, private student // private πρόσβαση αν π.χ. αντικ/να δεν καλούν ρουτίνες που ανήκουν στις βασικές κλάσεις..; class manager: private employee, private student..; Πρόβληµα στην πολλαπλή κληρονοµικότητα η αµφισηµία δηλ. Όταν υπάρχει η ίδια συνάρτηση σε δυο βασικές και η παραγόµενη (και από τις δυο) κλάση, δεν έχει συνάρτηση µε το ίδιο όνοµα Ποια συνάρτηση να χρησιµοποιήσει ο µεταγλωττιστής? Όταν παράγουµε µια κλάση από δύο άλλες κλάσεις και κάθε µία απ αυτές παράγεται από την ίδια κλάση (σχήµα ρόµβου) πια διαδροµή θα χρησιµοποιήσει ο µεταγλωττιστής? Λύση :: ο τελεστής επίλυσης εµβέλειας VK - page 52