Προγραμματισμός Υπολογιστών με C++ ( 2012-13 ) 7η διάλεξη Ίων Ανδρουτσόπουλος http://www.aueb.gr/users/ion/ 1
Τι θα ακούσετε σήμερα Τάξεις: δημόσια και ιδιωτικά μέλη, μέθοδοι inline. Αρχεία κεφαλίδων και τάξεις. Αποφυγή πολλαπλής εισαγωγής αρχείου κεφαλίδας. Κατασκευαστές. 2
class Person { public: string name; unsigned short year; unsigned phone; ; // Προσοχή, χρειάζεται «;». Τάξεις int main() { Person p1, p2; p1.name = "Γιάννης"; p2.name = "Μαρία"; p1.year = 1968; p2.year = 1970; p1.phone = 2108203571; p2.phone = 2108203572; cout << p1.name << ": " << p1.year << ", " << p1.phone << endl << p2.name << ": " << p2.year << ", " << p2.phone << endl; 3
Μέθοδοι (συναρτήσεις) σε τάξεις class Person { public: string name; unsigned short year; unsigned phone; void greeting(); ; void Person::greeting() { cout << "Το όνομά μου είναι " << name << endl; int main() { Person p1, p2; // Τιμές όπως στην προηγούμενη διαφάνεια. p1.greeting(); p2.greeting(); 4
Δημόσια και ιδιωτικά μέλη class Person { private: // Μόνο οι μέθοδοι της Person έχουν πρόσβαση σε αυτά: string name; unsigned short year; void test(); public: // Σε αυτά έχουν πρόσβαση όλοι: void set(const string& n, unsigned short y); void print(); ; void Person::set(const string& n, unsigned short y) { name = n; // ΟΚ. Οι μέθοδοι της Person έχουν πρόσβαση year = y; // στις ιδιωτικές μεταβλητές της Person. void Person:: print() { cout << name << ": " << year << endl; test(); // ΟΚ. Οι μέθοδοι της Person έχουν πρόσβαση στις // ιδιωτικές μεθόδους της Person. 5
Δημόσια/ιδιωτικά μέλη συνέχεια void Person::test() { cout << "δοκιμή" << endl; int main() { Person p1, p2; // p1.name = "Γιάννης"; // Λάθος. Το name είναι ιδιωτικό μέλος. p1.set("γιάννης", 1968); // ΟΚ. Καλώ δημόσιες μεθόδους p2.set("μαρία", 1970); // της Person. p1.print(); // Τυπώνει «Γιάννης: 1968 δοκιμή». p2.print(); // Τυπώνει «Μαρία: 1970 δοκιμή». // cout << p1.name; // Λάθος. Το name είναι ιδιωτικό μέλος. // p1.test(); // Λάθος. Η test() είναι ιδιωτικό μέλος. 6
Δημόσια ή ιδιωτικά; Δηλώνουμε ως δημόσια μόνο τα μέλη που χρειάζεται να γνωρίζει ο χρήστης της τάξης. Συνήθως δηλώνουμε ως ιδιωτικές τις μεταβλητές και γενικότερα τις δομές δεδομένων που χρησιμοποιούν εσωτερικά τα αντικείμενα της τάξης και επιτρέπουμε την είσοδο/έξοδο δεδομένων πρός/από αυτές μόνο μέσω δημόσιων μεθόδων της τάξης. Αυτό μας επιτρέπει να αλλάζουμε τον τρόπο αποθήκευσης των δεδομένων στο εσωτερικό των αντικειμένων της τάξης, χωρίς να επηρεάζονται προγράμματα που χρησιμοποιούν τις δημόσιες μεθόδους της. Μας επιτρέπει επίσης να ελέγχουμε μήπως τα δεδομένα που εισέρχονται προς τα αντικείμενα της τάξης παραβιάζουν περιορισμούς (π.χ. ηλικία > 150). 7
Μέθοδοι inline class Person { private: string name; unsigned short year; public: // Επιτόπου ορισμός. Η set() θα είναι inline // (βλ. προηγούμενες διαλέξεις): void set(const string& n, unsigned short y) { name = n; year = y; void print(); ; (. δήλωση // H print δεν είναι inline. (Εκτός αν γράψουμε «inline» στη void Person:: print() { cout << name << ": " << year << endl; 8
Αρχεία κεφαλίδων και τάξεις αρχείο person.h: #include <string> using namespace std; class Person { private: string name; unsigned short year; public: void set(const string& n, unsigned short y) { name = n; year = y void print(); ; 9
Αρχεία κεφαλίδας και τάξεις συνέχεια αρχείο person.cpp: #include "person.h" #include <iostream> using namespace std; void Person:: print() { // Δεν είναι inline. cout << name << ": " << year << endl; 10
Χρήση αρχείων κεφαλίδων με τάξεις αρχείο myapp.cpp: #include "person.h" int main() { Person p1, p2; p1.set("γιάννης", 1968); p2.set("μαρία", 1970); p1.print(); // Τυπώνει «Γιάννης: 1968» p2.print(); // Τυπώνει «Μαρία: 1970» 11
Προβλήματα με αρχεία κεφαλίδων αρχείο mylib1.h: #include "person.h" αρχείο mylib2.h: #include "person.h" void f(person p); αρχείο mynewapp.cpp: #include "person.h" #include "mylib1.h" #include "mylib2.h" void h(person p) { f(p); g(p); void g(person p); // To person.h περιλαμβάνεται 3 φορές και // ο ορισμός της τάξης person δίνεται // 3 φορές στο mynewapp.cpp. Λάθος! 12
Βελτιωμένο αρχείο person.h #ifndef _PERSON_H_ // Αν δεν έχει δημιουργηθεί η σταθερά // _PERSON_H_ του προεπεξεργαστή... #define _PERSON_H_ // Δημιουργία της σταθεράς. #include <string> using namespace std; class Person { private: string name; unsigned short year; public: void set(const string& n, unsigned short y) { name = n; year = y void print(); ; #endif Αν κατά λάθος περιλάβω δύο φορές το person.h σε ένα αρχείο, τη 2η φορά η σταθερά _PERSON_H_ θα υπάρχει και θα αγνοηθούν οι γραμμές μεταξύ #ifndef και #endif. 13
Η αναγκαιότητα των κατασκευαστών class Person { string name; unsigned short year; Στη C++11 επιτρέπονται και τέτοιες αρχικοποιήσεις. // unsigned short year = 1980; // Λάθος. Δεν επιτρέπεται. public: void setname(const string& n) { name = n; void setyear(unsigned short y) { year = y; void print() { cout << name << ": " << year << endl; ; int main() { Person p1; // Τα p1.name και p1.year δεν έχουν αρχικοποιηθεί. p1.print(); // Τυπώνει «σκουπίδια» (τυχαίες τιμές). 14
Κατασκευαστές class Person { string name; unsigned short year; public: void setname(const string& n) { name = n; void setyear(unsigned short y) { year = y; void print() { cout << name << ": " << year << endl; Person(const string& n, unsigned short y); // Κατασκευαστής ; Person::Person(const string& n, unsigned short y) { name = n; year = y; int main() { // Person p1; // Λάθος. Δεν επιτρέπεται πια! Person p2 = Person("Γιώργος", 1975); p2.print(); // Τυπώνει «Γιώργος: 1975». 15