12. ΑΛΦΑΡΙΘΜΗΤΙΚΑ υο είδη αλφαριθµητικών Τα αλφαριθµητικά της C πίνακες τύπου char Ta αντικείµενα της κλάσης string Aλφαριθµητικά της C int main() const int max=80; char str[max); //κάθε char δεσµεύει ένα byte cin>>str; Πρέπει να τελειώνουν µε ένα byte µε τιµή 0 που αναπαρίσταται µε το χαρακτήρα \0 null character Αλφαριθµητικές σταθερές οριοθετούνται µε διπλά εισαγωγικά char str[]= Trala la la alpharithmitika //αντί char str[]= T, r, a,.. Ανάγνωση ενσωµατωµένων κενών µε την cin.get () Ο τελεστής εξαγωγής >> θεωρεί το κενό διάστηµα σαν τελικό χαρακτήρα. Για να διαβάσουµε κείµενο µε κενά διαστήµατα χρησιµοποιούµε την cin::get() char str[max); cin.get(str,max); Ανάγνωση πολλών γραµµών µε την cin.get () και τρίτο όρισµα To τρίτο όρισµα καθορίζει τον χαρακτήρα που σταµατά η ανάγνωση. char str[max); cin.get(str,max, $ );//µόλις πατήθεί το $, σταµατά η ανάγνωση Υπάρχουν συναρτήσεις βιβλιοθήκης (#include <cstring>) για την επεξεργασία τους π.χ. char dest[80],source[80]= Trala lo ; strcpy(dest,source); //δεν µπορώ να γράψω κατευεθείαν dest=source Η κλάση string της standard C++ Αναλαµβάνει όλη την διαχείριση της µνήµης Επιτρέπει την υπερφόρτωση των τελεστών π.χ. s3=s1+s2 //s1,s2,s3 strings int main() string s1( Man ); string s2= Women ; string s3; s1=s2; // απόδοση τιµής s3+=s2; s1.swap(s2); cout<<s3; cout<<endl; H κλάση string βελτιώνει τα παραδοσιακά αλφαριθµητικά της C. εν υπάρχει το θέµα δηµιουργίας πίνακα κατάλληλου µεγέθους (η κλάση διαχειρίζεται την µνήµη). VK - page 53
Είναι πιο αποδοτική και πιο ασφαλής. Η κλάση string xρησιµοποιεί overloaded τελεστές. Ανάγνωση ενσωµατωµένων κενών µε την getline (cin,str) string str; getline(cin,str, $ ); Υπάρχουν συναρτήσεις βιβλιοθήκης (#include <string>) για την επεξεργασία τους π.χ. string s= Tra la la lo ; int n; n=s.find( la ); //βρίσκει την θέση του la s.erase(0,2); //από την θέση µηδεν σβύνει 2 χαρακτήρες s.replace(3,2, lo ); //από την θέση τρία αντικατέστησε 2 χαρακτήρες µε το lo s.append( la ); //προσάρτηση του la s.insert(s.size()-3, Oh ); //προσθήκη στην θέση size()-1, του Oh cout<<s; ====================================================================== Virtual functions Friend functions Static functions Overloaded assignment operator Overloaded copy constructor The this pointer 13. ΕΙΚΟΝΙΚΕΣ ΣΥΝΑΡΤΗΣΕΙΣ (VIRTUAL FUNCTIONS) Eικονική: αν και φαίνεται να υπάρχει, δεν είναι σε ισχύ. // 43Virt.cpp class Base void show() // virtual void show() cout << "Base\n"; ; class Derv1 : public Base void show() cout << "Derv1\n"; ; Base* ptr; //δείκτης προς την βασική κλάση Derv1 dv1; ptr = &dv1; ptr -> show(); //ο δείκτης της βασικής κλάσης δείχνει στην παράγωγη VK - page 54
ptr = &dv1; Επιτρέπεται αυτό? ΝΑΙ οι δείκτες προς αντικείµενα µιας παράγωγης κλάσης είναι συµβατοί µε δείκτες προς αντικείµενα της βασικής κλάσης. ptr -> show(); Ποια συνάρτηση θα εκτελεστεί? Η συνάρτηση «επιλέγει» την συνάρτηση που συµφωνεί µε τον τύπο του δείκτη. Εκτός και αν γράψω virtual void show() οπότε εκτελείται η συνάρτηση της παράγωγης. Τότε επιλέγεται η συνάρτηση µε βάση τα περιεχόµενα του δείκτη και όχι τον τύπο του. Dynamic binding (δυναµική σύνδεση): κατά την εκτέλεση του προγράµµατος γίνεται η επιλογή συνάρτησης (και όχι κατά την διάρκεια της µεταγλώτισσης στατική σύνδεση). Όταν δεν δηµιουργούνται αντικείµενα της βασικής κλάσης τότε η κλάση ονοµάζεται αφηρηµένη. Αυτό γίνεται όταν στην βασική κλάση τοποθετήσουµε τουλάχιστον µία γνήσια εικονική συνάρτηση στη δήλωση της οποίας έχει προστεθεί η παράσταση = 0, δηλαδή: virtual void show()=0 Εικονικές συναρτήσεις ΑΠΟ ΟΜΗΣΗΣ Παρεµβολή: ιαχείρηση µνήµης µε new και delete O τελεστής new αποκτά µνήµη από το λειτουργικό σύστηµα και επιστρέφει ένα δείκτη προς την αρχή αυτού του µπλόκ µνήµης. Base* pbase; pbase =new Derv; Ο τελεστής new συνοδεύεται από τον αντίστοιχο τελεστή delete που επιστρέφει την µνήµη που δέσµευσε ο δείκτης. delete pbase; (Γενικά, η µνήµη επιστρέφεται όταν τελειώνει το πρόγραµµα. Σε µια συνάρτηση όµως µε τοπικό δείκτη, ο δείκτης στο τέλος της συνάρτησης καταστρέφεται και η µνήµη παραµένει ορφανή..) Οι συναρτήσεις αποδόµησης των βασικών κλάσεων πρέπει να είναι πάντα εικονικές. Στο παράδειγµα παρακάτω αν ο αποδοµητής δεν ήταν εικονικός η εντολή delete θα καλούσε την συνάρτηση αποδόµησης µόνο της βασικής κλάσης. // 44 Vertdest.cpp class Base /* ~Base(void) //µη εικονικός cout << "Base destroyed\n";*/ //Base destroyed ; virtual ~Base() //EIKONIKOΣ ΑΠΟ ΟΜΗΤΗΣ cout << "Base destroyed\n";//base destroyed //Derv destroyed VK - page 55
class Derv : public Base ~Derv() cout << "Derv destroyed\n"; ; int main() Base* pbase = new Derv; //δέσµευση µνήµης για αντικείµενο τύπου Derv delete pbase; Εικονικές βασικές ΚΛΑΣΕΙΣ Στη παραπάνω διάταξη-ρόµβος, για να λυθεί το - όταν µια συνάρτηση µέλος της κλάσης GrandChild θελήσει να προσπελάσει δεδοµένα ή συναρτήσεις της κλάσης Parent (εκτός από την λύση του τελεστή επίλυσης εµβέλειας ::) µετατρέπω τις δύο παράγωγες (Child1, Child2) σε εικονικές, οπότε υποχρεώνονται να χρησιµοποιούν ένα µόνο κοινό αντίγραφο-υποαντικείµενο της κλάσης Parent. // 45 NormBase.cpp class Parent protected: int basedata; ; class Child1 : virtual public Parent; class Child2 : virtual public Parent; class Grandchild : public Child1, public Child2 int getdata() return basedata ;//Child1::basedata; ; ABSTRACT κλάση Όταν δεν πρόκειται να δηµιουργηθούν ποτέ αντικείµενα της βασικής κλάσης την ονοµάζουµε αφηρηµένη -abstract (π.χ. βασική (αφηρηµένη) σχήµα, παράγωγες κύκλος, τρίγωνο..) Γνήσια Εικονική συνάρτηση Μια γνήσια εικονική συνάρτηση είναι αυτή που στην δήλωσή της έχει προστεθεί η παράσταση =0 Χρησιµοποιείται σε µια βασική κλάση για να την κάνει αφηρηµένη VK - page 56
14. ΦΙΛΕΣ ΣΥΝΑΡΤΗΣΕΙΣ (FRIEND FUNCTIONS) Οι συναρτήσεις που δεν είναι µέλη δεν µπορούν να προσπελάσουν private ή protected δεδοµένα ενός αντικειµένου. Οι φίλες συναρτήσεις λειτουργούν σαν «γέφυρες» µεταξύ δυο κλάσεων, δυνάµενες να προσπελάσουν τα ιδιωτικά τους µέλη. Τότε η φίλη συνάρτηση πρέπει να δηλωθεί και στις δύο κλάσεις µε την λέξη friend. Αυτή η δήλωση µπορεί να τοποθετηθεί σε οποιοδήποτε σηµείο µέσα στην κλάση (public ή private) // 46 Friend.cpp class Beta;//πρόσθια δήλωση class Alpha Alpha() : data(3) friend int frifunc(alpha a, Beta b); ; class Beta Beta() : data(7) friend int frifunc(alpha a, Beta b); ; // Φίλη συνάρτηση γέφυρα ανάµεσα στις Alpha και Beta int frifunc(alpha a, Beta b) return (a.data + b.data ); int main() Alpha aa; Beta bb; cout << frifunc(aa, bb) << endl; Ο υπερφορτωµένος τελεστής + µπορεί να µετατραπεί σε φίλη συνάρτηση τότε όµως θα δέχεται δυο ορίσµατα. π.χ. για την κλάση Distance //47 friendplus.cpp class Distance Distance(float feet) //συνάρτηση δόµησης που µετατρέπει float σε distance friend Distance operator + (Distance, Distance); //δήλωση φίλης VK - page 57
; Distance operator + (Distance d1, Distance d2) int f = d1.feet + d2.feet; float i = d1.inches + d2.inches; if (i >= 12.0) i -= 12.0; f++; return Distance(f, i); int main() Distance d1=2.5, d2=1.25, d3; d3=d1+10.0; //εντολή εφικτή cout<< "\nd3=" ; d3.showdist(); d3=10.0+d1; //στα αριστερά του + έχω float, αυτό δεν θα λειτουργούσε χωρίς την φίλη. cout<< "\nd3=" ; d3.showdist(); cout<<endl; system( "PAUSE" ) ; Φίλες ΚΛΑΣΕΙΣ // 48 Friclass.cpp class Alpha Alpha() : data(99) friend class Beta; ; class Beta void func(alpha a) cout << "\ndata= " <<a.data<<endl; ; Alpha a; Beta b; b.func(a); Τότε όλες οι συναρτήσεις-µέλη της κλάσης Βeta είναι φίλες και µπορούν να προσπελάσουν τα ιδιωτικά δεδοµένα της alpha. VK - page 58
15. ΣΤΑΤΙΚΕΣ ΣΥΝΑΡΤΗΣΕΙΣ (STATIC FUNCTIONS) // 49 Statfunc.cpp class Gamma static int total; //στατική µεταβλητή int id; Gamma() total++; id = total; ~Gamma() total--; cout << "Destroying ID number " << id << endl; static void showtotal() cout << "Total is " << total << endl; ; void showid() cout << "ID number is " << id << endl; int Gamma::total = 0; int main() Gamma g1; Gamma::showtotal(); //αντί g1.showtotal(); Gamma g2, g3; Gamma::showtotal(); //το g2.showtotal() δίνει 3 και όχι 2. cout << "----end of program----\n"; Υπενθύµιση: όταν ένα µέλος δεδοµένων δηλώνεται ως στατικό τότε υπάρχει µόνο µια τιµή αυτού για όλη την κλάση (για όλα τα αντικείµενά της). Για να προσπελάσουµε µια συνάρτηση-µέλος µόνο µε το όνοµα της κλάσης πρέπει να την δηλώσουµε ως στατική συνάρτηση µέλος τότε µπορώ να γράψω π.χ. Gamma::showtotal(); 16. ΑΝΑΘΕΣΗ ΚΑΙ ΑΝΤΙΓΡΑΦΗ Τελεστής απόδοσης τιµής: Αν α1,α2 δυο αντικείµενα, η εντολή α2=a1 δίνει στο α2 την τιµή του α1, και αντιγράφονται τα δεδοµένα µέλος προς µέλος από το α1 στο α2. Συνάρτηση δόµησης αντιγράφου: Η εντολή alpha a2(a1) καλεί τον δοµητή (αντιγράφου) της κλάσης alpha - copy constructor- δηµιουργώντας ένα νέο αντικείµενο α2, αντιγράφοντας τα δεδοµένα µέλος προς µέλος από το α1 στο α2. Η απόδοση τιµής και συνάρτηση δόµησης αντιγράφου παρέχονται αυτόµατα από τον µεταγλωττιστή. VK - page 59
// 50 Xofxref.cpp class Alpha Alpha() Alpha(int d) data = d; Alpha(Alpha& a)//δοµητής αντιγράφου data = a.data; cout << "\ncopy constructor invoked;"; void display() cout << data; ; void operator = (Alpha& a)//απόδοση τιµής data = a.data; cout << "\nassignment operator invoked"; Alpha a1(37); Alpha a2; a2 = a1; //καλείται υπερφορτωµένο = cout << "\na2= "; a2.display(); Alpha a3(a1); //καλείται ο δοµητής αντιγράφου cout << "\na3= "; a3.display(); a3=a1;//καλείται = cout << endl; 17. O ΕΙΚΤΗΣ THIS Οι συναρτήσεις-µέλη κάθε αντικειµένου έχουν πρόσβαση σε ένα δείκτη που λέγεται this, που έχει την διεύθυνση του αντικειµένου αυτού. class alpha int a; void tp() this->a=11;//ίδιο µε a=11; ; Xρήση του δείκτη this για επιστροφή τιµών H πρακτική χρήση του δείκτη this είναι: η επιστροφή τιµών από συναρτήσεις-µέλη και υπερφορτωµένους τελεστές // 51 Assign2.cpp VK - page 60
class Alpha Alpha() Alpha(int d) data = d; void display(void) cout << data; ; Alpha& operator = (Alpha& a) //αν επιστρέψω ένα τοπικό αντικείµενο θα καταστραφεί µετά την συνάρτηση data = a.data; cout << "\nassignment operator invoked"; return *this; //επιστροφή του ίδιου του αντικειµένου Alpha a1(37); Alpha a2, a3; a3 = a2 = a1; //κλήση δυο φορές του υπερφορτωµένου = cout << "\na2= "; a2.display(); cout << "\na3= "; a3.display(); cout << endl; Αποφυγή δηµιουργίας επιπλέον αντικειµένων. VK - page 61