Προγραμματισμός Υπολογιστών με C++ ( 2012-13 ) 6η διάλεξη Ίων Ανδρουτσόπουλος http://www.aueb.gr/users/ion/ 1
Τι θα ακούσετε σήμερα Προκαθορισμένες τιμές ορισμάτων. Υπερφόρτωση συναρτήσεων. Συναρτήσεις inline. Αρχεία κεφαλίδων. Χώροι ονομάτων. 2
Προκαθορισμένες τιμές ορισμάτων #include // Δήλωση συνάρτησης με προκαθορισμένη τιμή ορίσματος: void print(int i, const string& s = "the value is: "); int i = 5; print(i, "i = "); // Τυπώνει «i = 5». print(i); // Τυπώνει «the value is: 5». // Ορισμός της συνάρτησης. Η προκαθορισμένη τιμή // δίνεται στη δήλωση: void print(int i, const string& s) { cout << s << i << endl; 3
Κανόνες χρήσης προτεροτιμών void g(int i, int j = 0, float f = 1.0F); Αν ορίσω προτεροτιμή για ένα όρισμα, πρέπει να ορίσω προτεροτιμές και για όλα τα ορίσματα δεξιά του. X void g(int i, int j = 0, float f); // Λάθος. Πρέπει να ορίσω // προτεροτιμή και για το f. 4
Υπερφόρτωση συναρτήσεων void print(float f); // Για τύπωμα float. void print(string s); // Για τύπωμα string. void print(float arg[], unsigned size); // Τύπωμα πίνακα float. float f = 5.0F; int i = 10; string s = "test"; float arr[] = {1.0F, 2.0F, 3.0F; print(f); // Χρησιμοποιείται η πρώτη μορφή. print(s); // Χρησιμοποιείται η δεύτερη μορφή. print(arr, 3); print(i); // Χρησιμοποιείται η τρίτη μορφή. // Χρησιμοποιείται η πρώτη μορφή μετά // από μετατροπή του i σε float. 3 ξεχωριστοί ορισμοί για τις μορφές της print() 5
() print 3 διαφορετικοί ορισμοί της void print(float f) { cout << f << endl; void print(string s) { cout << s << endl; void print(float arg[], unsigned size) { for(unsigned i = 0; i < size; i++) { cout << arg[i] << endl; 6
Περισσότερα για την υπερφόρτωση X void f(int i); X int f(int i); // Οι μορφές δεν μπορούν να διαφέρουν // μόνο στον τύπο επιστροφής. X void g(string s); // Δε θεωρείται αρκετή η διαφορά μεταξύ X void g(string& s); // τύπου και αναφοράς στον ίδιο τύπο. void h(string& s); // Αν έχουν οριστεί και οι δύο, void h(const string& s); // χρησιμοποιείται η 2η μορφή // όταν μεταβιβάζονται σταθερές και η 1η μορφή // όταν μεταβιβάζονται μη σταθερές. 7
Συναρτήσεις inline void print(int arg) { cout << "value: " << arg; int i = 10; print(i); i = 20; print(i); inline void print(int arg) { cout << "value: " << arg; int i = 10; Ταχύτερη εκτέλεση, αλλά μεγαλύτερο μέγεθος εκτελέσιμου κώδικα. print(i); { int arg = i; cout << "value:" << arg; i = 20; print(i); { int arg = i; cout << "value:" << arg; 8
Πολλά αρχεία πηγαίου κώδικα Αρχείο mylib.cpp: float f1(int i); int f2(int i); float f1(int i) { return i / 3.0F; int f2(int i) { return i * 10; Αρχείο myapp.cpp: #include <iostream> using namespace std; float f1(int i); int f2(int i); int k = f2(10); float f = f1(k); cout << k << endl << f << endl; g++ -o target.exe mylib.cpp myapp.cpp 9
Αρχεία κεφαλίδων Αρχείο mylib.h: float f1(int i); int f2(int i); Αρχείο myapp.cpp: #include <iostream> using namespace std; Αρχείο mylib.cpp: float f1(int i) { return i / 3.0F; int f2(int i) { return i * 10; int k = f2(10); float f = f1(k); cout << k << endl << f << endl; g++ -o target.exe mylib.cpp myapp.cpp 10
Αρχεία κεφαλίδων και inline Αρχείο mylib.h: float f1(int i); inline int f2(int i) { return i * 10; Αρχείο mylib.cpp: float f1(int i) { return i / 3.0F; Αρχείο myapp.cpp: #include <iostream> using namespace std; int k = f2(10); float f = f1(k); cout << k << endl << f << endl; Τις συναρτήσεις inline τις ορίζουμε στο αρχείο κεφαλίδας, γιατί απαιτείται να ορίζονται ξανά σε κάθε αρχείο.cpp! 11
Τι μπαίνει στα αρχεία κεφαλίδων; Δηλώσεις συναρτήσεων. Ορισμοί συναρτήσεων inline. Ορισμοί τάξεων (επόμενες διαλέξεις). Σχεδιότυπα (επόμενες διαλέξεις). Ορισμοί δομών, δηλώσεις καθολικών μεταβλητών και καθολικών σταθερών (τελευταίες διαλέξεις, αν προλάβουμε...). Ό,τι άλλο χρειάζεται κάποιος για να χρησιμοποιήσει το αντίστοιχο αρχείο.cpp. 12
Η ανάγκη για χώρους ονομάτων Αρχείο mylib.h: float f1(int i); inline int f2(int i) { return i * 10; Αρχείο mylib.cpp: float f1(int i) { return i / 3.0F; Πρόβλημα κατά τη σύνδεση των mylib.o και myapp.o. Αρχείο myapp.cpp: #include <iostream> using namespace std; // Λάθος! Oρίζεται και στο // mylib.cpp. Δύο ορισμοί! float f1(int i) { return 100 * i; cout << f1(f2(10)) << endl; 13
Αρχείο mylib.h: namespace auebsoft { float f1(int i); inline int f2(int i) { return i * 10; Αρχείο mylib.cpp: namespace auebsoft { float f1(int i) { return i / 3.0F; Χώροι ονομάτων Αρχείο myapp.cpp: #include <iostream> using namespace std; float f1(int i) { return 100 * i; cout << f1(1) // Τυπώνει 100. << auebsoft::f1(1) // 0.333333. << auebsoft::f2(1) // 10. << ::f1(1); // Τυπώνει 100. // cout << f2(1); // Λάθος: ανύπαρκτη // συνάρτηση. 14
Η εντολή using namespace Αρχείο mylib.h: namespace auebsoft { float f1(int i); inline int f2(int i) { return i * 10; Αρχείο mylib.cpp: namespace auebsoft { float f1(int i) { return i / 3.0F; Αρχείο myapp.cpp: #include <iostream> using namespace std; using namespace auebsoft; float f1(int i) { return 100 * i; cout << auebsoft::f1(1) // 0.333333. << auebsoft::f2(1) // 10. << ::f1(1) // Τυπώνει 100. << f2(1); // Τυπώνει 10. // cout << f1(1); // Λάθος. Δεν ξέρει // ποια να διαλέξει. 15
Τι κάνει η «using namespace»; Η εντολή using namespace μού επιτρέπει να αναφέρομαι στις συναρτήσεις, τάξεις κλπ. ενός χώρου ονομάτων χωρίς το «επώνυμό» τους. Αν όμως υπάρχει συνάρτηση, τάξη κλπ. με το ίδιο όνομα και στον ανώνυμο χώρο («::»), τότε δημιουργείται πρόβλημα αμφισημίας και πρέπει να χρησιμοποιήσω οπωσδήποτε τον τελεστή ::. Χωρίς το «using namespace std;» θα έπρεπε να γράφω std::string, std::cout, std::endl κλπ. 16
Χωρίς «using namespace std» #include <iostream> #include <string> std::string s; // H τάξη string ανήκει στο χώρο ονομάτων «std». // Το ίδιο και τα cout, cin, endl. std::cout << "Type a string: " << std::endl; std::cin >> s; std::cout << "You typed: " << s << std::endl; 17