Εισαγωγή. 1 Γενικά. 2 Προγράμματα σε C++ 5 Νοεμβρίου 2012

Σχετικά έγγραφα
Υπερφόρτωση τελεστών

Προγραμματισμός Ι. Κλάσεις και Αντικείμενα. Δημήτρης Μιχαήλ. Τμήμα Πληροφορικής και Τηλεματικής Χαροκόπειο Πανεπιστήμιο

Προγραμματισμός Ι. Εισαγωγή στην C++ Δημήτρης Μιχαήλ. Τμήμα Πληροφορικής και Τηλεματικής Χαροκόπειο Πανεπιστήμιο

3ο σετ σημειώσεων - Πίνακες, συμβολοσειρές, συναρτήσεις

Εισαγωγή σε αντικειμενοστραφή concepts. Και λίγη C#

Ερωτήσεις και απαντήσεις στα θέματα του κανονισμού κατάρτισης

Κλάσεις και αντικείμενα #include <iostream.h<

Η-Υ ΠΡΟΓΡΑΜΜΑΤΙΣΜΟΣ. Εργαστήριο 1 Εισαγωγή στη C. Σοφία Μπαλτζή s.mpaltzi@di.uoa.gr

Pascal. 15 Νοεμβρίου 2011

Εισαγωγή στον Προγραμματισμό με C++

Προγραμματισμός ΙI (Θ)

Κλήση Συναρτήσεων ΚΛΗΣΗ ΣΥΝΑΡΤΗΣΕΩΝ. Γεώργιος Παπαϊωάννου ( )

ΥΠΟΛΟΓΙΣΤΕΣ ΙΙ. Τι περιλαμβάνει μια μεταβλητή; ΔΕΙΚΤΕΣ. Διεύθυνση μεταβλητής. Δείκτης

Δομημένος Προγραμματισμός

Η γλώσσα προγραμματισμού C

Γλώσσα Προγραμματισμού C++ Εισαγωγή - Μια πρώτη ματιά

Προγραμματιστικές τεχνικές

Αντικειμενοστραφείς Γλώσσες Προγραμματισμού C++ / ROOT

Εισαγωγή στον Προγραμματισμό

Εισαγωγή στον Προγραμματισμό με C++

5ο σετ σημειώσεων - Δείκτες

Προγραμματισμός Ι. Δείκτες. Δημήτρης Μιχαήλ. Τμήμα Πληροφορικής και Τηλεματικής Χαροκόπειο Πανεπιστήμιο

Στη C++ υπάρχουν τρεις τύποι βρόχων: (a) while, (b) do while, και (c) for. Ακολουθεί η σύνταξη για κάθε μια:

Τι είναι κλάση Κλάση

Εισαγωγή στον Προγραμματισμό

Διαδικασιακός Προγραμματισμός

Δομή Προγράμματος C++, Χειρισμός Μεταβλητών και Συναρτήσεις Εισόδου - Εξόδου

Κλάσεις και Αντικείµενα

Εισαγωγή στην C. Μορφή Προγράµµατος σε γλώσσα C

Εαρινό. Ύλη εργαστηρίου, Ασκήσεις Java

ΟΝΤΟΚΕΝΤΡΙΚΟΣ ΠΡΟΓΡ/ΣΜΟΣ C++

Προγραμματισμός Ι (ΗΥ120)

Τελικό τεστ - απαντήσεις

Προγραμματισμός Ι. Εγγραφές. Δημήτρης Μιχαήλ. Τμήμα Πληροφορικής και Τηλεματικής Χαροκόπειο Πανεπιστήμιο

Δομημένος Προγραμματισμός. Τμήμα Επιχειρηματικού Σχεδιασμού και Πληροφοριακών Συστημάτων

ΠΟΛΥΜΟΡΦΙΣΜΟΣ. 4.1 Κληρονομικότητα και Αρχή της Υποκατάστασης

Ανάπτυξη και Σχεδίαση Λογισμικού

Η πρώτη παράμετρος είναι ένα αλφαριθμητικό μορφοποίησης

Σημειώσεις του εργαστηριακού μαθήματος Πληροφορική ΙΙ. Εισαγωγή στην γλώσσα προγραμματισμού

Εισαγωγή στον Προγραµµατισµό. Πανεπιστήµιο Θεσσαλίας Τµήµα Ηλεκτρολόγων Μηχανικών και Μηχανικών Η/Υ

ΑΝΤΙΚΕΙΜΕΝΟΣΤΡΑΦΗΣ ΠΡΟΓΡΑΜΜΑΤΙΣΜΟΣ

2.1 Αντικειµενοστρεφής προγραµµατισµός

ΥΠΟΛΟΓΙΣΤΕΣ ΙI. Άδειες Χρήσης. Δομή του προγράμματος. Διδάσκοντες: Αν. Καθ. Δ. Παπαγεωργίου, Αν. Καθ. Ε. Λοιδωρίκης

Αντικειμενοστρεφής Προγραμματισμός

Εισαγωγή στην γλώσσα προγραμματισμού C

ΠΑΝΕΠΙΣΤΗΜΙΟ ΘΕΣΣΑΛΙΑΣ ΣΧΟΛΗ ΘΕΤΙΚΩΝ ΕΠΙΣΤΗΜΩΝ ΤΜΗΜΑ ΠΛΗΡΟΦΟΡΙΚΗΣ

Πίνακες. 1 Πίνακες. 30 Μαρτίου 2014

Προγραμματισμός Ι. Δυναμική Διαχείριση Μνήμης. Δημήτρης Μιχαήλ. Ακ. Έτος Τμήμα Πληροφορικής και Τηλεματικής Χαροκόπειο Πανεπιστήμιο

Δομές Επανάληψης. Εισαγωγή στη C++

2 Ορισμός Κλάσεων. Παράδειγμα: Μηχανή για Εισιτήρια. Δομή μιας Κλάσης. Ο Σκελετός της Κλάσης για τη Μηχανή. Ορισμός Πεδίων 4/3/2008

Εισαγωγή στον Αντικειμενοστρεφή Προγραμματισμό Διάλεξη #2

Κεφάλαιο Αλφαριθμητικές Σειρές Χαρακτήρων (Strings) (Διάλεξη 20) 1) Strings στη C

ΤΕΧΝΙΚΕΣ ΑΝΤΙΚΕΙΜΕΝΟΣΤΡΑΦΟΥΣ ΠΡΟΓΡΑΜΜΑΤΙΣΜΟΥ. Αντικείμενα με πίνακες. Constructors. Υλοποίηση Στοίβας

Αντικειμενοστραφής Προγραμματισμός

ΤΕΧΝΙΚΕΣ ΑΝΤΙΚΕΙΜΕΝΟΣΤΡΑΦΟΥΣ ΠΡΟΓΡΑΜΜΑΤΙΣΜΟΥ. Κλάσεις και Αντικείμενα Constructors, equals, tostring

