1 Η Γλώσσα Προγραµµατισµού C++ (The C++ Programming Language) ηµήτριος Κατσαρός, Ph.D. Χειµώνας 2005 ιάλεξη 8η
2 Ιστοσελίδα του µαθήµατος http://skyblue.csd.auth.gr/~dimitris/courses/cpp_fall05.htm Θα τοποθετούνται οι διαφάνειες του επόµενου µαθήµατος Επικοινωνία: dimitris@skyblue.csd.auth.gr
3 Περιεχόµενα Χωριστή µεταγλώττιση και Namespaces Ρεύµατα Εισόδου/Εξόδου
4 Στόχοι εκµάθησης Χωριστή µεταγλώττιση Επανα-θεώρηση της ενθυλάκωσης Αρχεία κεφαλίδας (header) και αρχεία υλοποίησης (implementation) Namespaces Με χρήση των directives Qualifying ονόµατα Namespaces χωρίς όνοµα Απόκρυψη των βοηθητικών συναρτήσεων Φωλιασµένα namespaces
5 Χωριστή µεταγλώττιση Τµήµατα του προγράµµατος Κρατούνται σε διαφορετικά αρχεία Μεταγλωττίζονται χωριστά Συνενώνονται πριν εκτελεστεί το πρόγραµµα Ορισµοί κλάσεων Χωριστοί από τα προγράµµατα που τις χρησιµοποιούν ηµιουργία βιβλιοθηκών κλάσεων Επανα-χρησιµοποιούνται από πολλά διαφορετικά προγράµµατα Όπως και οι προκαθορισµένες βιβλιοθήκες
6 ιαχωρισµός κλάσεων Ανεξαρτησία κλάσης Χωριστά ο ορισµός/προσδιορισµός της κλάσης Αποκαλείται interface Χωριστά η υλοποίηση της κλάσης Τοποθετούνται σε δυο διαφορετικά αρχεία Εάν αλλάξει η υλοποίηση µόνο αυτό το αρχείο χρειάζεται να αλλάξει Ο προσδιορισµός της κλάση δεν αλλάζει Τα προγράµµατα των χρηστών δεν αλλάζουν
7 Επαναθεώρηση της ενθυλάκωσης Αρχή της ενθυλάκωσης: ιαχωρισµός του πώς χρησιµοποιείται η κλάση από τον προγραµµατιστή από τις λεπτοµέρειες υλοποίησης της κλάσης Πλήρης διαχωρισµός Αλλαγή της υλοποίησης ΚΑΜΙΑ επίδραση στα άλλα προγράµµατα Βασική αρχή του OOP
8 Κανόνες ενθυλάκωσης Κανόνες για να εγγυηθούµεενθυλάκωση: 1. Όλες οι µεταβλητές-µέλη πρέπει να είναι ιδιωτικές 2. Οι βασικές λειτουργίες της κλάσης πρέπει να είναι οι: ηµόσιες συναρτήσεις-µέλη Friend ή κανονικές συναρτήσεις Υπερφορτωµένοι τελεστές Οµαδοποίηση του ορισµού της κλάσης και των δηλώσεων/πρωτότυπα των συναρτήσεων Αποκαλείται διασύνδεση ( interface ) της κλάσης 3. Κάνουµε την υλοποίηση της κλάσης µη διαθέσιµη στους χρήστες της
9 Περισσότερα για διαχωρισµό κλάσης Αρχείο διασύνδεσης Περιέχει τον ορισµό της κλάσης µαζί µε τις δηλώσεις/πρωτότυπα των συναρτήσεων και των τελεστών Οι χρήστες βλέπουν αυτό το αρχείο Χωριστή µονάδα µεταγλώττισης Αρχείο υλοποίησης Περιέχει τους ορισµούς (υλοποίηση) των συναρτήσεων-µελών Χωριστή µονάδα µεταγλώττισης
10 Αρχεία κεφαλίδας της κλάσης Η διασύνδεση της κλάσης πάντα στο header file Χρήση του.h είναι σύµβαση για το όνοµά του Τα προγράµµατα που θα χρησιµοποιήσουν την κλάση θα το κάνουν "include" #include "myclass.h" Τα " " σηµατοδοτούν ότι γράφηκε από εµάς Το εντοπίζουµε στον τοπικό φάκελο εργασίας µας Θυµηθείτε τα include για βιβλιοθήκες, π.χ., <iostream> Τα < > σηµατοδοτούν header file προκαθορισµένης βιβλιοθήκης Τα εντοπίζουµε στο φάκελο µε τις βιβλιοθήκες
11 Αρχεία υλοποίησης της κλάσης Η υλοποίηση της κλάσης τοποθετείται σε.cpp αρχείο Συνήθως δίνουµε στο interface αρχείο και στο αρχείο υλοποίησης το ίδιο όνοµα myclass.h και myclass.cpp Όλες οι συναρτήσεις-µέλη της κλάσης ορίζονται εδώ Το αρχείο υλοποίησης πρέπει να κάνει #include το header αρχείο της κλάσης Τα.cpp αρχεία συνήθως, περιέχουν εκτελέσιµο κώδικα π.χ., ορισµούς συναρτήσεων, περιλαµβανοµένης και της main()
12 Αρχεία της κλάσης Το header αρχείο της κλάσης γίνεται #include από: Το αρχείο υλοποίησης Το αρχείο προγράµµατος Συχνά αποκαλείται αρχείο εφαρµογής ή αρχείο οδηγός Η οργάνωση των αρχείων διαφέρει από σύστηµα σε σύστηµα Τα συνήθη IDE έχουν "project" ή "workspace" Τα αρχεία υλοποίησης συνδυάζονται εδώ Εξακολουθούµε να κάνουµε #include τα header αρχεία
Πολλαπλές µεταγλωττίσεις των 13 αρχείων header Αρχεία header Συνήθως γίνονται #include πολλές φορές π.χ., η διασύνδεση της κλάσης γίνεται include από την υλοποίηση της κλάσης αλλά και από το αρχείο εφαρµογής Πρέπει όµως να µεταγλωττιστεί µόνο µια φορά! εν υπάρχει εγγύηση για το ποιο "#include" σε ποιο αρχείο, θα δει πρώτο ο compiler Χρήση του προεπεξεργαστή Καθοδηγούµε τον compiler να κάνει include το header µόνο µια φορά
14 Χρήση της #ifndef οµή αρχείου header: #ifndef FNAME_H #define FNAME_H //Contents of header file #endif Το FNAME είναι συνήθως το όνοµα του ίδιου του αρχείου για συνέπεια και ευκολία Αυτή η σύνταξη αποφεύγει τους πολλαπλούς ορισµούς του αρχείου header
15 Άλλα αρχεία βιβλιοθήκης Η βιβλιοθήκες δεν είναι µόνο για τις κλάσεις Σχετικές συναρτήσεις ηλώσεις αρχείο header Ορισµοί αρχείο υλοποίησης Άλλοι ορισµοί τύπων structs, απλά typedefs αρχείο header ηλώσεις σταθερών αρχείο header
16 Namespaces Ορισµός ενός namespace: Μια συλλογή ορισµών ονοµάτων Ορισµοί κλάσεων ηλώσεις µεταβλητών Τα προγράµµατα χρησιµοποιούν πολλές συναρτήσεις, κλάσεις Συνήθως έχουν ίδια ονόµατα Τα namespaces αντιµετωπίζουν αυτό το πρόβληµα Μπορεί να είναι "on" ή "off" Εάν τα ονόµατα είναι πιθανό να συγκρουστούν turn off
17 Η directive using using namespace std; Κάνει διαθέσιµους όλους τους ορισµούς στο std namespace Γιατί πιθανόν να ΜΗΝ το θέλουµε αυτό? Μπορεί να κάνει τα cout, cin να έχουν το µητυπικό τους νόηµα Ίσως ανάγκη να ξανα-ορίσουµε τα cout, cin Μπορούµε να ξαναορίσουµε όποιο άλλο επιθυµούµε
18 Το namespace std Περιέχει όλα τα ονόµατα που ορίζονται σε πολλά αρχεία standard βιβλιοθηκών Παράδειγµα: #include <iostream> Τοποθετεί όλους τους ορισµούς των ονοµάτων (cin, cout, κ.τ.λ.) στο std namespace Το πρόγραµµά µας δεν γνωρίζει τα ονόµατα Πρέπει να καθορίσουµε αυτό το namespace για να µπορέσει το πρόγραµµά µας να προσπελάσει τα ονόµατα
19 Καθολικό (Global) namespace Όλος ο κώδικας πηγαίνει σε κάποιο namespace Εκτός εάν το καθορίσουµε αλλιώς Global namespace εν χρειάζεται να κάνουµε χρήση κάποιας directive Το Global namespace είναι πάντα διαθέσιµο Υπάρχει µια αυτόµατη using directive για το global namespace
20 Πολλαπλά ονόµατα Πολλαπλά namespaces π.χ., συνήθως χρησιµοποιούνται το global και το std Τι θα συµβεί εάν κάποιο όνοµα ορίζεται και στα δυο? Error Μπορούµε να τα χρησιµοποιήσουµε και τα δυο, αλλά όχι ταυτόχρονα Πρέπει να καθορίσουµε ποιο από τα δυο χρησιµοποιούµε
21 Καθορίζοντας namespaces εδοµένων των namespaces NS1 και NS2 Και τα δυο έχουν void function myfunction() η οποία όµως ορίζεται διαφορετικά { using namespace NS1; myfunction(); } { using namespace NS2; myfunction(); } Χρησιµοποιώντας τη directive έχει εµβέλεια block
22 ηµιουργώντας ένα namespace Χρησιµοποιήστε namespace οµαδοποίηση: namespace Name_Space_Name { Some_Code } Τοποθετεί όλα τα ονόµατα που ορίζονται στο Some_Code στο namespace Name_Space_Name Κατόπιν µπορούν να γίνουν διαθέσιµα: using namespace Name_Space_Name
Παράδειγµα δηµιουργίας namespace ήλωση συνάρτησης: namespace Space1 { void greeting(); } Ορισµός συνάρτησης: namespace Space1 { void greeting() { cout << "Hello from namespace Space1.\n"; } } 23
24 using δηλώσεων Μπορούµε να καθορίσουµε µεµονωµένα ονόµατα από το namespace είτε το εξής: Έστωσαν τα namespaces NS1 και NS2 Κάθε ένα έχει συναρτήσεις fun1(), fun(2) Σύνταξη δήλωσης: using Name_Space::One_Name; Καθορίζουµε ποιο όνοµα από τα δυο: using NS1::fun1; using NS2::fun2;
25 using ορισµούς και δηλώσεις ιαφορές: using δήλωση Κάνει διαθέσιµο ΈΝΑ µόνο όνοµα του namespace Εισαγάγει ονόµατα, έτσι ώστε καµία άλλη χρήση αυτών δεν επιτρέπεται using directive Κάνει διαθέσιµα ΌΛΑ τα ονόµατα του namespace Εισαγάγει ονόµατα µόνο εν δυνάµει
26 Qualifying ονόµατα Μπορούµε να καθορίσουµε από πού προέρχεται ένα όνοµα Χρησιµοποιούµε "qualifier" και τελεστή διάκρισης εµβέλειας (scope-resolution operator) Χρησιµοποιείται µόνο εάν πρόκειται να χρησιµοποιήσουµε το όνοµα µια φορά (ή λίγες σχετικά) NS1::fun1(); Καθορίζει ότι η fun() προέρχεται από το namespace NS1 Ειδικά χρήσιµο για παραµέτρους: int getinput(std::istream inputstream); Η παράµετρος βρίσκεται στο std namespace της istream Εξαλείφει την ανάγκη για την directive using ή using δήλωση
27 Ονοµατίζοντας namespaces Χρησιµοποιούµε µοναδικό string Ελαττώνει την πιθανότητα για άλλα namespaces µε το ίδιο όνοµα Συχνά πολλοί προγραµµατιστές γράφουν namespaces για το ίδιο πρόγραµµα Πρέπει να έχουν διακριτά ονόµατα Χωρίς πολλαπλοί ορισµοί του ίδιου ονόµατος στην ίδια εµβέλεια Προκύπτει error
28 Παρ. κλάσης σε namespace (αρχείο.h)
29 Παρ. κλάσης σε namespace (αρχείο.cpp)
30 Ανώνυµα (unnamed) Namespaces Ορισµός µονάδας µεταγλώττισης : Ένα αρχείο, µαζί µε όλα τα αρχεία που γίνονται #include από αυτό Κάθε µονάδα µεταγλώττισης έχει unnamed namespace Γράφεται µε τον ίδιο τρόπο, αλλά χωρίς όνοµα Τότε, όλα τα ονόµατα είναι τοπικά στην µονάδα µεταγλώττισης Χρησιµοποιούµε unnamed namespaces για να κρατήσουµε τα πράγµατα τοπικά Η εµβέλεια ενός unnamed namespace είναι η µονάδα µεταγλώττισης
31 Global vs. Unnamed Namespaces εν είναι το ίδιο Global namespace: εν υπάρχει καθόλου namespace οµαδοποίηση Καθολική εµβέλεια Unnamed namespace: Έχει namespace οµαδοποίηση, απλά δεν έχει όνοµα Τοπική εµβέλεια
32 Φωλιαµένα namespaces Ο φωλιασµός namespaces είναι έγκυρος namespace S1 { namespace S2 { void sample() { } } Κάνουµε qualification το όνοµα δυο φορές: S1::S2::sample();
33 Απόκρυψη βοηθητικών συναρτήσεων Θυµηθείτε τις βοηθητικές συναρτήσεις: Χαµηλού επιπέδου λειτουργίες Όχι για δηµόσια χρήση υο τρόποι να τις κρύψουµε: Τις κάνουµε ιδιωτικές συναρτήσεις-µέλη Εάν η συνάρτηση παίρνει calling object Τις τοποθετούµε στο unnamed namespace της υλοποίησης της κλάσης! Εάν η συνάρτηση δεν χρειάζεται calling object Φτιάχνει καθαρότερο κώδικα (χωρίς qualifiers)
34 Περίληψη 1 Μπορούµε να διαχωρίσουµε τον ορισµό από την υλοποίηση µιας κλάσης διαφορετικά αρχεία ιαφορετικές µονάδες µεταγλώττισης Ένα namespace είναι µια συλλογή από ορισµούς ονοµάτων Τρεις τρόποι για να χρησιµοποιήσουµε ένα όνοµα ενός namespace: using directive using declaration qualifying
35 Περίληψη 2 Οι ορισµοί των namespace τοποθετούνται µέσα σε οµαδοποιήσεις namespace Ανώνυµο (Unnamed) namespace Χρησιµοποιείται για τοπικούς ορισµούς ονοµάτων Η εµβέλεια είναι η µονάδα µεταγλώττισης Καθολικό (Global) namespace Τα στοιχεία (items) που δεν βρίσκονται σε καµία οµαδοποίηση namespace Καθολική εµβέλεια
36 Περιεχόµενα Χωριστή µεταγλώττιση και Namespaces Ρεύµατα Εισόδου/Εξόδου
37 Στόχοι εκµάθησης Ρεύµατα I/O I/Oαρχείων I/Oχαρακτήρων Εργαλεία για I/O ρευµάτων Ονόµατα αρχείων ως είσοδος Μορφοποίηση εξόδου, ρυθµίσεις των flags Ιεραρχίες ρευµάτων Πρώτη γνωριµία µε την κληρονοµικότητα Τυχαία προσπέλαση σε αρχεία
38 Εισαγωγικά Ρεύµατα Ειδικά αντικείµενα ιανέµουν την είσοδο/έξοδο του προγράµµατος I/Oαρχείων Χρησιµοποιεί κληρονοµικότητα (στην επόµενη διάλεξη) I/O αρχείων εξαιρετικά χρήσιµη
39 Ρεύµατα (streams) Ροή χαρακτήρων Ρεύµα εισόδου Ρέει µέσα στο πρόγραµµα Προέρχεται από το πληκτρολόγιο Προέρχεται από αρχείο Ρεύµα εξόδου Ρέει έξω από το πρόγραµµα Πηγαίνει στην οθόνη Πηγαίνει σε αρχείο
40 Χρήση των ρευµάτων Έχουµε ήδη χρησιµοποιήσει ρεύµατα cin Ρεύµα εισόδου συνδεδεµένο στο πληκτρολόγιο cout Ρεύµα εξόδου συνδεδεµένο στην οθόνη Μπορούµε να ορίσουµε νέα ρεύµατα Προς ή από αρχεία Χρησιµοποιούνται παρόµοια µε τα cin, cout
41 Χρήση ρευµάτων όπως των cin, cout Θεωρήστε το: εδοµένο πρόγραµµα ορίζει το ρεύµα instream που προέρχεται από κάποιο αρχείο: int thenumber; instream >> thenumber; ιαβάζει τιµή από το ρεύµα και την αναθέτει στη µεταβλητή thenumber Το πρόγραµµα ορίζει το ρεύµα outstream που πηγαίνει σε κάποιο αρχείο outstream << "thenumber is " << thenumber; Γράφει τιµή στο ρεύµα, που πηγαίνει σε ένα αρχείο
42 Αρχεία Θα χρησιµοποιήσουµε αρχεία κειµένου (text files) Ανάγνωση από αρχείο Όταν το πρόγραµµα δέχεται είσοδο Εγγραφή σε αρχείο Όταν το πρόγραµµα στέλνει έξοδο Επεξεργασία από την αρχή µέχρι το τέλος του αρχείου Άλλες διαθέσιµες µέθοδοι θα ασχοληθούµε µε την προσπέλαση σε αυτό το απλό αρχείο
43 Σύνδεση σε αρχείο Πρέπει πρώτα να συνδέσουµε το αντικείµενο ρεύµατος (stream object) σε ένα αρχείο (file) Για είσοδο: File αντικείµενο ifstream Για έξοδο: File αντικείµενο ofstream Οι κλάσεις ifstream και ofstream Ορίζονται στη βιβλιοθήκη <fstream> Στο namespace std
44 Βιβλιοθήκες I/O αρχείων Για να επιτρέψουµε είσοδο και έξοδο από/προς αρχεία στο πρόγραµµά µας: #include <fstream> using namespace std; Ή #include <fstream> using std::ifstream; using std::ofstream;
45 ήλωση ρευµάτων Το ρεύµα πρέπει να δηλωθεί όπως κάθε άλλη µεταβλητή τύπου κλάσης: ifstream instream; ofstream outstream; Κατόπιν, πρέπει να συνδεθεί σε ένα αρχείο: instream.open("infile.txt"); Αποκαλείται άνοιγµα του αρχείου Χρησιµοποιεί τη συνάρτηση-µέλος open Μπορούµε να καθορίσουµε όνοµα πλήρους διαδροµής (full pathname)
46 Χρήση ρευµάτων Αφού δηλωθεί χρησιµοποιείται κανονικά! int onenumber, anothernumber; instream >> onenumber >> anothernumber; Όµοια για την έξοδο του ρεύµατος: ofstream outstream; outstream.open("outfile.txt"); outstream << "onenumber = " << onenumber << " anothernumber = " << anothernumber; Στέλνει τα items στο αρχείο εξόδου
47 Ονόµατα αρχείων Προγράµµατα και αρχεία Τα αρχεία έχουν δυο ονόµατα στα προγράµµατά µας Εξωτερικό όνοµα αρχείου Αποκαλείται επίσης φυσικό όνοµα αρχείου Όπως το "infile.txt" Μερικές φορές θεωρείται το πραγµατικό όνοµα αρχείου" Χρησιµοποιείται µόνο µια φορά στο πρόγραµµα (για να ανοιχτεί το αρχείο) Όνοµα ρεύµατος Αποκαλείται επίσης λογικό όνοµα αρχείου Το πρόγραµµα χρησιµοποιεί αυτό το όνοµα για τις λειτουργίες του
48 Κλείσιµο αρχείων Τα αρχεία πρέπει να κλείνουν When program completed getting input or sending output Disconnects stream from file Στην πράξη: instream.close(); outstream.close(); Σηµειώστε ότι δεν υπάρχουν ορίσµατα Τα αρχεία κλείνουν αυτόµατα όταν τερµατιστεί το πρόγραµµά µας
49 Άδειασµα (Flush) αρχείου Συχνά η έξοδος είναι "buffered" Αποθηκεύεται προσωρινά πριν σταλεί στο αρχείο Γράφεται σε οµάδες Περιστασιακά, ίσως χρειαστεί να εξαναγκάσουµε την εγγραφή στο αρχείο, δηλ., το άδειασµα των buffers: outstream.flush(); Συνάρτηση-µέλος flush, για όλα τα ρεύµατα εξόδου Όλη η buffered output γράφεται στο αρχείο Το κλείσιµο του αρχείου καλεί αυτόµατα την flush()
50 Παράδειγµα I/O αρχείου (1/2)
51 Παράδειγµα I/O αρχείου (2/2)
Προσθήκη στο τέλος (append) αρχείου 52 Η τυπική λειτουργία open ξεκινά µε άδειο αρχείο Ακόµα και εάν το αρχείο υπάρχει τα περιεχόµενα χάνονται (overwritten) Λειτουργία open για προσθήκη στο τέλος (append): ofstream outstream; outstream.open("important.txt", ios::app); Εάν το αρχείο δεν υπάρχει το δηµιουργεί Εάν το αρχείο υπάρχει προσθέτει στο τέλος Το 2 ο όρισµα είναι µια σταθερά ορισµένη στην κλάση ios Στη βιβλιοθήκη <iostream>, και στο namespace std
53 Άλλη σύνταξη για άνοιγµα αρχείου Μπορούµε να καθορίσουµε το όνοµα του αρχείου στη δήλωση Περνάει ως όρισµα στον constructor ifstream instream; instream.open("infile.txt"); ΙΣΟ ΥΝΑΜΟ ΜΕ ΤΟ: ifstream instream("infile.txt");
Έλεγχος για επιτυχές άνοιγµα 54 αρχείου File opens θα µπορούσαν να αποτύχουν Εάν το αρχείο εισόδου δεν υπάρχει εν έχουµε δικαίωµα εγγραφής στο αρχείο εξόδου Απρόβλεπτες καταστάσεις Συνάρτηση-µέλος fail() Κάνουµε κλήση στη fail() για να ελέγξουµε την επιτυχία της λειτουργίας στο ρεύµα instream.open("stuff.txt"); if (instream.fail()) { cout << "File open failed.\n"; exit(1); }
55 I/O χαρακτήρων µε αρχεία Όλες οι λειτουργίες I/O χαρακτήρων µε cin και cout ίδιες και µε τα αρχεία! Οι συναρτήσεις-µέλη δουλεύουν το ίδιο: get, getline put, putback, peek, ignore
56 Έλεγχος τέλους αρχείου: Τρόπος 1 ος Χρήση βρόχου για επεξεργασία του αρχείου µέχρι να τελειώσει Τυπική προσέγγιση υο τρόποι για να ελέγξουµε για τέλος αρχείου Συνάρτηση-µέλος eof() instream.get(next); while (!instream.eof()) { cout << next; instream.get(next); } ιαβάζει κάθε χαρακτήρα µέχρι να τελειώσει το αρχείο Η συνάρτηση-µέλος eof() επιστρέφει bool
57 Έλεγχος τέλους αρχείου: Τρόπος 2 ος εύτερη µέθοδος Η λειτουργία read επιστρέφει τιµή bool! (instream >> next) Η έκφραση επιστρέφει true εάν η read είναι επιτυχής Επιστρέφει false εάν προσπαθήσει να διαβάσει πέρα από το τέλος του αρχείου Στην πράξη: double next, sum = 0; while (instream >> next) sum = sum + next; cout << "the sum is " << sum << endl;
58 Ονόµατα αρχείων ως είσοδος Λειτουργία open για ρεύµα Το όρισµα στην open() είναι τύπου string Μπορεί να είναι literal (όπως µέχρι τώρα) ή µεταβλητή char filename[16]; ifstream instream; cout << "Enter file name: "; cin >> filename; instream.open(filename); Παρέχει ευελιξία
Μορφοποίηση εξόδου µε συναρτήσεις 59 Έχουµε χρησιµοποιήσει σε παράδειγµα τα: cout.setf(ios::fixed); cout.setf(ios::showpoint); cout.precision(2); Τυπώνει τους αριθµούς σε µορφή χρήµατος (12.52) Μπορεί να χρησιµοποιηθεί σε οποιοδήποτε ρεύµα εξόδου Τα ρεύµατα αρχείων (file streams) έχουν τις ίδιες συναρτήσεις-µέλη µε το αντικείµενο cout
60 Συναρτήσεις-µέλη για έξοδο (1/2) Θεωρήστε τα: outstream.setf(ios::fixed); outstream.setf(ios::showpoint); outstream.precision(2); Η συνάρτηση-µέλος precision(x) Οι δεκαδικοί γράφονται µε "x" ψηφία µετά την υποδιαστολή Η συνάρτηση-µέλος setf() Επιτρέπει πολλές από τις flags εξόδου να τεθούν σε κάποια τιµή
61 Συναρτήσεις-µέλη για έξοδο (2/2) Θεωρήστε το: outstream.width(5); Η συνάρτηση-µέλος width(x) Θέτει το πλάτος σε "x" για την τιµή εξόδου Επηρεάζει µόνο την επόµενη τιµή στην έξοδο Πρέπει να θέτουµε το width πριν από κάθε τιµή ώστε να επηρεαστούν όλες Είναι τυπικό να έχουµε µεταβλητά widths Για να φτιάξουµε στήλες
62 Flags Θυµηθείτε: η συνάρτηση-µέλος setf() Θέτει την κατάσταση των flags εξόδου Όλα τα ρεύµατα εξόδου έχουν µέλος τη setf() Οι flags είναι σταθερές στην κλάση ios Στη βιβλιοθήκη <iostream>, στο namespace std
63 Παραδείγµατα µε τη setf() Συνήθεις σταθερές flag: outstream.setf(ios::fixed); Θέτει τον συµβολισµό fixed-point (δεκαδική αναπαράσταση) outstream.setf(ios::showpoint) Να περιλαµβάνεται πάντα η υποδιαστολή outstream.setf(ios::right); Θέτει δεξιά στοίχιση Θέτουµε πολλές flags µε µια κλήση: outstream.setf(ios::fixed ios::showpoint ios::right);
64 ιαχειριστές (Manipulators) Ως διαχειριστής (manipulator) ορίζεται: Μια συνάρτηση που καλείται µε µη-παραδοσιακό τρόπο Μπορεί να έχει ορίσµατα Τοποθετείται µετά τον τελεστή εισαγωγής Κάνουν τα ίδια πράγµατα όπως και οι συναρτήσεις-µέλη! Με διαφορετικό τρόπο Είναι σύνηθες να τους χρησιµοποιούµε µαζί Οι setw() και setprecision() βρίσκονται στη βιβλιοθήκη <iomanip>, στο namespace std
65 Παράδειγµα διαχειριστή: setw() Ο διαχειριστής setw(): cout << "Start" << setw(4) << 10 << setw(4) << 20 << setw(6) << 30; Προκύπτει το: Start 10 20 30 Σηµειώστε ότι: η setw() επηρεάζει µόνο την επόµενη τιµή εξόδου Πρέπει να περιλαµβάνουµε την setw() πριν από κάθε item εξόδου, ώστε να επηρεαστούν όλα
66 Ο διαχειριστής setprecision() Ο διαχειριστής setprecision(): cout.setf(ios::fixed ios::showpoint); cout << "$" << setprecision(2) << 10.3 << " " << "$" << 20.5 << endl; Προκύπτει το: $10.30 $20.50
67 Αποθήκευση των τιµών των Flag Οι τιµές των flags παραµένουν µέχρι να αλλαχτούν Οι flags precision και setf µπορούν να αποθηκευτούν και να ανακτηθούν Η συνάρτηση precision() επιστρέφει την τρέχουσα τιµή, εάν κληθεί χωρίς ορίσµατα Η συνάρτηση-µέλος flags() παρέχει παρόµοια λειτουργικότητα
68 Παράδειγ. αποθήκευσης τιµών flag void outputstuff(ofstream& outstream) { int precisionsetting = outstream.precision(); long flagsettings = outstream.flags(); outstream.setf(ios::fixed ios::showpoint); outstream.precision(2); outstream.precision(precisionsetting); outstream.flags(flagsettings); } Συνάρτηση για αποθήκευση και ανάκτηση τυπικών ρυθµίσεων Κλήση: outputstuff(mystream);
69 Ανακτώντας τις εξ ορισµού τιµές Μπορούµε να ανακτήσουµε τις εξ ορισµού ρυθµίσεις: cout.setf(0, ios::floatfield); εν είναι αναγκαστικά οι τελευταίες ρυθµίσεις! Οι εξ ορισµού ρυθµίσεις εξαρτώνται από την υλοποίηση εν κάνει reset τις ρυθµίσεις της precision Μόνο τις ρυθµίσεις της setf
70 Ιεραρχίες ρευµάτων Σχέσεις κλάσεων Παράγεται από Μια κλάση προέρχεται από άλλη κλάση Κατόπιν προστίθονται χαρακτηριστικά Παράδειγµα: ηλ.: το ifstream παράγεται από το istream
71 Κληρονοµικότητα κλάσεων ρευµάτων Θεωρήστε το: Εάν η D είναι παραγόµενη κλάση της B Όλα τα αντικείµενα τύπου D είναι επίσης αντικείµενα τύπου B Σε ότι αφορά τα ρεύµατα: Ένα αντικείµενο ifstream είναι επίσης ένα αντικείµενο istream Θα πρέπει να χρησιµοποιούµε αντικείµενα istream ως παραµέτρους Έτσι περισσότερα αντικείµενα µπορούν να περαστούν ως παράµετροι!
Παράδειγµα κληρονοµικότητας κλάσεων 72 ρευµάτων
Κληρονοµικότητα κλάσεων 73 ρευµάτων: Παραδείγµατα κλήσεων Θεωρώντας τις προηγούµενες συναρτήσεις: twosumversion1(filein); // Νόµιµο! twosumversion1(cin); // Παράνοµο! Επειδή η cin δεν είναι τύπου ifstream! twosumversion2(filein); twosumversion2(cin); // Νόµιµο! // Νόµιµο! Πιο ευέλικτο Η παράµετρος istream δέχεται και τα δυο αντικείµενα
74 Τυχαία προσπέλαση σε αρχεία Σειριακή προσπέλαση Η πιο συχνά χρησιµοποιούµενη µέθοδος Τυχαία προσπέλαση Γρήγορη προσπέλαση στις εγγραφές Για µεγάλες βάσεις Προσπελάζει τυχαία οποιοδήποτε µέρος του αρχείου Χρήση των αντικειµένων fstream Είσοδος και έξοδος
75 Εργαλεία τυχαίας προσπέλασης Ανοίγει όµοια µε istream ή ostream Έχει δεύτερο όρισµα fstream rwstream; rwstream.open("stuff", ios::in ios:: out); Ανοίγει µε δυνατότητα read και write Μετακίνηση µέσα σε ένα αρχείο rwstream.seekp(1000); Τοποθετεί τον put-pointer στο 1000 th byte rwstream.seekg(1000); Τοποθετεί τον get-pointer στο 1000 th byte
76 Μεγέθη για τυχαία προσπέλαση Για να µετακινούµαστε πρέπει να γνωρίζουµε τα µεγέθη Ο τελεστής sizeof() προσδιορίζει τον αριθµό των bytes που απαιτούνται για ένα αντικείµενο: sizeof(s) //Where s is string s = "Hello" sizeof(10) sizeof(double) sizeof(myobject) Τοποθετεί τον put-pointer στην 100 th εγγραφή των αντικειµένων: rwstream.seekp(100*sizeof(myobject) 1);
77 Περίληψη 1 Τα ρεύµατα συνδέονται σε αρχεία µε τη λειτουργία open Η συνάρτηση-µέλος fail() ελέγχει την επιτυχία ιάφορες συναρτήσεις-µέλη µορφοποιούν την έξοδο π.χ., width, setf, precision Ίδια χρήση της cout (οθόνη) ή αρχεία Οι τύποι ρευµάτων (stream) µπορεί να είναι παράµετροι Πρέπει να περνάνε ως call-by-reference
78 Περίληψη 2 istream (χωρίς f ) παράµετροι δέχονται αντικείµενα cin ή αντικείµενα ifstream ως ορίσµατα ostream (χωρίς f ) παράµετροι δέχονται αντικείµενα cout ή αντικείµενα ofstream ως ορίσµατα Συνάρτηση-µέλος eof Χρησιµοποιείται για να ελέγξει για το τέλος του αρχείου εισόδου