19. ΠΡΟΤΥΠΑ (TEMPLATES) Πρότυπα συναρτήσεων µε ένα όρισµα int abs (int n) float abs (float n) return (n<0)? -n : n return (n<0)? -n : n Template <classt> //πρότυπο συνάρτησης T abs (T n) //Τ, όρισµα προτύπου return (n<0)? -n : n Η abs τώρα δουλεύει για διάφορους τύπους δεδοµένων, που χρησιµοποιούνται ως ορίσµατα Το T λέγεται όρισµα προτύπου. Όταν τρέξει το πρόγραµµα και κληθεί η συνάρτηση π.χ. abs(-8.5), τότε παράγεται µια συγκεκριµένη εκδοχή της συνάρτησης που λέγεται συνάρτηση προτύπου και η διαδικασία αυτή λέγεται συγκεκριµενοποίηση του προτύπου. Πρότυπα συναρτήσεων µε πολλά ορίσµατα template <class A> int find ( A* array, A value, int size) //επιστρέφει τον αριθµοδείκτη του στοιχείου αν βρεί, ή -1, for (int j = 0; j < size; j++) if (array[j] == value) return j; return -1; int main() char C[]=1,3,5,9,11,13; //πίνακας double D[]=1.0,3.0,5.0,9.0,11.0,13.0; char ch=5; //τιµή προς εύρεση cout<<find(c,ch,6)<<endl; cout<<find(d,4.0,6)<<endl; VK - page 71
Τα ορίσµατα είναι ένας δείκτης προς τον πίνακα, η αναζητούµενη τιµή και το µέγεθος του πίνακα. Τα ορίσµατα προτύπων πρέπει να ταιριάζουν, ο Μεταγλωττιστής περιµένει όλες τις συγκεκριµενοποιήσεις A να είναι ίδιου τύπου π.χ. find (int*, int, int) ή find( float*,float,int). Μακροεντοεντολές ή πρότυπα? Π.χ. abs θα µπορούσε να οριστεί #define abs(n) ( (n<0)? (-n) : (n) ) Αποφεύγεται η χρήση των µακροεντολών στην C++, και γενικότερα η χρήση τους περιορίζεται σε συναρτήσεις της µιας µόνο εντολής. Πρότυπα κλάσεων Χρησιµοποιούνται για κλάσεις αποθήκευσης δεδοµένων (αποδέκτες) : στοίβες, λίστες κ.τ.λ. //59 stack templates.cpp - ΣΤΟΙΒΑ & ΠΡΟΤΥΠΑ (TEMPLATES) //Στην στοίβα µπαίνουν στοιχεία το ένα µετά το άλλο, //η εξαγωγή γίνεται ξεκινώντας από το τελευταίο στοιχείο #include <iostream> using namespace std; const int MAX = 5; /*1. κλάση στοίβα ΑΚΕΡΑΙΩΝ */ class istack int st[max]; //µια στοίβα απο ακεραίους int top; //ο αριθµοδείκτης που δείχνει στην κορυφή istack():top(-1) void push(int n) //εισαγωγή του στοιχείου n στην στοίβα st[++top]=n; cout << "istack::push (" << n << ")\n"; int pop() //ποιο είναι το τελευταίο στοιχείο που θα βγει,topvalue int topvalue=st[top--]; cout << "istack::pop(): " << topvalue<< endl; return topvalue; ; /*2. κλάση στοίβα ΤEMPLATE */ template <class TC> //ένα όρισµα προτύπου TC class tstack TC st[max]; //η στοίβα µπορεί να έχει ακέραιους, float..tc int top; //ο αριθµοδείκτης είναι ακέραιος tstack(): top(-1) void push(tc n) //εισαγωγή του στοιχείου n στην στοίβα st[++top]=n; cout << "tstack::push (" << n << ")\n"; TC pop() //βγάλε το τελευταίο στοιχείο, TC TC topvalue=st[top--]; cout << "tstack::pop(): " << topvalue<< endl; return topvalue; VK - page 72
; int main(int argc, char *argv[]) int i; istack s; //στοίβα ακεραίων for (i=0; i<3;i++) s.push(i); for (i=0; i<3;i++) s.pop(); cout<<"======template======\n" ;//Στοίβες για κάθε τύπο αντικειµένου cout<<"-float!\n"; tstack<float> s1; //Ε Ω ΠΡΟΣΟΧΗ όχι σκέτο tstack s,αλλά tstack<float> s s1.push(1111.1f);s1.push(2222.2f); s1.pop();s1.pop(); cout<<"-long!\n"; tstack<long> s2; //και tstack<long> s s2.push(123123123l); s2.push(234234234l); s2.pop();s2.pop(); cout<<"-char!\n"; tstack<char> s3; //και tstack<char> s s3.push('a');s3.pop(); system("pause"); return EXIT_SUCCESS; //Η κλάση istack προφανώς καλύπτεται -είναι περιττή- από την κλάση tstack //H καθιερωµένη βιβλιοθήκη προτύπων (STL) περιέχει έτοιµη κλάση στοίβα //µε όνοµα stack και ανήκει στους προσαρµογείς αποδεκτών //(container adapters), µαζί µε την queue και την priority_queue //παραλλαγές του αποδέκτη deque. Tα πρότυπα κλάσεων διαφέρουν από τα πρότυπα συναρτήσεων ως προς τον τρόπο συγκεκριµενοποίησής τους γιατί οι κλάσεις συγκεκριµενοποιούνται όταν ορίζετε ένα αντικείµενο π.χ. tstack<float> s; O µεταγλωττιστής παρέχει τότε χώρο για δεδοµένα και συναρτήσεις ανάλογα τον τύπο ορίσµατος. Οι συναρτήσεις µέλη όταν αναπτύσσονται έξω από την κλάση πρότυπο, απαιτούν και την δήλωση της κλάσης πρότυπο π.χ. template<class Type> //59 Templist.cpp κλάση συνδεδεµένης λίστας και πρότυπα #include <iostream> using namespace std; template<class Type> struct Link //ένα στοιχείο της λίστας Type data; Link* next; //δείκτης προς τον επόµενο ; //κλάση Linklist αποτελούµενη από δείκτη σε δοµή template<class Type> class Linklist Link<Type>* first; Linklist() VK - page 73
first = NULL; ; void additem(type d); void display();//εµφάνιση όλων //για όλες τις συναρτήσεις που ανπτύσσονται εκτός κλάσης επαναλαµβάνεται //το δηλωτικό template<class Type> template<class Type> void Linklist<Type>::additem(Type d) Link<Type>* newlink =new Link<Type>;//νέος σύνδεσµος newlink->data = d; newlink->next = first;//δείχνει στον πρώτο first = newlink; //γίνεται πρώτος template<class Type> void Linklist<Type>::display() Link<Type>* current = first; //από τον πρώτο while(current!= NULL) cout << endl << current->data; current = current->next; int main(int argc, char *argv[]) Linklist<double> ld; ld.additem(151.5); ld.additem(262.6); ld.additem(373.7); ld.display(); Linklist<char> lch; lch.additem('a'); lch.additem('b'); lch.additem('c'); lch.display(); cout << endl; system("pause"); return EXIT_SUCCESS; 20. ΕΞΑΙΡΕΣΕΙΣ (EXCEPTIONS) Οι εξαιρέσεις (exceptions) είναι σφάλµατα που µπορούν να εµφανιστούν κατά τον χρόνο εκτέλεσης ενός προγράµµατος. Είναι συνήθως καταστάσεις που δεν µπορεί να χειριστεί το πρόγραµµα π.χ. ιαίρεση µε µηδέν Προβλήµατα στην εγγραφή ή την ανάγνωση αρχείων Εξάντληση της ελεύθερης µνήµης του συστήµατος Πρόσβαση εκτός των ορίων ενός πίνακα Η βασική ιδέα είναι κάθε φορά που συµβαίνει µια εξαίρεση να ενεργοποιείται µια σηµαία σφάλµατος. Μόλις την εντοπίσει το σύστηµα παρακολούθησης καλεί τον κώδικα χειρισµού του σφάλµατος. O µηχανισµός χειρισµού εξαιρέσεων χρησιµοποιεί τρεις δεσµευµένες λέξεις C++ VK - page 74
throw //παραγωγή εξαίρεσης try catch //χειριστής εξαιρέσεων και ένα νέο είδος οντότητας που λέγεται κλάση χειρισµού εξαιρέσεων (exception class) //61 stack exceptions.cpp - ΣΤΟΙΒΑ & ΕΞΑΙΡΕΣΕΙΣ - EXCEPTIONS //Μέσα στη κλάση στοίβα, δηµιουργείται κλάση µε κενό σώµα //για τον χειρισµό των εξαιρέσεων -των λαθών- της συνάρτησης µέλους //Ο µηχανισµός εξαιρέσεων χρησιµοποιεί 3 δεσµευµένες λέξεις //throw, try, catch #include <iostream> using namespace std; const int MAX = 5; class istack int st[max]; int top; istack(); //δοµητής istack void push(int n); //εισαγωγή στοιχείου int istack::pop() ; //εξαγωγή στοιχείου class poponempty ; //κλάση χειρισµού εξαιρέσεων class pushonfull ; // >> συνήθως δεν έχουν κανένα µέλος- σώµα κενό ; istack::istack():top(-1) void istack::push(int n) //παραγωγή εξαίρεσης µε την δεσµευµένη λέξη throw if ( top==max-1 ) throw pushonfull(); //ακολουθούµενη από το δοµητή //της κλάσης χειρισµού εξαιρέσεων st[++top]=n; cout << "istack::push (" << n << ")\n"; int istack::pop() if ( top==-1 ) throw poponempty(); //παραγωγή εξαίρεσης int topvalue=st[top--]; cout << "istack::pop(): " << topvalue<< endl; return topvalue; int main(int argc, char *argv[]) int i;istack s; try for (i=0; i<5;i++) s.push(i); for (i=0; i<15;i++) s.pop() ; catch(istack::pushonfull) cout<<"full DEN PAEI ALLO!!!\n"; catch(istack::poponempty) cout<<"adeia TI NA BGALO???\n"; //try block - τµήµα δοκιµής //τµήµα σύλληψης VK - page 75
system("pause"); return EXIT_SUCCESS; //H καθιερωµένη βιβλιοθήκη προτύπων περιέχει έτοιµη κλάση στοίβα, stack. ο κώδικας εκτελείται κανονικά έξω από το block try έλεγχος εισέρχεται στο το block try µια εντολή του block try προκαλεί ένα σφάλµα σε κάποια συνάρτηση µέλος η συνάρτηση µέλος παράγει µια εξαίρεση ο έλεγχος µεταφέρεται στο χειριστή εξαιρέσεων cath block που ακολουθεί το block try Οι εξαιρέσεις δεν πρέπει να χρησιµοποιούνται για όλα τα είδη σφαλµάτων επιβαρύνουν το πρόγραµµα (µέγεθος & χρόνο) π.χ. δεν πρέπει να χρησιµοποιούνται στην περίπτωση εσφαλµένων καταχωρίσεων του χρήστη. 21. KAΘΙΕΡΩΜΕΝΗ ΒΙΒΛΙΟΘΗΚΗ ΠΡΟΤΥΠΩΝ (STL) Standard Template Library (STL) ενσωµατωµένη βιιβλιοθήκη κλάσεων-αποδεκτών Τρεις οι πιο σηµαντικές οντότητες Αποδέκτες (containers) τρόπος αποθήκευσης δεδοµένων Ακολουθιακοί vector (διάνυσµα-επεκτάσιµος πίνακας) list deque (ουρά διπλής εισόδου) Συνειρµικοί χρησιµοποιούν κλειδιά set (σύνολο) δοµή δένδρου µε κλειδί map (χάρτης)» ζεύγη τιµή-κλειδί multimap πολλαπλά κλειδιά Aπό αυτούς προκύπτουν οι προσαρµογείς αποδεκτών: stack (στοίβα) queue(ουρά) priority queue (ουρά προτεραιότητος) Αλγόριθµοι Συναρτήσεις που πραγµατοποιούν ενέργεια στα στοιχεία ενός αποδέκτη π.χ. sort : ταξινόµηση των στοιχείων. Επαναλήπτες (iterators) Μοιάζουν µε δείκτες και χρησιµοποιούνται για την προσπέλαση των στοιχείων ενός αποδέκτη. Στην STL οι επαναλήπτες αντιπροσωπεύονται από ένα αντικείµενο της κλάσης iterator. VK - page 76