ΜΑΘΗΜΑ: Αντικειμενοστρεφής Προγραμματισμός

ΥΠΟΛΟΓΙΣΤΕΣ ΙI. Άδειες Χρήσης. Δείκτες Διδάσκοντες: Αν. Καθ. Δ. Παπαγεωργίου, Αν. Καθ. Ε. Λοιδωρίκης

Προγραµµατιστικές τεχνικές

Αντικειμενοστραφείς Γλώσσες Προγραμματισμού C++ / ROOT

Διαδικασιακός Προγραμματισμός

ΠΛΗΡΟΦΟΡΙΚΗ ΙΙ (JAVA) 11/3/2008

Δομημένος Προγραμματισμός

Γραφικά υπολογιστών Εργαστήριο 9 Κλάσεις στην Python. Σκοπός της 9ης άσκησης είναι να μάθουμε αντικειμενοστρεφή προγραμματισμό στην Python.

Οντοκεντρικός Προγραμματισμός

Ενδεικτική περιγραφή μαθήματος

Αντικειμενοστρέφεια. Henri Matisse, Harmony in Red, Κωστής Σαγώνας Νίκος Παπασπύρου

Διδάσκων: Κωνσταντίνος Κώστα Διαφάνειες: Δημήτρης Ζεϊναλιπούρ

Εντολές ελέγχου ροής if, for, while, do-while

ΑΣΚΗΣΗ 5: ΠΙΝΑΚΕΣ. Σχήµα 1: H έννοια των πινάκων

ΕΡΓΑΣΤΗΡΙΟ 3: Προγραμματιστικά Περιβάλλοντα και το Πρώτο Πρόγραμμα C

ΤΕΧΝΙΚΕΣ ΑΝΤΙΚΕΙΜΕΝΟΣΤΡΑΦΟΥΣ ΠΡΟΓΡΑΜΜΑΤΙΣΜΟΥ. Κλάσεις και Αντικείμενα Constructors

ΤΕΧΝΙΚΕΣ ΑΝΤΙΚΕΙΜΕΝΟΣΤΡΑΦΟΥΣ ΠΡΟΓΡΑΜΜΑΤΙΣΜΟΥ. Μαθήματα από τα εργαστήρια

ΤΕΧΝΙΚΕΣ ΑΝΤΙΚΕΙΜΕΝΟΣΤΡΑΦΟΥΣ ΠΡΟΓΡΑΜΜΑΤΙΣΜΟΥ. Κλάσεις και Αντικείμενα Αναφορές

Προγραμματισμός Ι. Προχωρημένα Θέματα. Δημήτρης Μιχαήλ. Τμήμα Πληροφορικής και Τηλεματικής Χαροκόπειο Πανεπιστήμιο

ΠΡΟΓΡΑΜΜΑΤΙΣΜΟΣ ΥΠΟΛΟΓΙΣΤΩΝ & ΥΠΟΛΟΓΙΣΤΙΚΗ ΦΥΣΙΚΗ

ΣΕΤ ΑΣΚΗΣΕΩΝ 3. Προθεσµία: 7/1/2014, 22:00

Τι χρειάζεται ένας φοιτητής για τη σωστή παρακολούθηση και συμμετοχή στο μαθημα;

ΤΕΧΝΙΚΕΣ ΑΝΤΙΚΕΙΜΕΝΟΣΤΡΑΦΟΥΣ ΠΡΟΓΡΑΜΜΑΤΙΣΜΟΥ. Κλάσεις και Αντικείμενα

3 Αλληλεπίδραση Αντικειμένων

ΜΕΤΑΓΛΩΤΤΙΣΤΕΣ. Στην εξοικείωση με τη διαδικασία κατασκευής ενός Λεξικού Αναλυτή κάνοντας χρήση του lex.

Διάλεξη 3η: Τύποι Μεταβλητών, Τελεστές, Είσοδος/Έξοδος

Πληροφορική 2. Γλώσσες Προγραμματισμού

B. Ενσωμάτωση Ιθαγενών Μεθόδων

Κεφάλαιο 8.7. Πολυδιάστατοι Πίνακες (Διάλεξη 19)

Προγραμματισμός Η/Υ (ΤΛ2007 )

Δομημένος Προγραμματισμός (ΤΛ1006)

Προγραμματισμός Υπολογιστών με C++

Η βασική συνάρτηση προγράμματος main()

Προγραμματισμός Υπολογιστών με C++

ΕΡΓΑΣΤΗΡΙΟ 3: Προγραμματιστικά Περιβάλλοντα και το Πρώτο Πρόγραμμα C

ΥΠΟΛΟΓΙΣΤΕΣ ΙΙ. Τι είναι ; Συναρτήσεις. Παράδειγμα #1. double convert ( double cm ) { double inch;

Προγραμματισμός Υπολογιστών με C++

ΤΕΧΝΙΚΕΣ ΑΝΤΙΚΕΙΜΕΝΟΣΤΡΑΦΟΥΣ ΠΡΟΓΡΑΜΜΑΤΙΣΜΟΥ. Κλάσεις και Αντικείμενα

Γραφικά υπολογιστών Εργαστήριο 1 Εισαγωγή στην Python

ΕΡΓΑΣΤΗΡΙΟ 3: Προγραμματιστικά Περιβάλλοντα και το Πρώτο Πρόγραμμα C

ΥΠΟΛΟΓΙΣΤΕΣ ΙI. Άδειες Χρήσης. Συναρτήσεις I Διδάσκοντες: Αν. Καθ. Δ. Παπαγεωργίου, Αν. Καθ. Ε. Λοιδωρίκης

Στοιχειώδης προγραμματισμός σε C++

Κεφάλαιο ΙV: Δείκτες και πίνακες. 4.1 Δείκτες.

Γ7.1 Επανάληψη ύλης Β Λυκείου. Γ Λυκείου Κατεύθυνσης

Γραφικά υπολογιστών Εργαστήριο 10 Εισαγωγή στα Sprites

Transcript:

Εισαγωγή 5 Νοεμβρίου 2012 1 Γενικά Η C++ αναπτύχθηκε με στόχο την ενσωμάτωση χαρακτηριστικών του αντικειμενοστρεφούς προγραμματισμού στη διαδικαστική C. Δεν θεωρείται αμιγής αντικειμενοστρεφής γλώσσα αλλά συνδυάζει την προς τα πίσω συμβατότητα με τις βιβλιοθήκες της C ενώ εμφανίζει και χαρακτηριστικά του OOP (Object Oriented Programming) όπως Abstraction (αφαιρετικότητα) Encapsulation (ενθυλάκωση) Inheritance (κληρονομικότητα) Polymorphism (πολυμορφισμός) Η φιλοσοφία του OOP είναι ότι για να λυθεί ένα πρόβλημα πρέπει τα αντικείμενα του πραγματικού κόσμου να υλοποιηθούν στον υπολογιστή ως ξεχωριστά αντικείμενα. Κάθε αντικείμενο ανήκει σε κάποια κλάση που περιγράφει τα κοινά χαρακτηριστικά των αντικειμένων. Τα αντικείμενα περιέχουν τα δεδομένα και τις διαδικασίες που τα αφορούν. 2 Προγράμματα σε C++ Τα αρχεία πηγαίου κώδικα (source code) της C++ τυπικά έχουν κατάληξη.cc ή.cpp ή.cc ή ό,τι άλλο λέει ο μεταγλωττιστής και το περιβάλλον εργασίας σας. Μιας και η προς τα πίσω συμβατότητα με τη C ήταν μία από τις βασικές σχεδιαστικές αρχές της γλώσσας θα περίμενε κανείς ότι το παρακάτω πρόγραμμα είναι ένα νόμιμο πρόγραμμα C++. 1 # include <stdio.h> 2 int main() { 3 printf(" Hello world\n"); 4 } Αυτό είναι αλήθεια. Όμως ένας πιο C++ τρόπος να χαιρετίσει κανείς τον κόσμο θα ήταν ο ακόλουθος: 1

1 # include <iostream > 2 int main() { 3 std:: cout << " Hello, world!" << std:: endl; 4 return 0; 5 } Μερικές παρατηρήσεις: Η στάνταρ βιβλιοθήκη εισόδου/εξόδου χαρακτήρων στην C++ είναι η iostream. Τα αρχεία συμπερίληψης (include files) της C++ δεν έχουν την κατάληξη.h. Το αντικείμενο που αναλαμβάνει την έξοδο χαρακτήρων ονομάζεται cout. Δεν αρκεί να χρησιμοποιήσουμε το όνομα cout αλλά πρέπει να προσδιορίσουμε την βιβλιοθήκη στην οποία ορίζεται γράφοντας μπροστά το όνομά της και δύο άνω-κάτω τελείες: std::cout. Στην πραγματικότητα το std δεν είναι βιβλιοθήκη αλλά ένας χώρος ονομάτων (namespace). Ο τελεστής bit-ολίσθησης << όταν εφαρμόζεται στο αντικείμενο cout έχει ως αποτέλεσμα την εκτύπωση και όχι την bit-ολίσθηση. Αυτό λέγεται υπερφόρτωση (overloading) δηλαδή η απόδοση περισσότερων από μίας λειτουργιών στο ίδιο όνομα ή τελεστή. Για να μην γράφουμε το std:: κάθε φορά που θέλουμε να χρησιμοποιήσουμε ένα όνομα που είναι δηλωμένο σε αυτό το namespace, μπορούμε να δηλώσουμε στην γλώσσα namespaces στα οποία θέλουμε να γίνεται αναζήτηση γράφοντας 1 using namespace std; μετά τη γραμμή με το #include <iostream>. Με τον ίδιο τρόπο που χρησιμοποιούμε το αντικείμενο cout για να τυπώσουμε στην οθόνη, μπορούμε να χρησιμοποιούμε το αντικείμενο cin για να διαάζουμε τιμές μεταβλητών από το πληκτρολόγιο, π.χ. όπως στο παρακάτω παράδειγμα, όπου με την εντολή cin >> x; η τιμή που θα δώσει ο χρήστης στο πληκτρολόγιο αποηθηκεύεται στην μεταβλητή x. 1 # include <iostream > 2 using namespace std; 3 4 int main() 5 { 6 int x; 7 cout << "Dose mia timi: "; 8 cin >> x; 9 cout << " Edoses tin timi " << x << endl; 10 11 return 0; 12 } 2

3 Κλάσεις Στην C++ μπορούμε να ορίζουμε νέες κλάσεις τις οποίες μπορεί κανείς να φανταστεί ως κατηγορίες αντικειμένων. Για παράδειγμα θα μπορούσαμε να ορίσουμε κλάσεις για την αναπαράσταση ανθρώπων, αυτοκινήτων, κτηρίων, τρισδιάσταστων σημείων ή ότι άλλο έπρεπε να χειριστούμε στο πρόγραμμά μας. Μία κλάση δεν περιγράφει ένα συγκεκριμένο πράγμα αλλά είναι μια γενική περιγραφή αντικειμένων με παρόμοιες ιδιότητες. Έχοντας ορίσει κάποιες κλάσεις σε ένα πρόγραμμα, μπορούμε να δημιουργήσουμε στιγμιότυπα αυτών των κλάσεων δηλαδή συγκεκριμένα αντικείμενα που υπάγονται στην κλάση. Για παράδειγμα, αν σε ένα πρόγραμμα είχαμε ορίσει κάποια κλάση κτήριο, θα μπορούσαμε να έχουμε ένα στιγμιότυπο αυτής της κλάσης που να αντιστοιχεί στο δημαρχείο, ένα για την αποκεντρωμένη διοίκηση, ένα για το ΙΚΑ. Ή έχοντας δηλώσει μία κλάση για την αναπαράσταση αυτοκινήτων, θα μπορούσαμε να δημιουργήσουμε ένα αντικείμενο για το αυτοκίνητο με αριθμό κυκλοφορίας ΥΜΕ 1475, ένα για το ΙΕΤ 2029 κτλ. Μία κλάση λοιπόν είναι μία αφηρημένη, γενικη περιγραφή ενός συνόλου πραγματών. Σε ένα πρόγραμμα μπορούμε να έχουμε αντικείμενα που υπάγονται σε μία κλάση, δηλαδή έχουν τα χαρακτηριστικά και τις ιδιότητες αυτής. Κάθε αντικείμενο μπορεί να προέρχεται από μία και μόνο μία κλάση. Δεν μπορεί δηλαδή ένα αντικείμενο να ανήκει σε δύο ή περισσότερες κλάσεις¹. Οι κλάσεις στην C++, αφού δηλωθούν, μπορούν να χρησιμοποιηθούν όπως και οι βασικοί ή άλλοι τύποι της γλώσσας. 3.1 Δήλωση κλάσης και αντικείμενα Η δήλωση μιας κλάσης έχει τη μορφή 1 class onoma_klasis { 2... 3 }; Δηλαδή τη δεσμευμένη λέξη class ακολουθούμενο από το όνομα που θέλουμε να δώσουμε στην κλάση μας και στη συνέχεια μέσα σε άγκιστρα, τις δηλώσεις και τους ορισμούς που αφορούν την κλάση. Μετά το τελικό άγκιστρο ακολουθεί ελληνικό ερωτηματικό. Αν για παράδειγμα θέλαμε να φτιάξουμε μια κλάση για την αναπαράσταση μιγαδικών αριθμών θα μπορούσαμε να ξεκινήσουμε κάπως έτσι: 1 class cplex { 2 }; Ο παραπάνω ορισμός είναι σωστός και πλήρης οπότε μπορούμε να τον χρησιμοποιήσουμε σε ένα πρόγραμμα για να ορίσουμε αντικείμενα αυτής της κλάσης. 4 Μέλη κλάσεων Κάθε κλάση μπορεί να περιέχει δύο ειδών μέλη: ¹Θα δούμε στη συνέχεια όμως ότι με το μηχανισμό της κληρονομικότητας μπορούμε αν θέλουμε να συνδυάσουμε τα χαρακτηριστικά δύο κλάσεων να φτιάξουμε μια καινούρια. 3

Μέλη δεδομένων (data members) και Μεθόδους (methods). 4.1 Μέλη δεδομένων Τα μέλη δεδομένων είναι μεταβλητές (βασικών ή άλλων τύπων). Είναι τα δεδομένα που συναπαρτίζουν κάθε ένα αντικείμενο της συγκεκριμένης κλάσης. Για παράδειγμα μία κλάση που θα αναπαριστούσε έναν μιγαδικό αριθμό με ένα πραγματικό και ένα φανταστικό μέρος θα μπορούσε να είναι όπως αυτή: 1 class cplex { 2 float re; // Pragmatiko meros 3 float im; // Fantastiko meros 4 }; Ή μια κλάση που θα αναπαριστούσε ένα αντικείμενο που κινείται στο χώρο δύο διαστάσεων και επομένως θα είχε δύο συντεταγμένες και ταχύτητα με δύο συνιστώσες θα μπορούσε να είναι κάπως έτσι: 1 class moving { 2 float x, y; // Syntetagmenes 3 float vx, vy; // Synistoses taxititas 4 }; Οι δηλώσεις των μελών μιας κλάσης είναι όπως και οι δηλώσεις μεταβλητών-μελών των struct στη C. Προφανώς, τα μέλη μίας κλάσης πρέπει να δηλώνονται μέσα στον ορισμό της κλάσης δηλαδή μέσα στα άγκιστρα που ακολουθούν τη δήλωση class onoma_klasis. Προσέξτε όμως ότι δεν επιτρέπεται η αρχικοποίησή τους, π.χ. γράφοντας παραπάνω float re = 0; (Γιατί; ²). Έχοντας ορίσει μία κλάση, μπορούμε να χρησιμοποιήσουμε όπως αναφέρουμε παραπάνω το όνομά της όπως τα ονόματα των βασικών τύπων της C++ για να δημιουργήσουμε αντικείμενα αυτής της κλάσης. Π.χ. έχονας ορίσει τις κλάσεις cplex και moving όπως παραπάνω μπορούμε να δηλώσουμε αντικείμενα όπως στο ακόλουθο παράδειγμα: 1 int main() 2 { 3 moving rock, ship; 4 cplex a, b, c; 5 } ²Για να αρχικοποιηθεί μια μεταβλητή ας πούμε x με μία τιμή θα πρέπει η μεταβλητή να είναι αντιστοιχισμένη σε μία θέση μνήμης στην οποία και θα αποθηκευτεί η τιμή. Αυτό δεν ισχύει στην περίπτωσή μας γιατί μιλάμε για ένα μέλος μιας κλάσης και όχι κάποιου συγκεκριμένου αντικειμένου. Με άλλα λόγια η δήλωση μιας κλάσης περιγράφει πώς θα ήταν ένα αντικείμενο αν υπήρχε. Αντικείμενα αυτής της κλάσης δεν θα μπορούσαν καν να υπάρχουν πριν ολοκληρωθεί η δήλωση. Θα μπορούσε βέβαια κάποιος να σκεφτεί ότι οι μηχανισμοί της γλώσσας θα μπορούσαν να λειτουργήσουν έτσι ώστε η αρχικοποίηση να γίνεται κάθε φορά που δημιουργείται ένα αντικείμενο αυτής της κλάσης και αυτή η σκέψη θα ήταν σωστή. Αλλά αυτήν τη δουλειά στην C++ την κάνουν οι constructors, ειδικές μέθοδοι για τις οποίες θα μιλήσουμε στη συνέχεια. 4

Εδώ τα αντικείμενα rock και ship είναι τύπου moving ενώ τα a, b και c είναι τύπου cplex. Από τη συνάρτηση main, μπορούμε να προσπελάσουμε τα μέλη δεδομένων των παραπάνω αντικειμένων τόσο για ανάγνωση όσο και για εγγραφή χρησιμοποιώντας την τελεστή. (τελεία) μετά από το όνομα του αντικειμένου και στη συνέχεια γράφοντας το όνομα της μεταβλητής-μέλους που μας ενδιαφέρει, π.χ. κάπως έτσι: 1 rock.x = 10; 2 rock.y = 2 * rock.x; 3 ship.x = rock.x + 100; 4 a. re = 0; 5 a. im = 0; Αν δοκιμάσετε να γράψετε τις παραπάνω εντολές ο μεταγλωττιστής θα σας δώσει μηνύματα λάθους σχετικά με τα δικαιώματα πρόσβασης στα μέλη των κλάσεων. Θα αναφερθούμε αναλυτικά στη συνέχεια στα δικαιώματα πρόσβασης και πώς μπορούμε να λύσουμε το πρόβλημα που παρουσιάζεται. 4.2 Μέθοδοι Εκτός από μέλη δεδομένων, μία κλάση μπορεί να έχει και συναρτήσεις-μέλη. Δεν είναι απαραίτητο, καθώς η C++ επιστρέπει τον ορισμό κλάσεων χωρίς συναρτήσεις-μέλη αλλά αυτό σπάνια συμβαίνει στην πράξη. Οι συναρτήσεις-μέλη αναφέρονται συχνότερα ως μέθοδοι (methods). Οι μέθοδοι μιας κλάσης δηλώνονται μέσα στο σώμα της κλάσης με τρόπο όμοιο με εκείνον που δηλώνονται οι συναρτήσεις της C, δηλαδή ακολουθώντας το γενικό σχήμα 1 return_type method_name( parameter_list) {... } όπου: return_type είναι ο τύπος της τιμής που επιστρέφει η μέθοδος ή void αν δεν επιστρέφει κάτι. method_name είναι το όνομα της μεθόδου, το οποίο ακολουθεί τους κανόνες σχηματισμού ονομάτων (δεν ξεκινάει με αριθμό, περιέχει αλφαριθμητικά σύμβολα κτλ). parameter_list είναι η λίστα των τυπικών παραμέτρων της μεθόδου η οποία μπορεί να είναι και κενή. Οι παράμετροι, αν υπάρχουν, μπορούν να είναι μία ή περισσότερες και χωρίζονται μεταξύ τους με κόμματα. Κάθε δήλωση παραμέτρου είναι ένα ζευγάρι της μορφής param_type param_name όπου param_name είναι το όνομα της παραμέτρου και param_type ο τύπος της. Τέλος, μέσα στα άγκιστρα βρίσκεται το σώμα της μεθόδου, δηλαδή οι εντολές που εκτελούνται όταν καλείται. Μέσα στο σώμα της μεθόδου μπορούμε να δηλώσουμε τοπικές μεταβλητές ή να αναφερθούμε στα μέλη δεδομένων του αντικειμένου για το οποίο καλείται η μέθοδος. Δείτε π.χ. τo παρακάτω πρόγραμμα: 1 # include <iostream > 2 using namespace std; 3 5

4 class cplex { 5 public: 6 float re, im; 7 8 void print() { 9 cout << "(" << re << "," << im << ")" << endl; 10 } 11 12 void increase( float a, float b) { 13 re += a; 14 im += b; 15 } 16 17 void add( cplex other) { 18 re += other. re; 19 im += other. im; 20 } 21 }; 22 23 int main() 24 { 25 cplex a; 26 a. re = 5; a. im = 10; 27 a.print(); 28 a. increase(20, 30); 29 a.print(); 30 31 cplex b; 32 b. re = 12; b. im = 24; 33 a.add(b); 34 a.print(); 35 36 return 0; 37 } 4.3 Δικαιώματα πρόσβασης Στο προηγούμενο παράδειγμα, στη γραμμή 5, εμφανιζόταν η λέξη public:. Επίσης στην ενότητα για τα μέλη δεδομένων είδαμε ότι ο μεταγλωττιστής έδινε μήνυμα λάθους όταν προσπαθούσαμε να προσπελάσουμε μέλη δεδομένων της κλάσης παρόλο που το συντακτικό ήταν σωστό. Στην C++ όλα τα μέλη είναι εξ ορισμού κρυφά δηλαδή κανείς δεν μπορεί να τα προσπελάσει για ανάγνωση ή εγγραφή από τα έξω. Στην ορολογία της C++ αυτά τα μέλη λέγονται private (ιδιωτικά), και όταν λέμε ότι όλα τα μέλη είναι εξ ορισμού ιδιωτικά εννοούμε ότι αν δεν δηλώσουμε ρητά το αντίθετο, κανένα μέλος μίας κλάσης δεν είναι ορατό από τα έξω. Αν θέλουμε ένα μέλος (είτε δεδομένων είτε μέθοδος) να είναι ορατό από έξω θα πρέπει να βάλουμε 6

πριν τη δήλωσή του μέσα στην κλάση, την λέξη public:. Τέτοια μέλη λέγονται public (δημόσια). Για να κάνουμε ένα μέλος δημόσιο, γράφουμε πριν τη δήλωσή του μέσα στην κλάση την λέξη public:. Για να κάνουμε ένα μέλος ιδιωτικό, γράφουμε private:. Δεν χρειάζεται να γράφουμε μία από αυτές τις δύο λέξεις πριν από κάθε λέξη: Ο κανόνας είναι ότι αν κάπου μέσα στη δήλωση μιας κλάσης εμφανιστεί o προσδιοριστής δικαιωμάτων public: ή ο προσδιοριστής private:, τότε όλα τα μέλη από εκείνο το σημείο και κάτω είναι δημόσια ή ιδιωτικά αντίστοιχα, μέχρι τον επόμενο προσδιοριστή. Δείτε το παρακάτω παράδειγμα: 1 class acctest { 2 int a; 3 int b; 4 public: 5 int c; 6 int d; 7 private: 8 int e; 9 10 void m1() {} 11 public: 12 void m2() { e = 0; } 13 void m3() {} 14 private: 15 void m4() {} 16 }; 17 18 int main() 19 { 20 acctest test; 21 test.a = 0; 22 test.b = 0; 23 test.c = 0; 24 test.d = 0; 25 test.e = 0; 26 27 test.m1(); 28 test.m2(); 29 test.m3(); 30 test.m4(); 31 } Εδώ δηλώνουμε μια κλάση με διάφορα μέλη και μεθόδους, δηλώνουμε ένα αντικείμενο της κλάσης στην γραμμή 20 και στην συνέχεια στις γραμμές 21 έως 30 προσπαθούμε να προσπελάσουμε τα μέλη ή να καλέσουμε τις μεθόδους. Αν μεταγλωττίσετε το πρόγραμμα θα δείτε ότι ο μεταγλωττιστής διαμαρτύρεται σχετικά με το ότι κάποια μέλη είναι ιδιωτικά, άρα η προσπέλασή τους δεν επιτρέπεται. Ας δούμε γιατί: Εξ ορισμού τα μέλη της κλάσης είναι ιδιωτικά. Άρα τα μέλη a και b είναι ιδιωτικά αφού δεν εμφανίζεται πριν από αυτά ο προσδιοριστής public:. Ο οποίος όμως εμφανίζεται στην 7

γραμμή 4 οπότε τα μέλη που βρίσκονται κάτω από αυτόν και μέχρι την επόμενη εμφάνιση κάποιου προσδιοριστή είναι δημόσια. Άρα τα μέλη c και d είναι δημόσια. Στην γραμμή 7 εμφανίζεται ο προσδιοριστής public: οπότε το μέλος e και η μέθοδος m1 στις γραμμές 8 και 10 είναι ιδιωτικά. Ανάλογα οι μέθοδοι m2 και m3 είναι δημόσιες, ενώ η m3 είναι ιδιωτική. Παρατηρήστε το εξής: Παρόλο που το μέλος e της γραμμής 8 είναι ιδιωτικό, ο μεταγλωττιστής δεν δίνει μήνυμα λάθους όταν στην γραμμή 12, το αλλάζει η μέθοδος m2. Ο κανόνας είναι ότι η πρόσβαση στα ιδιωτικά μέλη απαγορεύεται για όλους τους από έξω αλλά επιτρέπεται για τις μεθόδους της ίδιας της κλάσης. Τελικά λοιπόν³: Τα public μέλη μιας κλάσης είναι προσβάσιμα από οπουδήποτε σε ένα πρόγραμμα. Τα private μέλη μιας κλάσης είναι προσβάσιμα μόνο από μεθόδους της ίδιας της κλάσης. 4.4 Σχόλια για τα δικαιώματα πρόσβασης Για τους αρχάριους στη C++ τα δικαιώματα πρόσβασης μπορεί να είναι πρόβλημα καθώς ο μεταγλωττιστής αρνείται την πρόσβαση σε μέλη μιας κλάσης. Συχνά λοιπόν καταφεύγουν στην εύκολη λύση, του να βάζουν τον προσδιοριστή public: κάπου ψηλά μέσα στην δήλωση της κλάσης, αμέσως μετά το άγκιστρο στην επικεφαλίδα class onoma_klasis {. Αυτό για αρχή δεν είναι και τόσο κακό προκειμένου να προχωρήσει κανείς που ξεκινάει να μαθαίνει τη γλώσσα αλλά είναι κακός προγραμαμτισμός και μάλλον απαράδεκτο σε πραγματικές συνθήκες. Για ποιο λόγο όμως είναι καλός προγραμματισμός να απαγορεύει κάποιος την πρόσβαση σε κάποια μέλη της κλάσης του; Ο λόγος είναι ότι πολλές φορές, η πρόσβαση θα πρέπει να ακολουθεί κάποιους κανόνες τους οποίους θέτει αυτός που φτιάχνει την κλάση και τους οποίους εύκολα μπορεί να παραβλέψει κάποιος που την χρησιμοποιεί. Ένα παράδειγμα θα βοηθήσει: Υποθέστε ότι φτιάχνετε την παρακάτω κλάση προκειμένου να αναπαραστήσετε ένα αντικείμενο στον χώρο δύο διαστάσεων. Το σκεπτικό σας είναι να το εμφανίσετε κάποια στιγμή σε μια οθόνη διαστάσεων 400 επί 400 πίξελς οπότε οι συντεταγμένες x και y θα πρέπει να έχουν τιμές από 0 μέχρι και 399. 1 class point2d { 2 int x, y; 3 }; Αν τώρα αυτή η κλάση είναι πολύ καλή και όλοι θέλουν να την χρησιμοποιήσουν, τους την δίνετε ή τους την πουλάτε και εκείνοι δηλώνουν στα προγράμματα τους αντικείμενα αυτής της κλάσης γράφοντας point2d a, b; και φυσικά θα θέλουν να ορίσουν τις συντεταγμένες των σημείων γράφοντας a.x = 100;, a.y = 200;, b.x = 50; κτλ. Το πρόβλημα είναι ότι κανείς δεν τους απαγορεύει να γράψουν a.x = -50; ή a.y = 500; δηλαδή να θέσουν τιμές τις οποίες εσείς δεν θα επιτρέπατε. Και ακόμα, αυτό μπορεί να συμβεί και από εσάς τους ίδιους γιατί απλώς (ανθρώπινο) ξεχάσατε τους περιορισμούς που είχατε θέσει σε ένα πρόγραμμα που γράψατε πριν τρία χρόνια. Άρα θα ήταν καλό να μην επιτρέπετε ελεύθερη πρόσβαση στα μέλη της παραπάνω κλάσης. Αν όμως κάνετε τα μέλη x καιy ιδιωτικά, πώς θα μπορούσε κανείς να τα αλλάξει και επίσης, για να επανέρθουμε στο σημείο από όπου ξεκινήσαμε, πώς θα μπορούσε να αποφύγει την απόδοση λανθασμένων τιμών ³Εκτός από τους προσδιοριστές public και private υπάρχει και ο protected για τον οποίο θα μιλήσουμε αργότερα όταν αναφερθούμε στην κληρονομικότητα 8

σε αυτά; Τυπικά, στην C++αυτό γίνεται κάνοντας το μέλος ιδιωτικό και γράφοντας δύο δημόσιες μεθόδους με τις οποίες πραγματοποιείται η πρόσβαση σε αυτά. Δηλάδη για την παραπάνω κλάση, θα κάναμε τα μέλη x και y private και θα γράφαμε για κάθε ένα από αυτά δύο μεθόδους: μία για να του αναθέτουμε νέα τιμή και μία για να διαβάζουμε την τιμή του. Κάπως έτσι: 1 # include <iostream > 2 using namespace std; 3 4 class point2d { 5 private: 6 int x, y; 7 8 public: 9 void setx(int value) { x = value % 400; if (x < 0) x += 400; } 10 void sety(int value) { y = value % 400; if (y < 0) y += 400; } 11 12 int getx() { return x; } 13 int gety() { return y; } 14 15 void print() { cout << "x: " << x << ", y: " << y << endl; } 16 }; 17 18 int main() 19 { 20 point2d a; 21 a.setx (12345); 22 a.sety(-2100); 23 24 a.print(); 25 } 4.5 Κατασκευαστές και καταστροφείς Μία συνηθισμένη πηγή λαθών σε προγράμματα είναι οι μη αρχικοποιημένες μεταβλητές, δηλαδή μεταβλητές που δηλώνονται μεν αλλά δεν αρχικοποιούνται σωστά. Για παράδειγμα, αν θέλαμε να αθροίσουμε τις τιμές ενός πίνακα p θα έπρεπε να χρησιμοποιήσουμε μια μεταβλητή, ας πούμε sum στην οποία να προσθέσουμε διαδοχικά τα στοιχεία του πίνακα. Αν λοιπόν το πλήθος των στοιχείων του πίνακα είναι n, το παρακάτω πρόγραμμα κάνει ακριβώς αυτήν τη δουλειά: 1 int sum; 2 sum = 0; 3 for (i = 0; i < n; ++i) 4 sum += p[n]; Το αποτέλεσμα θα είναι σωστό. Αν όμως ξεχάσει κανείς την αρχικοποίηση της μεταβλητής sum=0;, το πρόγραμμα θα είναι συντακτικά σωστό (οπότε ο μεταγλωττιστής δεν θα δώσει κάποιο μήνυμα 9

λάθους) και ενώ η ουσία του υπολογισμού (δηλαδή ο βρόχος επανάληψης) είναι σωστά γραμμένη, το αποτέλεσμα θα είναι εντελώς λάθος. Στην C++ δίνεται η δυνατότητα ορισμού ειδικών μεθόδων, οι οποίες λέγονται constructors (κατασκευαστές) που καλούνται τη στιγμή που δημιουργείται ένα αντικείμενο και το αρχικοποιούν έτσι ώστε οι αρχικές τιμές των μελών δεδομένων του αντικειμένου να είναι σωστές. Ακριβώς επειδή ο σκοπός των constructors είναι να αρχικοποιούν ένα αντικείμενο σωστά ακόμα και όταν ο προγραμματιστής ξεχάσει να το αρχικοποιήσει, δεν μπορούμε να τους καλέσουμε εμείς από το πρόγραμμά μας αλλά καλούνται αυτόματα από τους μηχανισμούς της γλώσσας τη στιγμή που δημιουργείται ένα αντικείμενο. Για να μπορεί η γλώσσα να αναγνωρίσει ανάμεσα σε όλες τις μεθόδους που έχουμε δηλώσει, ποιος⁴ είναι ο constructor, ορίζεται ότι constructors είναι οι μέθοδοι που έχουν το ίδιο όνομα με την κλάση. Δείτε ένα παράδειγμα: 1 # include <iostream > 2 using namespace std; 3 4 class foo { 5 int a, b; 6 7 public: 8 void print() { cout << "a, b: " << a << " " << b << endl; } 9 }; 10 11 int main() 12 { 13 foo x; 14 x.print(); 15 16 return 0; 17 } Σε αυτό δηλώνεται μία κλάση foo με δύο μέλη, τα a και b. Στη συνέχεια δημιουργείται ένα αντικείμενο αυτής της κλάσης και για αυτό καλείται η μέθοδος print που τυπώνει τις τιμές των μελών. Στο δικό μου υπολογιστή ένα τρέξιμο έδωσε την παρακάτω έξοδο: a, b: 653999360 32767 Οι τιμές αυτές προφανώς δεν έχουν νόημα και είναι απλώς οι τιμές που έτυχε να έχουν οι θέσεις μνήμης που αντιστοιχίστηκαν στα μέλη a και b. Αν τώρα προσθέσουμε μετά τη γραμμή 7 έναν constructor γράφοντας το παρακάτω: 1 foo() { a = 0; b = 0; } τότε η έξοδος του προγράμματός μας, χωρίς να κάνουμε καμία άλλη μετατροπή, θα είναι a, b: 0 0 ⁴ή ποιοι, θα δούμε ότι μπορούμε να έχουμε περισσότερους από έναν constructors 10

Χωρίς δηλαδή να κάνουμε κάποια αλλαγή στο κομμάτι από τη γραμμή 13 και κάτω όπου δηλώνουμε το αντικείμενο, η γλώσσα είδε ότι ορίσαμε έναν constructor και τον κάλεσε αυτόματα. Στο συγκεκριμένο παράδειγμα, ορίσαμε έναν constructor ο οποίος δεν έπαιρνε παραμέτρους. Αυτός αρχικοποίησε τα μέλη τις κλάσης με την τιμή μηδέν, κάτι ελαφρά καλύτερο από τα σκουπίδια της προηγούμενης εκδοχής αλλά σίγουρα όχι αρκετό καθώς υπάρχουν περιπτώσεις που δεν μπορούμε εκ των προτέρων να ξέρουμε τι τιμές να βάλουμε στα μέλη της κλάσης. Αυτό δεν είναι πρόβλημα καθώς μπορούμε να δηλώσουμε constructors με παραμέτρους και μάλιστα οσουσδήποτε θέλουμε αρκεί αυτοί να διαφέρουν μεταξύ τους ως προς τις παραμέτρους που δέχονται. Για παράδειγμα, μπορούμε να δηλώσουμε αμέσως μετά τον προηγούμενο constructor έναν νέο που να δέχεται δύο παραμέτρους κάπως έτσι: 1 foo(int _a, int _b) { a = _a; b = _b; } ή και ακόμα έναν που να δέχεται μία παράμετρο κάπως έτσι: 1 foo(int value} { a = b = value; } Έχοντας δηλώσει αυτούς τους constructors μπορούμε να επιλέξουμε ποιος θα χρησιμοποιηθεί για την αρχικοποίηση ενός νέου αντικειμένου, γράφοντας μια λίστα ορισμάτων αμέσως μετά το όνομά του στη γραμμή που το δηλώνουμε. Αν π.χ. δηλώσουμε ένα νέο αντικείμενο έτσι: foo y(5); τότε θα χρησιμοποιηθεί ο constructor που παίρνει μία παράμετρο γιατί τόσα είναι τα ορίσματα που δίνουμε μέσα σε παρενθέσεις μετά από το όνομα του νέου αντικειμένου y. Αν δηλώσουμε ένα αντικείμενο έτσι:foo z(1,2); τότε θα κληθεί να το αρχικοποιήσει ο constructor που παίρνει δύο παραμέτρους. Το τελικό πρόγραμμα είναι το παρακάτω: 1 # include <iostream > 2 using namespace std; 3 4 class foo { 5 int a, b; 6 7 public: 8 foo() { a = 0; b = 0; } 9 foo(int _a, int _b) { a = _a; b = _b; } 10 foo(int value) { a = b = value; } 11 void print() { cout << "a, b: " << a << " " << b << endl; } 12 }; 13 14 int main() 15 { 16 foo x; // kaleitai o foo() 17 foo y(5); // kaleitai o foo(int value) 18 foo z(1,2); // kaleitai o foo(int _a, int _b) 19 20 x.print(); 21 y.print(); 22 z.print(); 23 24 return 0; 11

25 } Μία τελευταία παρατήρηση για τους constructors: Αν γράψατε και τρέξατε την προηγούμενη εκδοχή του προγράμματος, εκείνην δηλαδή που η κλάση δεν είχε κανέναν constructor και αρχικοποιούσε με τυχαίες τιμές τα μέλη της κλάσης, θα έχετε πειστεί ότι η C++ επιτρέπει να μην δηλώνονται constructors σε μία κλάση. Δηλαδή δίνει στον προγραμματιστή την ελευθερία να μην χρησιμοποιήσει τους (καλούς) μηχανισμούς που του παρέχει η γλώσσα. Σε αυτήν την περίπτωση η C++ απλώς αφήνει τα μέλη της κλάσης να έχουν τυχαίες τιμές. Θυμηθείτε λοιπόν ότι στην περίπτωση που δεν υπήρχε constructor, η δήλωση foo x; επιτρεπόταν. Αν τώρα, στην τελική εκδοχή του προγράμματος βάλετε τους χαρακτήρες // ακριβώς πριν από τον ορισμό της γραμμής 8, τότε ο μεταγλωττιστής θα σας δώσει μήνυμα λάθους διαμαρτυρόμενος ότι η δήλωση της γραμμής 8 δεν επιτρέπεται γιατί δεν υπάρχει αντίστοιχος constructor. Ο κανόνας λοιπόν είναι ότι η γλώσσα επιτρέπει να δηλώσετε ένα αντικείμενο χωρίς να το αρχικοποιήσετε ρητά δίνοντας κάποιες παραμέτρους (όπως στη γραμμή 8) αν και μόνο αν δεν έχει δηλωθεί κανένας απολύτως constructor για την κλάση στην οποία υπάγεται το αντικείμενο. Αν έχουν δηλωθεί ένας ή παραπάνω constructors τότε κάθε δήλωση αντικειμένου πρέπει υποχρεωτικά να αντιστοιχεί σε κάποιον constructor. Οι constructors δίνουν μία λύση στο πρόβλημα των ενεργειών που πρέπει να πραγματοποιούνται κατά τη δημιουργία ενός αντικειμένου. Ένα αντίστοιχο πρόβλημα είναι εκείνο των ενεργειών που πρέπει να πραγματοποιούνται κατά το τέλος της ζωής ενός αντικειμένου. Για παράδειγμα, σκεφτείτε ένα πρόγραμμα που κάνει προσομοίωση της λειτουργίας ενός τηλεφωνικού κέντρου. Υπάρχει ένα αντικείμενο το οποίο αναπαριστά το τηλεφωνικό κέντρο το οποίο υποτίθεται ότι μπορεί να εξυπηρετεί μέχρι έναν συγκεκριμένο αριθμό ταυτόχρονων κλήσεων. Επίσης υπάρχουν αντικείμενα που αναπριστούν τις κλήσεις. Κάθε φορά που δημιουργείται ένα νέο αντικείμενο τηλεφωνικής κλήσης, αυτό δεσμεύει μία από τις ελεύθερες γραμμές του τηλεφωνικού κέντρου, αυξάνοντας έναν μετρητή. Όταν τερματίζεται μία κλήση, το αντίστοιχο αντικείμενο καταστρέφεται. Σε αυτό το σημείο θα έπρεπε να μειωθεί κατά μία μονάδα ο μετρητής των γραμμών εν χρήση του τηλεφωνικού κέντρου. Αυτό θα μπορούσε να το κάνει ο προγραμματιστής που χρησιμοποιεί τα παραπάνω αντικείμενα, αλλά θα ήταν σαφώς καλύτερα αν τα αντικείμενα-τηλεφωνικές-κλήσεις, μείωναν αυτόματα τον μετρητή κάθε φορά που τελείωνε ο κύκλος ζωής τους. Για να προγραμματίσουμε τέτοιες ενέργειες, που πραγματοποιούνται στο τέλος της ζωής ενός αντικειμένου, γράφουμε destructors (καταστροφείς). Ένας destructor δηλώνεται περίπου όπως και οι constructors με μόνη διαφορά ότι το όνομα του destructor έχει μπροστά τον χαρακτήρα ~ (περισπωμένη). Επίσης, κάθε κλάση μπορεί να έχει έναν και μόνο έναν destructor, ο οποίος όμως δεν είναι υποχρεωτικό να υπάρχει. Δηλαδή μία κλάση μπορεί να έχει είτε κανέναν είτε ακριβώς έναν destructor. Ένα τελευταίο θέμα σχετικά με τους constructors και τους destructors είναι το πότε ακριβώς καλούνται. Ο constructor καλείται τη στιγμή που δημιουργείται το αντικείμενο αμέσως μετά τη δέσμευση μνήμης για τα μέλη δεδομένων του. Αυτό γίνεται στο σημείο του προγράμματος που δηλώθηκε το αντικείμενο. Ο destructor καλείται όταν κλείσει το μπλοκ στο οποίο δηλώθηκε το αντικείμενο. Αν τρέξετε το παρακάτω παράδειγμα θα δείτε τα σημεία που καλούνται οι constructors και οι destructors των αντικειμένων του προγράμματος. 1 # include <iostream > 2 using namespace std; 3 4 class foo { 12

5 int a; 6 public: 7 foo(int _a) { a = _a; cout << " Constructor called for object " << a << endl; } 8 ~foo() { cout << " Destructor called for object " << a << endl; } 9 }; 10 11 int main() 12 { 13 cout << "Prin ton constructor tou object x(1)" << endl; 14 foo x(1); 15 16 cout << "Prin ton constructor tou object y(2)" << endl; 17 foo y(2); 18 19 cout << "Prin ton constructor tou object z(3)" << endl; 20 foo z(3); 21 22 cout << " To programma teleiwvei stnv epomevn grammn" << endl; 23 } Η έξοδος του οποίου είναι Prin ton constructor tou object x(1) Constructor called for object 1 Prin ton constructor tou object y(2) Constructor called for object 2 Prin ton constructor tou object z(3) Constructor called for object 3 To programma teleiwvei stnv epomevn grammn Destructor called for object 3 Destructor called for object 2 Destructor called for object 1 5 Παραδείγματα και ασκήσεις Στον γνωστό ιστοτόπου του μαθήματος, δείτε στον φάκελο examples τα stack (υλοποίηση στοίβας), cplex (υλοποίηση μιγαδικού αριθμού). Μπορείτε προφανώς να τα κατεβάσετε όπως είναι και να τα χρησιμοποιήσετε. Εκτός από αυτό, δοκιμάστε να τα φτιάξετε μόνοι σας από το μηδέν. Ξεκινήστε κάπως έτσι, κάνοντας compile μετά από κάθε βήμα: Γράψτε μια κενή δήλωση κλάσης πριν από την main του προγράμματος η οποία θα περιέχει απλώς το όνομα της κλάσης και τα άγκιστρα. Δηλώστε ένα αντικείμενο αυτής της κλάσης μέσα στη συνάρτηση main. Προσθέστε μέλη δεδομένων στη δήλωση της κλάσης σας. Αρχικά μπορείτε να τα δηλώσετε public για μεγαλύτερη ευκολία. 13

Προσπαθήστε μέσα από τη main να αλλάξετε τις τιμές τους. Προσθέστε μια μέθοδο print και καλέστε την. Προσθέστε έναν ή περισσότερους constructors και χρησιμοποιήστε τους για να φτιάξετε καινούρια αντικείμενα. Τυπώστε τα με την μέθοδο print. Προσθέστε κάποια από τις μεθόδους που υπάρχουν στα ολοκληρωένα παραδείγματα. Καλέστε τις για να επιβεβαιώσετε την σωστή λειτουργία τους. Επίσης: Προσθέστε μια μέθοδο empty() που να αδειάζει τη στοίβα. Προσθέστε μια μέθοδο reverse() στη στοίβα που να αδειάζει τα στοιχεία της. Αν τρέξετε το πρόγραμμα της στοίβας θα δείτε ότι σε κάποια σημεία κάνει λάθη. Μπορείτε να καταλάβετε γιατί και να βρείτε έναν τρόπο να τα διορθώσετε; Φτιάξτε μια μέθοδο multiply στην κλάση cplex η οποία να πολλαπλασιάζει το αντικείμενο για το οποίο καλείται με έναν άλλο μιγαδικό αριθμό που θα δίνεται ως παράμετρος. Θυμηθείτε ότι στον πολλαπλασιασμό μιγαδικών αριθμών ισχύει ότι για δύο μιγαδικούς x 1 και x 2 με πραγματικά μέρη r 1 και r 2 αντίστοιχα και φανταστικά i 1 και i 2 ισχύει x 1 x 2 = (r 1 +i 1 j) (r 2 +i 2 j) = r 1 r 2 +i 1 i 2 j j +r 1 i 2 j +i 1 r 2 j = (r 1 r 2 i 1 i 2 )+(r 1 i 2 +i 1 r 2 ) j δηλαδή το αποτέλεσμα έχει πραγματικό μέρος r 1 r 2 i 1 i 2 και φανταστικό μέρος r 1 i 2 +i 1 r 2. 14