ΤΕΙ ΔΥΤΙΚΗΣ ΜΑΚΕΔΟΝΙΑΣ Program-Ergast...Ασκήσεις εργαστηρίου...

44
ΤΕΙ ΔΥΤΙΚΗΣ ΜΑΚΕΔΟΝΙΑΣ ΤΜΗΜΑ ΔΙΟΙΚΗΣΗΣ ΕΠΙΧΕΙΡΗΣΕΩΝ (ΓΡΕΒΕΝΑ) Ασκήσεις εργαστηρίου Εργαστήριο: Αντικειμενοστρεφής Προγραμματισμός Δρ. Δημήτριος Συνδουκάς Επίκ. Καθηγητής ΓΡΕΒΕΝΑ 2012-2015 C++

Transcript of ΤΕΙ ΔΥΤΙΚΗΣ ΜΑΚΕΔΟΝΙΑΣ Program-Ergast...Ασκήσεις εργαστηρίου...

Page 1: ΤΕΙ ΔΥΤΙΚΗΣ ΜΑΚΕΔΟΝΙΑΣ Program-Ergast...Ασκήσεις εργαστηρίου ... του και τέλος θα εμφανίζει τον αριθμό και

ΤΕΙ ΔΥΤΙΚΗΣ ΜΑΚΕΔΟΝΙΑΣ

ΤΜΗΜΑ ΔΙΟΙΚΗΣΗΣ ΕΠΙΧΕΙΡΗΣΕΩΝ

(ΓΡΕΒΕΝΑ)

Ασκήσεις εργαστηρίου

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

Δρ. Δημήτριος Συνδουκάς

Επίκ. Καθηγητής

ΓΡΕΒΕΝΑ 2012-2015

C++

Page 2: ΤΕΙ ΔΥΤΙΚΗΣ ΜΑΚΕΔΟΝΙΑΣ Program-Ergast...Ασκήσεις εργαστηρίου ... του και τέλος θα εμφανίζει τον αριθμό και

Τ.Ε.Ι. Δυτικής Μακεδονίας Τμήμα Διοίκ. Επιχειρήσεων (Γρεβενά)

Αντικειμενοστρεφής προγραμματισμός με C++ Δρ. Δημ. Συνδουκάς

Σελίδα 2

Άσκηση 1. Υπερφόρτωση συναρτήσεων – function overloading.

α) Συναρτήσεις με ίδιο αριθμό παραμέτρων, που όμως έχουν διαφορετικό τύπο.

Σκοπός της άσκησης είναι να δείξει πως, μέσω της υπερφόρτωσης, μπορούμε να έχουμε δύο ή

περισσότερες συναρτήσεις με το ίδιο όνομα και κάθε φορά που κάνουμε μια κλήση να καλείται η

σωστή συνάρτηση!

Θα δημιουργήσετε μια συνάρτηση που να ονομάζεται square και να υπολογίζει το τετράγωνο ενός

αριθμού. Το τετράγωνο να υπολογίζεται με απλό πολλαπλασιασμό.

Συγκεκριμένα, να υπερφορτώσετε την συνάρτηση ώστε να είναι σε θέση να υπολογίζει το

τετράγωνο:

ενός ακέραιου αλλά και

ενός κινητής υποδιαστολής διπλής ακρίβειας αριθμού.

Το επιστρεφόμενο αποτέλεσμα θα είναι φυσικά ανάλογου τύπου με την είσοδο (παράμετρο).

Στη συνέχεια να γράψετε ένα πρόγραμμα το οποίο θα ζητά έναν ακέραιο αριθμό από τον χρήστη, θα

τον διαβάζει από το πληκτρολόγιο, θα καλεί την συνάρτηση square για να υπολογίσει το τετράγωνό

του και τέλος θα εμφανίζει τον αριθμό και το τετράγωνό του στην οθόνη με ανάλογα μηνύματα.

Θα κάνει το ίδιο για έναν κινητής υποδιαστολής διπλής ακρίβειας αριθμό.

#include <iostream>

using namespace std;

int square(int x);

double square(double x);

void main() {

int ar1, tetr1;

double ar2, tetr2;

cout <<"DOSE ENA AKERAIO ARITHMO: ";

cin >> ar1;

tetr1 = square(ar1);

cout << "TO TETRAGONO TOY ARITHMOY: " << ar1 << " EINAI: "

<< tetr1 << endl;

cout << "DOSE ENA PRAGMATIKO ARITHMO: ";

cin >> ar2;

tetr2 = square(ar2);

cout << "TO TETRAGONO TOY ARITHMOY: " << ar2 << " EINAI: "

<< tetr2 << endl;

}

int square (int x) {

return (x*x);

}

double square (double x) {

return (x*x);

}

Σχόλια:

Παρατηρήστε ότι καλώ την ίδια συνάρτηση δύο φορές στο πρόγραμμά μου αλλά με διαφορετικού

τύπου όρισμα (είσοδο). Οι κλήσεις υποδεικνύονται με τα βέλη (1) και (2). Ο compiler της C++

επιλέγει ποια από τις δύο συναρτήσεις square είναι η σωστή και καλεί αυτή, με βάση τον τύπο της

«εισόδου» που χρησιμοποίησα στην κλήση της.

Με δυο λόγια, οι δύο συναρτήσεις παρόλο που έχουν ίδιο όνομα αλλά και ίδιο αριθμό παραμέτρων

(εισόδων), ξεχωρίζουν από τον τύπο των παραμέτρων.

Τα πρωτότυπα των 2 συναρτήσεων.

Οι 2 συναρτήσεις με όνομα square.

Page 3: ΤΕΙ ΔΥΤΙΚΗΣ ΜΑΚΕΔΟΝΙΑΣ Program-Ergast...Ασκήσεις εργαστηρίου ... του και τέλος θα εμφανίζει τον αριθμό και

Τ.Ε.Ι. Δυτικής Μακεδονίας Τμήμα Διοίκ. Επιχειρήσεων (Γρεβενά)

Αντικειμενοστρεφής προγραμματισμός με C++ Δρ. Δημ. Συνδουκάς

Σελίδα 3

Άσκηση 2. Υπερφόρτωση συναρτήσεων – function overloading.

β) Συναρτήσεις με διαφορετικό αριθμό παραμέτρων (ο τύπος τους δεν έχει σημασία)

Σκοπός της άσκησης είναι να δείξει πως, μέσω της υπερφόρτωσης, μπορούμε να έχουμε δύο ή

περισσότερες συναρτήσεις με το ίδιο όνομα και κάθε φορά που κάνουμε μια κλήση να καλείται η

σωστή συνάρτηση!

Θα δημιουργήσετε μια συνάρτηση που να ονομάζεται per_par και να υπολογίζει την περίμετρο ενός

παραλληλογράμμου.

Συγκεκριμένα, να υπερφορτώσετε την συνάρτηση ώστε:

να έχει σαν «είσοδό της» δύο ακέραιους αριθμούς (τα μήκη των 2 πλευρών),

να έχει σαν «είσοδό της» μόνο έναν ακέραιο αριθμό (τότε υποθέτουμε ότι οι δύο πλευρές

έχουν ίσα μήκη, άρα είναι τετράγωνο).

Το επιστρεφόμενο αποτέλεσμα φυσικά θα είναι ακέραιος.

Στη συνέχεια να γράψετε ένα πρόγραμμα το οποίο να ζητά από τον χρήστη τα (ακέραια) μήκη των 2

πλευρών ενός παραλληλόγραμμου, θα τα διαβάζει, και θα καλεί την συνάρτηση per_par δύο φορές:

μία «δίνοντας» σαν είσοδό της τα δύο μήκη

μία «δίνοντας» σαν είσοδό της μόνο το πρώτο μήκος

Στο τέλος να εμφανιστούν οι δύο περίμετροι με ανάλογα μηνύματα, σε χωριστές γραμμές.

#include <iostream>

using namespace std;

int per_par (int x, int y);

int per_par (int x);

void main() {

int pleyra1, pleyra2, perim1, perim2;

cout << "DOSE TO MHKOS THS 1hs PLEYRAS TOY PARAL/MOY: ";

cin >> pleyra1;

cout << "DOSE TO MHKOS THS 2hs PLEYRAS TOY PARAL/MOY: ";

cin >> pleyra2;

perim1 = per_par(pleyra1, pleyra2);

cout << "H PERIMETROS EINAI: " << perim1 << endl;

perim2 = per_par(pleyra1);

cout << "H PERIMETROS EINAI: " << perim2 << endl;

}

int per_par (int x, int y) {

return (2*x + 2*y);

}

int per_par (int x) {

return (4*x);

}

Σχόλια:

Παρατηρήστε ότι και εδώ έχω δύο συναρτήσεις με το ίδιο όνομα! Ωστόσο η μία έχει 2 «εισόδους»

(παραμέτρους) ενώ η άλλη μία μόνο. Ο compiler της C++ καταλαβαίνει πότε καλώ την καθεμιά από

τον αριθμό των ορισμάτων (των εισόδων) που γράφω μέσα στις παρενθέσεις της κλήσης, που

σημειώνονται με (1) και (2).

Με δυο λόγια, οι δύο συναρτήσεις παρόλο που έχουν ίδιο όνομα αλλά και ίδιο τύπο παραμέτρων

(εισόδων), ξεχωρίζουν από το πλήθος των παραμέτρων.

Τα πρωτότυπα των 2 συναρτήσεων.

Οι 2 συναρτήσεις με όνομα per_par.

Page 4: ΤΕΙ ΔΥΤΙΚΗΣ ΜΑΚΕΔΟΝΙΑΣ Program-Ergast...Ασκήσεις εργαστηρίου ... του και τέλος θα εμφανίζει τον αριθμό και

Τ.Ε.Ι. Δυτικής Μακεδονίας Τμήμα Διοίκ. Επιχειρήσεων (Γρεβενά)

Αντικειμενοστρεφής προγραμματισμός με C++ Δρ. Δημ. Συνδουκάς

Σελίδα 4

Άσκηση 3. Συναρτήσεις με προκαθορισμένες τιμές παραμέτρων – default parameter values.

Σκοπός της άσκησης είναι να δείξει πως μπορούμε να καλούμε μια συνάρτηση παραλείποντας τις

τιμές για κάποιες από τις παραμέτρους της. Τότε χρησιμοποιούνται οι προκαθορισμένες τιμές.

Να δημιουργήσετε μια συνάρτηση που να ονομάζεται riza και να υπολογίζει την ρίζα n-βαθμού ενός

κινητής υποδιαστολής διπλής ακρίβειας αριθμού. Η συνάρτηση θα υπολογίζει την ν-οστή ρίζα ενός

αριθμού x χρησιμοποιώντας τον γεγονός ότι η nx ισούται με x1/n. Όπως γνωρίζετε, η δύναμη αριθμού

μπορεί εύκολα να υπολογιστεί με την συνάρτηση pow.

Συγκεκριμένα η συνάρτηση riza να έχει σαν προκαθορισμένη τιμή για τον βαθμό της ρίζας το 2,

έτσι ώστε αν κληθεί χωρίς να καθοριστεί ο βαθμός της ρίζας, να θεωρηθεί ότι ζητείται η τετραγωνική

ρίζα.

Στη συνέχεια, να γράψετε ένα πρόγραμμα που να ζητά από τον χρήστη έναν κινητής υποδιαστολής

διπλής ακρίβειας αριθμό και τον βαθμό της ρίζας που θέλει να υπολογίσει, να τα διαβάσει και να καλεί

την συνάρτηση riza 2 φορές:

μία κανονικά και με τις δύο τιμές (αριθμό και βαθμό ρίζας) και

μία μόνο με τον αριθμό, χωρίς να γράψετε τον βαθμό της ρίζας μέσα στις παρενθέσεις της

κλήσης

Στο τέλος να εμφανιστούν στην οθόνη τα αποτελέσματα με ανάλογα μηνύματα.

#include <iostream>

#include <cmath>

using namespace std;

double riza (double x, double y=2);

void main() {

double arithmos, bathmos, apot1, apot2;

cout << "DOSE TON ARITHMO: ";

cin >> arithmos;

cout << "DOSE TON BATHMO RIZAS: ";

cin >> bathmos;

apot1 = riza(arithmos, bathmos);

cout << "H RIZA BATHMOY: " << bathmos << " EINAI: "

<< apot1 << endl;

apot2 = riza(arithmos);

cout << "H TETRAGONIKH RIZA EINAI: " << apot2 << endl;

}

double riza (double x, double y) {

return ( pow(x, 1.0/y) );

}

Σχόλια:

Παρατηρήστε ότι καλώ την συνάρτηση δύο φορές:

την πρώτη, που σημειώνεται με το βέλος (1), παρέχοντάς της κανονικά δύο τιμές για τις

παραμέτρους της (εισόδους), όπως το απαιτεί

την δεύτερη, που σημειώνεται με το βέλος (2), παρέχοντάς της μία μόνο είσοδο! Ωστόσο αυτό

γίνεται αποδεκτό από τον compiler της C++, γιατί όταν δεν παρέχουμε τιμή για την δεύτερη

παράμετρο της συνάρτησης αυτή παίρνει αυτομάτως της τιμή 2. Αυτό φαίνεται στην δήλωση της

πρωτότυπου της συνάρτησης – κοιτάξτε το βέλος (3).

Ακόμη, οι προκαθορισμένες τιμές πρέπει πάντα να δίνονται αρχίζοντας από την πιο δεξιά παράμετρο

της συνάρτησης και να συνεχίζουν, χωρίς ενδιάμεσες παραλείψεις, προς τα αριστερά.

(3)

(1)

(2)

Το πρωτότυπο της συνάρτησης.

Η συνάρτηση με όνομα riza.

!

Page 5: ΤΕΙ ΔΥΤΙΚΗΣ ΜΑΚΕΔΟΝΙΑΣ Program-Ergast...Ασκήσεις εργαστηρίου ... του και τέλος θα εμφανίζει τον αριθμό και

Τ.Ε.Ι. Δυτικής Μακεδονίας Τμήμα Διοίκ. Επιχειρήσεων (Γρεβενά)

Αντικειμενοστρεφής προγραμματισμός με C++ Δρ. Δημ. Συνδουκάς

Σελίδα 5

Άσκηση 4. Αναφορές (references) – Χρήση τους στην κλήση συναρτήσεων.

Σκοπός της άσκησης είναι να δείξει τι είναι οι αναφορές και πως χρησιμοποιούνται στις παραμέτρους

μιας συνάρτησης.

Να δημιουργήσετε μια συνάρτηση που να ονομάζεται swap η οποία να δέχεται σαν «είσοδό της» δύο

ακέραιους αριθμούς και δεν θα επιστρέφει τίποτα. Ωστόσο, μετά την κλήση της συνάρτησης, οι δύο

αριθμοί να έχουν ανταλλαγεί μεταξύ τους (δηλαδή ο πρώτος να είναι στη θέση του δεύτερου και ο

δεύτερος στη θέση του πρώτου). Να το κάνετε με χρήση αναφορών.

Στη συνέχεια, να γράψετε ένα πρόγραμμα που να ζητά από τον χρήστη δύο ακέραιους αριθμούς, να

τους διαβάζει και να τους εμφανίζει στην οθόνη λέγοντας ότι ο πρώτος αριθμός είναι ο τάδε και ο

δεύτερος ο τάδε.

Έπειτα να καλεί την συνάρτησηswap στην οποία θα «δίνει» σαν είσοδο τους δύο αριθμούς.

Και έπειτα θα εμφανίζει και με τον ίδιο τρόπο τους δύο αριθμούς στην οθόνη.

Αφού τρέξτε το πρόγραμμα, παρατηρήστε από τα μηνύματα που εμφανίζονται στην οθόνη αν οι δύο

αριθμοί αντάλλαξαν θέσεις μετά την κλήση της συνάρτησης.

#include <iostream>

using namespace std;

void swap (int &x, int &y);

void main() {

int ar1, ar2;

cout <<"DOSE 2 AKERAIOYS: ";

cin >> ar1 >> ar2;

cout <<"O 1os ARITHMOS EINAI: "<< ar1 <<" KAI O 2os: "

<< ar2 << endl;

swap(ar1, ar2);

cout <<"O 1os ARITHMOS EINAI: "<< ar1 <<" KAI O 2os: "

<< ar2 << endl;

}

void swap (int &x, int &y) {

int temp;

temp = x;

x = y;

y = temp;

}

Σχόλια:

Μια συνάρτηση επιστρέφει το πολύ μια τιμή μέσα από την εντολή return. (Μόνο όταν μια

συνάρτηση είναι τύπου void δεν επιστρέφει τίποτα μέσω μιας return). Όταν όμως θέλουμε η

συνάρτηση να μας δίνει 2 ή περισσότερα αποτελέσματα, αναγκαστικά θα καταφύγουμε στη

χρήση αναφορών.

Όταν μια παράμετρος συνάρτησης δηλώνεται σαν αναφορά (με το σύμβολο & μπροστά από το

όνομά της) τότε δεν αποτελεί μόνο «είσοδο» για τη συνάρτηση αυτή, αλλά είναι ταυτόχρονα και

«έξοδός της».

Αν δεν χρησιμοποιούσαμε αναφορές, τότε όταν καλείται η συνάρτηση swap, οι τιμές των

μεταβλητών ar1 και ar2 αντιγράφονται στις μεταβλητές x και y, αντίστοιχα. Οπότε, όταν η

συνάρτηση ολοκληρώσει τους υπολογισμούς της και αν οι τιμές των x και y άλλαξαν, αυτό δεν

επηρεάζει τις τιμές των ar1 και ar2, οι οποίες διατηρούν τις αρχικές τιμές τους.

Αν χρησιμοποιήσουμε αναφορές, τότε οι μεταβλητή ar1 και η x είναι το ίδιο (όχι αντίγραφο η

μια της άλλης, αλλά ακριβώς το ίδιο). Η μεταβλητή ar2 και η y είναι επίσης το ίδιο. Αυτό

γίνεται γιατί αντιγράφεται η διεύθυνση και όχι η τιμή της κάθε μεταβλητής. Έτσι, όταν αλλάξει η

τιμή της x έχει αλλάξει ταυτόχρονα και της ar1, αφού είναι το ίδιο πράγμα. Το ίδιο

συμβαίνει και με τις μεταβλητές y και ar2.

κλήση

Το πρωτότυπο της

συνάρτησης – προσέξτε: οι

«είσοδοί της» είναι αναφορές!

Η συνάρτηση με όνομα swap.

Παρατηρείστε ότι οι «είσοδοί της»

(οι παράμετροι) είναι αναφορές!

Page 6: ΤΕΙ ΔΥΤΙΚΗΣ ΜΑΚΕΔΟΝΙΑΣ Program-Ergast...Ασκήσεις εργαστηρίου ... του και τέλος θα εμφανίζει τον αριθμό και

Τ.Ε.Ι. Δυτικής Μακεδονίας Τμήμα Διοίκ. Επιχειρήσεων (Γρεβενά)

Αντικειμενοστρεφής προγραμματισμός με C++ Δρ. Δημ. Συνδουκάς

Σελίδα 6

Άσκηση 5. Κλάσεις: Μεταβλητές-μέλη (member variables) και

Συναρτήσεις-μέλη (member functions) ή μέθοδοι (methods).

Σκοπός της άσκησης είναι να δείξει πως δημιουργούμε μια κλάση με μεταβλητές και συναρτήσεις-

μέλη και πως δημιουργούμε αντικείμενα μιας κλάσης. Ακόμη, παρουσιάζονται οι λέξεις-κλειδιά

«δημόσιος» ή public και «ιδιωτικός» ή private.

Αρχικά:

να δημιουργήσετε μια κλάση, η οποία να αντιπροσωπεύει γενικώς έναν κύκλο. Συγκεκριμένα:

να περιέχει μεταβλητές-μέλη (member-variables) ή ιδιότητες (attributes) που να τον περιγράφουν

(η τιμή της ακτίνας αρκεί στην περίπτωσή μας – είναι κινητής υποδιαστολής διπλής ακρίβειας),

να περιέχει 2 συναρτήσεις-μέλη (member-functions) ή μεθόδους (methods) που να ενεργούν

πάνω στις μεταβλητές του:

μια που δέχεται σαν «είσοδό της» μια τιμή, η οποία να καθορίζει την ακτίνα. Αυτή να

ονομαστεί set_aktina.

μια που να υπολογίζει και να επιστρέφει το εμβαδόν του κύκλου (κινητής υποδιαστολής

διπλής ακρίβειας). Αυτή να ονομαστεί give_embadon.

Οι μεταβλητές να είναι private ενώ οι συναρτήσεις public.

Στη συνέχεια, να γράψετε ένα πρόγραμμα, στο οποίο:

Να δηλώσετε ένα αντικείμενο της παραπάνω κλάσης, το οποίο να αντιπροσωπεύει έναν

συγκεκριμένο κύκλο, π.χ. τον κύκλο 1.

Το πρόγραμμά σας να ζητά από τον χρήστη την τιμή της ακτίνας, την οποία θα διαβάζει από το

πληκτρολόγιο και θα αποθηκεύει σε κάποια (απλή) μεταβλητή.

Κατόπιν, χρησιμοποιώντας τη μία από τις συναρτήσεις-μέλη, να δίνει την παραπάνω τιμή της

ακτίνας στο αντικείμενο κύκλος 1.

έπειτα, να υπολογίζει το εμβαδόν του κύκλου 1, χρησιμοποιώντας τη δεύτερη συνάρτηση-μέλος

και τέλος, θα εμφανίζει το εμβαδόν αυτό με ανάλογο μήνυμα.

#include <iostream>

using namespace std;

class kyklos {

private:

double aktina;

public:

void set_aktina(double a);

double give_embadon();

};

void kyklos::set_aktina(double a) {

aktina = a;

}

double kyklos::give_embadon() {

return 3.14*aktina*aktina;

}

void main() {

kyklos kyklos1; // Δήλωση αντικειμένου,

// της κλάσης kyklos

double r;

double embadon;

cout << "DOSE TIMH AKTINAS: ";

cin >> r;

kyklos1.set_aktina(r); // Κλήσησυνάρτησης-μέλους

embadon = kyklos1.give_embadon(); // Κλήσησυνάρτησης-μέλους

cout << "TO EMBADON TOY KYKLOY EINAI: " << embadon << endl;

}

(1)

(2)

(3)

(4)

(5)

Page 7: ΤΕΙ ΔΥΤΙΚΗΣ ΜΑΚΕΔΟΝΙΑΣ Program-Ergast...Ασκήσεις εργαστηρίου ... του και τέλος θα εμφανίζει τον αριθμό και

Τ.Ε.Ι. Δυτικής Μακεδονίας Τμήμα Διοίκ. Επιχειρήσεων (Γρεβενά)

Αντικειμενοστρεφής προγραμματισμός με C++ Δρ. Δημ. Συνδουκάς

Σελίδα 7

Σχόλια:

Όπως και στην περίπτωση του ορισμού δομής (structuredefinition), έτσι και οι κλάσεις αποτελούν

ένα είδος «περιτυλίγματος» ή καλουπιού. Μόνο που οι κλάσεις περικλείουν και μεταβλητές αλλά

και συναρτήσεις!

Οι συναρτήσεις μιας κλάσης έχουν σαν σκοπό:

o να μεταβάλλουν τις τιμές των μεταβλητών της κλάσης ή

o να μας πουν πόση είναι η τιμή μιας από αυτές τις μεταβλητές

o να κάνουν πράξεις με αυτές τις μεταβλητές.

Δηλαδή οι συναρτήσεις μιας κλάσης έχουν σαν κύριο σκοπό να επενεργούν μόνο σε μεταβλητές

αυτής της κλάσης.

Συνήθως θέλουμε οι μεταβλητές μιας κλάσης να είναι «προστατευμένες» ή «απομονωμένες» από

το υπόλοιπο πρόγραμμα, γι’ αυτό και τις δηλώνουμε στο τμήμα private της κλάσης.

Συνήθως θέλουμε τις συναρτήσεις μια κλάσης να μπορεί να τις καλεί το υπόλοιπο πρόγραμμα, γι’

αυτό τις δηλώνουμε στο public τμήμα της κλάσης.

Συναρτήσεις όπως η set_aktina έχουν σαν σκοπό μόνο να αλλάζουν την τιμή μιας μεταβλητής

της κλάσης, έτσι φροντίζουμε να έχουν «είσοδο» αλλά να μην επιστρέφουν τίποτα, δηλαδή να

είναι τύπου void (συνήθως).

Συναρτήσεις όπως η give_embado έχουν σαν σκοπό μόνο να μας πουν πόση είναι η τιμή μιας

μεταβλητής της κλάσης (ή να μας δώσουν ένα αποτέλεσμα μετά από πράξεις – όπως είναι και η

περίπτωση του εμβαδού), έτσι φροντίζουμε να μην έχουν είσοδο και απλώς να επιστρέφουν μια

τιμή.

Μέσα στην κλάση (στο public τμήμα της) γράφουμε συνήθως τα πρωτότυπα των συναρτήσεών

της – κοιτάξτε το βέλος (1). Όμως πρέπει κάπου να γράψουμε τις εντολές που εκτελεί η κάθε

συνάρτηση. Κι αυτό το κάνουμε συνήθως λίγο πιο κάτω από την κλάση. Όταν γράφουμε μια

συνάρτηση με τις εντολές που περικλείει, για να φαίνεται ότι η συνάρτηση αυτή ανήκει σε μια

κλάση, πρέπει πριν από το όνομά της να υπάρχει το όνομα της κλάσης και έπειτα 2 άνω-κάτω

τελείες – κοιτάξτε τα βέλη (2) και (3).

Μια κλάση είναι ένα «καλούπι» από το οποίο θα προκύψουν αντικείμενα αυτής της κλάσης.

Δημιουργούμε αντικείμενα μια κλάσης όπως φαίνεται στο βέλος (4), δηλαδή όπως δημιουργούμε

και απλές μεταβλητές.

Και πως γίνεται να καλέσουμε μια συνάρτηση του αντικειμένου αυτού; Όπως και στις δομές,

γράφουμε το όνομα του αντικειμένου, με μια τελεία, μπροστά από το όνομα της συνάρτησης –

κοιτάξτε στο βέλος (5) τις δύο κλήσεις.

Κανείς μπορεί να αναρωτηθεί: δηλαδή, αν ήθελα να αλλάξω της τιμή της μεταβλητής aktina

του αντικειμένου kyklos1, θα μπορούσα να γράψω στο κυρίως πρόγραμμα (σε αντιστοιχία με

τις δομές): kyklos1.aktina = 5;

Θα μπορούσα, υπό προϋποθέσεις, να το κάνω αυτό, οπότε και δεν θα χρειαζόταν να καλέσω την

συνάρτηση set_aktina για να αλλάξω την τιμή της ακτίνας (κοίτα βέλος (5)), αφού θα την

άλλαζα με την παραπάνω εντολή.

Όμως αυτό δεν γίνεται στην περίπτωσή μας γιατί η μεταβλητή aktina έχει δηλωθεί στο

private τμήμα της κλάσης, άρα είναι «απομονωμένη» από το υπόλοιπο πρόγραμμα και κανείς

δεν μπορεί ούτε να δει την τιμή της, ούτε να την αλλάξει άμεσα. Μόνο συναρτήσεις της ίδιας της

κλάσης μπορούν να κάνουν κάτι τέτοιο.

Κι αν η μεταβλητή aktina είχε δηλωθεί στο public τμήμα της κλάσης, τότε η παραπάνω

εντολή θα μπορούσε να αλλάξει την τιμή της ακτίνας του kyklos1; Η απάντηση είναι ναι, σ’

αυτή την περίπτωση. Όμως αν δηλώσουμε τις μεταβλητές μιας κλάσης στο public τμήμα της,

ακυρώνουμε μόνοι μας τη στρατηγική που θέλει τις μεταβλητές των κλάσεων «προστατευμένες».

Θέλουμε στις μεταβλητές μιας κλάσης να έχουν πρόσβαση μόνο οι συναρτήσεις της κλάσης αυτής

– όχι οποιοδήποτε τμήμα του προγράμματος.

Επιπλέον, μπορεί κανείς να αναρωτηθεί: η συνάρτηση set_aktina αλλάζει την τιμή της

ακτίνας του αντικειμένου ανάλογα με την «είσοδό της». Παρομοίως, η συνάρτηση

Page 8: ΤΕΙ ΔΥΤΙΚΗΣ ΜΑΚΕΔΟΝΙΑΣ Program-Ergast...Ασκήσεις εργαστηρίου ... του και τέλος θα εμφανίζει τον αριθμό και

Τ.Ε.Ι. Δυτικής Μακεδονίας Τμήμα Διοίκ. Επιχειρήσεων (Γρεβενά)

Αντικειμενοστρεφής προγραμματισμός με C++ Δρ. Δημ. Συνδουκάς

Σελίδα 8

give_embado μας επιστρέφει την τιμή του εμβαδού, το οποίο υπολογίζει από την ακτίνα.

Κοιτώντας όμως στα βέλη (2) και (3), παρατηρούμε ότι στις εντολές που περιέχουν οι δύο

συναρτήσεις της κλάσης γράφουμε σκέτο το όνομα της μεταβλητής, δηλαδή σκέτο aktina. Δεν

θα έπρεπε να γράψουμε kyklos1.aktina ή kyklos.aktina ή τέλος πάντων κάτι

παρόμοιο; Η απάντηση είναι όχι, και να γιατί:

Μέσα στις συναρτήσεις μιας κλάσης μπορούμε να γράφουμε τα ονόματα των μεταβλητών της

κλάσης αυτής σκέτα, δηλαδή χωρίς τίποτε επιπλέον.

Και τότε, πότε θα γράφουμε kyklos1.κάτι; (όπου το «κάτι» θα είναι μια μεταβλητή ή μια

συνάρτηση της κλάσης). Απάντηση: Θα χρησιμοποιούμε το όνομα του αντικειμένου και την

τελεία (δηλαδή kyklos1.κάτι), όταν γράφουμε εντολές έξω από την κλάση, όπως για

παράδειγμα όταν γράφουμε εντολές στο κυρίως πρόγραμμα.

Γι’ αυτό βλέπετε στο βέλος (5) ότι όταν καλούμε τις συναρτήσεις set_aktina και

give_embado πρέπει να γράψουμε πριν το όνομα των συναρτήσεων το όνομα του αντικειμένου

kyklos1 με μια τελεία.

Ξαναθυμίζω ότι τις δύο συναρτήσεις της κλάσης μπορούμε να τις καλούμε όπου θέλουμε γιατί

έχουν δηλωθεί σαν public, άρα είναι «ορατές» από παντού.

Η μεταβλητή aktina έχει δηλωθεί σαν private, άρα κανείς δεν την «βλέπει», παρά μόνο οι

συναρτήσεις της κλάσης. Και μάλιστα, οι συναρτήσεις της κλάσης, όπως είπαμε, μπορούν να

χρησιμοποιούν την μεταβλητή αυτή σκέτη, σαν “aktina” – όχι σαν

όνομα_αντικειμένου.aktina, αφού είναι κομμάτι της ίδιας κλάσης.

Συνοψίζοντας:

Μια κλάση περιέχει μεταβλητές και συναρτήσεις.

Θέλουμε τις μεταβλητές της κλάσης να μην μπορεί να τις «δει» ή αλλάξει κανείς, παρά μόνο η

ίδια η κλάση, γι’ αυτό τις δηλώνουμε στο private τμήμα της.

Η ίδια η κλάση μπορεί να «δει» ή να αλλάξει τις τιμές των μεταβλητών της μέσα από τις

συναρτήσεις της. Άλλωστε, γι’ αυτό υπάρχουν οι συναρτήσεις σε μια κλάση: για να «μας λένε» τις

τιμές ή να μας επιτρέπουν να αλλάζουμε τις τιμές των μεταβλητών της κλάσης αυτής ή

γενικότερα, για να κάνουν υπολογισμούς με τις μεταβλητές της κλάσης.

Για να μπορούμε να καλούμε τις συναρτήσεις μιας κλάσης πρέπει να μην είναι «απομονωμένες»,

άρα πρέπει να τις δηλώσουμε στο public τμήμα της.

Για να καλέσουμε μια συνάρτηση που ανήκει σε κλάση, πρέπει να έχουμε πρώτα δηλώσει

(δημιουργήσει) ένα αντικείμενο αυτής της κλάσης. Έπειτα, καλούμε τη συνάρτηση γράφοντας

πρώτα το όνομα του αντικειμένου, έπειτα μια τελεία, και τέλος το όνομα της συνάρτησης, π.χ: kyklos1.set_aktina(r);

Μην χρησιμοποιείτε το όνομα της κλάσης για να καλέσετε μια συνάρτησή της! Δηλαδή μη

γράψετε την εντολή: kyklos.set_aktina(r);

Η κλάση είναι απλώς το «καλούπι». Πρέπει να δημιουργήσετε ένα αντικείμενο από το καλούπι

αυτό, και το αντικείμενο αυτό θα χρησιμοποιηθεί στις πράξεις και τις εντολές του προγράμματός

σας.

Οι συναρτήσεις μιας κλάσης χρησιμοποιούν τις μεταβλητές της κλάσης αυτής «σκέτες», δηλαδή

χωρίς τελείες κλπ.

Όταν όμως χρησιμοποιείτε κάποιο συστατικό της κλάσης στο κυρίως πρόγραμμα (ή γενικότερα

έξω από την κλάση), τότε πρέπει να χρησιμοποιείτε τον συμβολισμό με την τελεία, δηλαδή: όνομα_αντικειμένου.συνάρτηση(...)

όνομα_αντικειμένου.μεταβλητή

αρκεί να θυμάστε ότι για να χρησιμοποιήστε κάποιο συστατικό της κλάσης έξω από την κλάση, θα

πρέπει να είναι public, δηλαδή προσβάσιμο δημοσίως.

Page 9: ΤΕΙ ΔΥΤΙΚΗΣ ΜΑΚΕΔΟΝΙΑΣ Program-Ergast...Ασκήσεις εργαστηρίου ... του και τέλος θα εμφανίζει τον αριθμό και

Τ.Ε.Ι. Δυτικής Μακεδονίας Τμήμα Διοίκ. Επιχειρήσεων (Γρεβενά)

Αντικειμενοστρεφής προγραμματισμός με C++ Δρ. Δημ. Συνδουκάς

Σελίδα 9

Αφού η γενικότερη στρατηγική υπαγορεύει οι μεταβλητές των κλάσεων να είναι private, ώστε

να μην μπορεί να τις «δει» ή «πειράξει» κανείς εκτός από την ίδια την κλάση, θα πρέπει, αφού

δηλώσουμε τις μεταβλητές αυτές να σκεφτούμε:

o Θέλουμε την «τάδε» μεταβλητή της κλάσης να μπορούμε να την αλλάξουμε; Τότε πρέπει να

γράψουμε και μια συνάρτηση η οποία να δέχεται μια «είσοδο» και να αλλάζει την τιμή αυτής

της μεταβλητής.

o Θέλουμε να μπορούμε να «δούμε» ποια είναι η τιμή της «τάδε» μεταβλητής της κλάσης; Τότε

πρέπει να γράψουμε και μια συνάρτηση η οποία να μας επιστρέφει την τιμή αυτής της

μεταβλητής.

o Θέλουμε η κλάση να υπολογίζει κάτι (για παράδειγμα το εμβαδόν) και να μας επιστρέφει την

τιμή αυτή; Τότε και πάλι (παρόμοια με την προηγούμενη κουκίδα) θα πρέπει να γράψουμε

μια συνάρτηση η οποία να κάνει τον υπολογισμό και να μας επιστρέφει την τιμή αυτή.

o Οι συναρτήσεις αυτές πρέπει να είναι public, για να μπορεί να τις καλεί ο οποιοσδήποτε,

για παράδειγμα το κυρίως πρόγραμμά μας.

Άσκηση 6. Προσθήκη κι άλλης συνάρτησης-μέλους.

Σκοπός της άσκησης είναι να δείξει τη χρήση των κλάσεων και των αντικειμένων τους.

Να προσθέσετε στην κλάση του κύκλου μια ακόμη συνάρτηση-μέλος, η οποία να υπολογίζει και

να επιστρέφει την περίμετρο του κύκλου.

Στο κυρίως πρόγραμμα, να προσθέσετε:

o τον υπολογισμό της περιμέτρου (με κλήση της ανάλογης συνάρτησης-μέλους) και

o εμφάνισή της στην οθόνη με ανάλογο μήνυμα.

Απάντηση:

Προσθήκη (1). Ο ορισμός της κλάσης kyklos θα περιλαμβάνει την νέα συνάρτηση, την οποία

ονομάζω give_perimetro. (Δείτε το βέλος (1) παρακάτω).

Προσθήκη (2). Επιπλέον, θα γράψω και την ίδια την συνάρτηση, η οποία περιέχει τον υπολογισμό της

περιμέτρου. (Δείτε το βέλος (2) παρακάτω).

class kyklos {

private:

double aktina;

public:

void set_aktina(double a);

double give_embadon();

double give_perimetro();

};

Double kyklos::give_perimetro() {

return 2*3.14*aktina;

}

Προσθήκη (3).Στο κυρίως πρόγραμμα (δείτε το βέλος (3) παρακάτω), θα προσθέσουμε την κλήση της

συνάρτησης ως εξής (μην ξεχάσετε να δηλώσετε μια δεκαδική μεταβλητή per, για να αποθηκευθεί η

επιστρεφόμενη τιμή):

per = kyklos1.give_perimetro(); // Κλήση συνάρτησης-μέλους

cout << "H PERIMETROS TOY KYKLOY EINAI: " << per << endl;

(1)

(2)

(3)

Page 10: ΤΕΙ ΔΥΤΙΚΗΣ ΜΑΚΕΔΟΝΙΑΣ Program-Ergast...Ασκήσεις εργαστηρίου ... του και τέλος θα εμφανίζει τον αριθμό και

Τ.Ε.Ι. Δυτικής Μακεδονίας Τμήμα Διοίκ. Επιχειρήσεων (Γρεβενά)

Αντικειμενοστρεφής προγραμματισμός με C++ Δρ. Δημ. Συνδουκάς

Σελίδα 10

Άσκηση 7. Default constructor και destructor μιας κλάσης.

Σκοπός της άσκησης είναι να δείξει πως γράφουμε τον εξ’ ορισμού κατασκευαστή ή

defaultconstructor μιας κλάσης αλλά και τον καταστροφέα ή destructor της, ποιος είναι ο ρόλος τους,

αλλά και πότε και πως καλούνται.

Να δημιουργήσετε μια κλάση, η οποία να αντιπροσωπεύει έναν κύκλο. Συγκεκριμένα, να αποτελείται:

από μια μεταβλητή-μέλος (ιδιότητα), που θα αντιπροσωπεύει την (κινητής υποδιαστολής διπλής

ακρίβειας) ακτίνα του, και

από μια συνάρτηση-μέλος (μέθοδο), που θα αλλάζει την τιμή της ακτίνας του.

από μια συνάρτηση-μέλος (μέθοδο), που θα υπολογίζει και επιστρέφει την περίμετρό του (κινητής

υποδιαστολής διπλής ακρίβειας).

έναν defaultconstructor (εξ’ ορισμού κατασκευαστή), ο οποίος να αρχικοποιεί την μεταβλητή της

κλάσης που περιέχει την ακτίνα στην τιμή 1.

έναν destructor(καταστροφέα), ο οποίος να περιέχει μια εντολή η οποία θα εμφανίζει το ακόλουθο

μήνυμα στην οθόνη: OKYKLOSKATASTRAFHKE!

Κατόπιν να γράψετε ένα πρόγραμμα όπου:

Να δημιουργήσετε ένα αντικείμενο της κλάσης κύκλου

Το πρόγραμμα να υπολογίζει κατευθείαν την περίμετρο του παραπάνω αντικειμένου καλώντας

την κατάλληλη συνάρτηση-μέλος της κλάσης (χωρίς εσείς να δώσετε πρώτα τιμή για την ακτίνα

του) και να την εμφανίζει στην οθόνη με ανάλογο μήνυμα.

Προσέξτε: δεν έχετε καθορίσει τιμή για την ακτίνα του κύκλου – άρα, πόση θα είναι η ακτίνα του

και πόση θα προκύψει η περίμετρός του;

Κατόπιν ο υπολογιστής να ζητά από τον χρήστη την τιμή της ακτίνας και να τη διαβάζει

να αλλάζει την ακτίνα του αντικειμένου-κύκλου στην τιμή που έδωσε ο χρήστης, καλώντας την

κατάλληλη συνάρτηση-μέλος της κλάσης

να υπολογίζει την περίμετρο του παραπάνω αντικειμένου καλώντας την κατάλληλη συνάρτηση-

μέλος της κλάσης (ξανά) και να την εμφανίζει στην οθόνη με ανάλογο μήνυμα.

#include <iostream>

using namespace std;

class kyklos {

private:

doubleaktina;

public:

kyklos();

~kyklos();

void set_aktina(double a);

double give_perimetro();

};

kyklos::kyklos() { // Default constructor

aktina = 1;

}

kyklos::~kyklos() { // Destructor

cout << "O KYKLOS KATASTRAFHKE!" << endl;

}

void kyklos::set_aktina(double a) {

aktina = a; }

double kyklos::give_perimetro() {

return 2*3.14*aktina; }

Page 11: ΤΕΙ ΔΥΤΙΚΗΣ ΜΑΚΕΔΟΝΙΑΣ Program-Ergast...Ασκήσεις εργαστηρίου ... του και τέλος θα εμφανίζει τον αριθμό και

Τ.Ε.Ι. Δυτικής Μακεδονίας Τμήμα Διοίκ. Επιχειρήσεων (Γρεβενά)

Αντικειμενοστρεφής προγραμματισμός με C++ Δρ. Δημ. Συνδουκάς

Σελίδα 11

void main() {

kyklos kyklos1; // Δήλωσηαντικειμένου,

// τηςκλάσης kyklos

double r;

double per;

per = kyklos1.give_perimetro(); // Κλήσησυνάρτησης-μέλους

cout << "H PERIMETROS TOY KYKLOY EINAI: " << per << endl;

cout << "DOSE TIMH AKTINAS: ";

cin >> r;

kyklos1.set_aktina(r); // Κλήσησυνάρτησης-μέλους

per = kyklos1.give_perimetro(); // Κλήσησυνάρτησης-μέλους

cout << "H PERIMETROS TOY KYKLOY EINAI: " << per << endl;

}

Σχόλια:

Ο κατασκευαστής μιας κλάσης καλείται αυτομάτως κάθε φορά που δημιουργείτε ένα αντικείμενο

αυτής της κλάσης. Εσείς δεν αντιλαμβάνεστε ότι ο κατασκευαστής καλείται, αυτός όμως πράγματι

καλείται.

Κι αν δεν υπάρχει κατασκευαστής για την κλάση, όπως στα προηγούμενα παραδείγματα; Τότε ο

compiler δημιουργεί μόνος του έναν κατασκευαστή (defaultconstructor), ο οποίος δεν κάνει τίποτα,

δηλαδή δεν περιέχει καμία εντολή. Αυτό ίσχυε στα προηγούμενα παραδείγματα, όπου δεν είχαμε

δημιουργήσει κατασκευαστή για τις κλάσεις μας.

Ένας κατασκευαστής είναι «default» όταν δεν έχει καθόλου παραμέτρους ή οι παράμετροί του

έχουν εξ΄ ορισμού τιμές.

Σημείο (1). Κοιτάξτε στο πρόγραμμα παραπάνω το αντίστοιχο σημείο - βέλος (1). Παρατηρήστε ότι

στο σημείο αυτό ο υπολογιστής θα βρει πόση είναι η περίμετρος του αντικειμένου kyklos1 και θα

μας εμφανίσει το αποτέλεσμα στην οθόνη. Όμως ο χρήστης του υπολογιστή δεν έχει δώσει, δεν έχει

καθορίσει, κάποια τιμή για την ακτίνα του κύκλου μέχρι τώρα!

Και τότε, ποια θα είναι η ακτίνα του αντικειμένου kyklos1; Και πως θα υπολογιστεί η περίμετρος

ενός κύκλου χωρίς ακτίνα; Διαβάστε παρακάτω…

Ο default constructor καλείται μόλις δημιουργηθεί ένα νέο αντικείμενο της κλάσης και δίνει

αυτομάτως την τιμή 1 στην ακτίνα. Έτσι, μόλις δηλώσουμε (δημιουργήσουμε) το αντικείμενο

kyklos1, αυτό παίρνει αυτομάτως σαν τιμή της ακτίνας του το 1. Έτσι υπάρχει κάποια αρχική τιμή

για την ακτίνα, ακόμη κι αν δεν δώσει ο χρήστης μια δική του.

Σημείο (2). Κοιτάξτε στο πρόγραμμα παραπάνω το αντίστοιχο σημείο - βέλος (2). Σ’ αυτό το σημείο,

ο υπολογιστής ζητά από τον χρήστη να προσδιορίσει πόση είναι η ακτίνα του κύκλου, διαβάζει την

τιμή που θα πληκτρολογηθεί και αλλάζει την τιμή του αντικειμένου-κύκλος καλώντας τη συνάρτηση

set_aktina.

Κατόπιν, καλώντας τη συνάρτηση give_perimetro, υπολογίζει την περίμετρο του κύκλου ξανά

και την εμφανίζει στην οθόνη. Η περίμετρος φυσικά τώρα θα είναι διαφορετική απ’ ότι στο σημείο (1),

εκτός κι αν ο χρήστης έδωσε ακτίνα ίση με 1, δηλαδή στην ουσία δεν την άλλαξε.

(1)

(2)

Page 12: ΤΕΙ ΔΥΤΙΚΗΣ ΜΑΚΕΔΟΝΙΑΣ Program-Ergast...Ασκήσεις εργαστηρίου ... του και τέλος θα εμφανίζει τον αριθμό και

Τ.Ε.Ι. Δυτικής Μακεδονίας Τμήμα Διοίκ. Επιχειρήσεων (Γρεβενά)

Αντικειμενοστρεφής προγραμματισμός με C++ Δρ. Δημ. Συνδουκάς

Σελίδα 12

Άσκηση 8. Δημιουργία constructor που δεν είναι default.

Σκοπός της άσκησης είναι να δείξει τον τρόπο δημιουργίας και χρήσης κατασκευαστή κλάσης

(constructor) που δεν είναι default.

Να δημιουργήσετε μια κλάση, η οποία να αντιπροσωπεύει έναν κύκλο.

o Συγκεκριμένα, να αποτελείται από μια μεταβλητή-μέλος (ιδιότητα), που θα αντιπροσωπεύει

την (κινητής υποδιαστολής διπλής ακρίβειας) ακτίνα του, και

o από μια συνάρτηση-μέλος (μέθοδο), που θα υπολογίζει και επιστρέφει την περίμετρό του

(κινητής υποδιαστολής διπλής ακρίβειας).

Επιπλέον να δημιουργήσετε 2 constructors:

o ο ένας θα είναι default, και θα αρχικοποιεί την ακτίνα στην τιμή 1.

o ο δεύτερος, θα έχει μια παράμετρο σαν «είσοδο», η τιμή της οποίας θα αρχικοποιεί την

ακτίνα.

και έναν destructor, ο οποίος θα εμφανίζει το μήνυμα: “KATASTROFHKYKLOY”

Να γράψετε ένα πρόγραμμα, στο οποίο:

Να δημιουργήσετε 2 αντικείμενα της κλάσης κύκλου:

o ένα χωρίς να καθορίσετε καμιά αρχική τιμή για την ακτίνα, και

o ένα με αρχική τιμή ακτίνας το 4

Στη συνέχεια, το πρόγραμμά σας να υπολογίζει την περίμετρο του καθενός κύκλου και να

εμφανίζει τις περιμέτρους σε ξεχωριστές γραμμές με ανάλογα μηνύματα.

Προσέξτε ότι η άσκηση δεν ζητά να δώσει ο χρήστης τιμή για την ακτίνα του κύκλου, οπότε θα

ισχύει η τιμή της ακτίνας που δίνουν οι κατασκευαστές (contructors) της κλάσης.

#include <iostream>

using namespace std;

class kyklos {

private:

double aktina;

public:

kyklos();

kyklos(double a);

~kyklos();

double give_perimetro();

};

kyklos::kyklos() { // Default constructor

aktina = 1; }

kyklos::kyklos(double a) { // Constructor

aktina = a; }

kyklos::~kyklos() { // Destructor

cout <<"O KYKLOS KATASTRAFHKE!"<< endl;

}

double kyklos::give_perimetro() {

return 2*3.14*aktina; }

Page 13: ΤΕΙ ΔΥΤΙΚΗΣ ΜΑΚΕΔΟΝΙΑΣ Program-Ergast...Ασκήσεις εργαστηρίου ... του και τέλος θα εμφανίζει τον αριθμό και

Τ.Ε.Ι. Δυτικής Μακεδονίας Τμήμα Διοίκ. Επιχειρήσεων (Γρεβενά)

Αντικειμενοστρεφής προγραμματισμός με C++ Δρ. Δημ. Συνδουκάς

Σελίδα 13

void main() {

kyklos kyklos1, kyklos2(4); // Δήλωση 2 αντικειμένων,

// τηςκλάσης kyklos

double per1, per2;

per1 = kyklos1.give_perimetro(); // Κλήσησυνάρτησης-μέλους

cout <<"H PERIMETROS TOY 1ou KYKLOY EINAI: " << per1 << endl;

per2 = kyklos2.give_perimetro(); // Κλήσησυνάρτησης-μέλους

cout <<"H PERIMETROS TOY 2ou KYKLOY EINAI: " << per2 << endl;

}

Σχόλια:

Παρατηρήστε ότι η δημιουργία 2 (ή περισσότερων) constructors συνεπάγεται υπερφόρτωσή τους

(overloading).

Όμως ποιος constructor ενεργοποιείται όταν δηλώνετε ένα νέο αντικείμενο της κλάσης του κύκλου;

Όταν δημιουργείτε ένα νέο αντικείμενο, χωρίς να καθορίζετε κάποια αρχική τιμή για την

ακτίνα, όπως π.χ.: kyklos kyklos1;

τότε καλείται ο constructor που δεν έχει καθόλου παραμέτρους, δηλαδή ο default contructor.

Όταν όμως ορίζετε αρχική τιμή για την ακτίνα ταυτόχρονα με τη δημιουργία του νέου

αντικειμένου, όπως π.χ.: kyklos kyklos2(4);

τότε καλείται ο constructor που έχει μια παράμετρο στις παρενθέσεις του. Εδώ ορίσαμε σαν

αρχική τιμή ακτίνας το 4.

Θα μπορούσατε να καθορίσετε μόνο έναν constructor για την κλάση του κύκλου. Τότε όμως πως θα

αντιμετωπίζατε την περίπτωση της δημιουργίας ενός αντικειμένου για το οποίο δεν καθορίζεται μια

αρχική τιμή για την ακτίνα; (όπως είναι ο kyklos1)

Μια λύση είναι να κάνουμε την παράμετρο a του constructorνα έχει μια εξ’ ορισμού τιμή. Έτσι, στην

δήλωση της κλάσης μόνο χρειάζεται να κάνουμε την αλλαγή που σημειώνεται με βέλος παρακάτω:

class kyklos {

private:

int aktina;

public:

kyklos(double a=1);

~kyklos();

double give_perimetro();

};

Παρατηρήστε ότι υπάρχει πια μόνο ένας constructor. Όμως ακόμη κι έτσι, αν δημιουργήσουμε ένα

αντικείμενο χωρίς να καθορίσουμε αρχική τιμή της ακτίνας του, π.χ.: kyklos kyklos1;

το αντικείμενο kyklos1 θα έχει αρχική τιμή ακτίνας το 1, λόγω του ότι η παράμετρος του constructor

έχει εξ’ ορισμού τιμή το 1.

Ερώτηση: αυτός ο κατασκευαστής, που υποδεικνύεται παραπάνω με το βέλος, χαρακτηρίζεται ως

«default» ή όχι;

Page 14: ΤΕΙ ΔΥΤΙΚΗΣ ΜΑΚΕΔΟΝΙΑΣ Program-Ergast...Ασκήσεις εργαστηρίου ... του και τέλος θα εμφανίζει τον αριθμό και

Τ.Ε.Ι. Δυτικής Μακεδονίας Τμήμα Διοίκ. Επιχειρήσεων (Γρεβενά)

Αντικειμενοστρεφής προγραμματισμός με C++ Δρ. Δημ. Συνδουκάς

Σελίδα 14

Άσκηση 9. Κληρονομικότητα. Δημιουργία κλάσης παραγόμενης από άλλη κλάση.

Σκοπός της άσκησης είναι να δείξει:

o πως μπορούμε να δημιουργήσουμε μια νέα κλάση παίρνοντας στοιχεία από μια άλλη κλάση που

υπάρχει ήδη και

o ποια είναι η σχέση της νέας κλάσης με τις συναρτήσεις-μέλη και τις μεταβλητές-μέλη της βασικής

της κλάσης. Επιπλέον, παρουσιάζεται η λέξη-κλειδί protected.

Να δημιουργήσετε μια κλάση, η οποία να αντιπροσωπεύει ένα τετράγωνο.

Συγκεκριμένα, να αποτελείται

από μια μεταβλητή-μέλος (ιδιότητα), που θα αντιπροσωπεύει το μήκος της

πλευράς του (κινητής υποδιαστολής διπλής ακρίβειας), η οποία να μπορεί να

προσπελαστεί απ’ ευθείας από τους απογόνους του και

από μια συνάρτηση-μέλος (μέθοδο), που θα υπολογίζει και επιστρέφει την

περίμετρό του.

Επιπλέον να δημιουργήσετε έναν constructor, ο οποίος θα έχει μια παράμετρο σαν «είσοδο», η

τιμή της οποίας θα αρχικοποιεί το μήκος της πλευράς. Η παράμετρος να έχει εξ’ ορισμού τιμή το

1.

και έναν destructor, ο οποίος θα εμφανίζει το μήνυμα: “KATASTROFHTETRAGONOY”

Να δημιουργήσετε μια ακόμη κλάση, η οποία να αντιπροσωπεύει ένα παραλληλεπίπεδο

(ορθογώνιο) και να προέρχεται από την κλάση (να έχει σαν βασική της κλάση) την κλάση του

τετραγώνου.

Συγκεκριμένα, να αποτελείται

από μια μεταβλητή-μέλος (ιδιότητα), που θα αντιπροσωπεύει

το ύψος του (κινητής υποδιαστολής διπλής ακρίβειας), και

από μια συνάρτηση-μέλος (μέθοδο), που θα υπολογίζει και θα

επιστρέφει τον όγκο του (εμβαδό βάσης x ύψος).

Επιπλέον να δημιουργήσετε έναν constructor, ο οποίος θα έχει

2 παραμέτρους σαν «είσοδο», η 1η θα αρχικοποιεί το μήκος της

πλευράς της βάσης του, και η 2η το ύψος του

παραλληλεπίπεδου. Η 2η παράμετρος να έχουν εξ’ ορισμού τιμή

το 1.

και έναν destructor, ο οποίος θα εμφανίζει το μήνυμα: “KATASTROFHPARALLHLEPIPEDOY”

Να γράψετε ένα πρόγραμμα, στο οποίο:

Να δημιουργήσετε ένα αντικείμενο της κλάσης παραλληλεπίπεδου, με αρχική τιμή μήκους

πλευράς βάσης το 5 και αρχική τιμή του ύψους το 10.

Στη συνέχεια, το πρόγραμμά σας να υπολογίζει (χωρίς ο χρήστης να δώσει καμία τιμή από το

πληκτρολόγιο):

o την περίμετρο της βάσης του παραλληλεπίπεδου καθώς και

o τον όγκο του παραλληλεπίπεδου

και να τα εμφανίζει στην οθόνη σε ξεχωριστές γραμμές με ανάλογα μηνύματα.

#include <iostream>

using namespace std;

class square {

protected:

double plevra;

public:

square(double p=1);

~square();

double give_perimetro();

};

square::square(double p) { // Constructor

plevra = p;

}

Η κλάση του τετραγώνου (1)

Page 15: ΤΕΙ ΔΥΤΙΚΗΣ ΜΑΚΕΔΟΝΙΑΣ Program-Ergast...Ασκήσεις εργαστηρίου ... του και τέλος θα εμφανίζει τον αριθμό και

Τ.Ε.Ι. Δυτικής Μακεδονίας Τμήμα Διοίκ. Επιχειρήσεων (Γρεβενά)

Αντικειμενοστρεφής προγραμματισμός με C++ Δρ. Δημ. Συνδουκάς

Σελίδα 15

square::~square() { // Destructor

cout << "TO TETRAGONO KATASTRAFHKE!" << endl;

}

double square::give_perimetro() {

return 4.0 * plevra;

}

class par_epip : public square {

private:

double ypsos;

public:

par_epip(double p, double y=1);

~par_epip();

double give_ogo();

};

// Constructor

par_epip::par_epip(double p, double y) : square(p) {

ypsos = y;

}

par_epip::~par_epip() { // Destructor

cout <<"TO PARALLHLEPIPEDO KATASTRAFHKE!"<< endl;

}

double par_epip::give_ogo() {

return plevra * plevra * ypsos;

}

void main() {

par_epip p1(5, 10); // Δήλωση ενός αντικειμένου,

// τηςκλάσης par_epip

double per, og;

per = p1.give_perimetro(); // Κλήσησυνάρτησης-μέλους

cout << "H PERIMETROS TOY PARHLLEPIPEDOY EINAI: " << per << endl;

og = p1.give_ogo(); // Κλήση συνάρτησης-μέλους

cout << "O OGOS TOY PARALLHLEPIPEDOY EINAI: " << og << endl;

}

Σχόλια: (υπάρχουν αντίστοιχα αριθμημένα βέλη)

(1) Η μεταβλητή-μέλος plevra της κλάσης square είναι protected, που σημαίνει ότι

συμπεριφέρεται σαν private εκτός από τις κλάσεις-απογόνους (όπως η par_epip) για τις οποίες

θα συμπεριφέρεται σαν public. Αυτό σημαίνει ότι τα αντικείμενα της κλάσης par_epip θα

μπορούν να προσπελάζουν απ’ ευθείας την μεταβλητή plevra.

(2) Παρατηρήστε ότι κατά τη δήλωση της κλάσης par_epip, δείχνουμε ότι προέρχεται από την

κλάση square.

(3) Ο constructor της κλάσης par_epip καθορίζει την αρχική τιμή που θα «σταλεί» στον constructor

της κλάσης square. Αυτό γίνεται γράφοντας το :square(p) μετά την δεξιά παρένθεση του

constructor της κλάσης par_epip. Η αρχική αυτή τιμή είναι η 1η παράμετρός της, δηλαδή το p.

Η κλάση του παραλληλεπίπεδου (2)

(3)

Page 16: ΤΕΙ ΔΥΤΙΚΗΣ ΜΑΚΕΔΟΝΙΑΣ Program-Ergast...Ασκήσεις εργαστηρίου ... του και τέλος θα εμφανίζει τον αριθμό και

Τ.Ε.Ι. Δυτικής Μακεδονίας Τμήμα Διοίκ. Επιχειρήσεων (Γρεβενά)

Αντικειμενοστρεφής προγραμματισμός με C++ Δρ. Δημ. Συνδουκάς

Σελίδα 16

Άσκηση 10. Κληρονομικότητα. Δημιουργία κλάσης παραγόμενης από άλλη κλάση.

Σκοπός της άσκησης είναι να δείξει:

o πως μπορούμε να δημιουργήσουμε μια νέα κλάση παίρνοντας στοιχεία από μια άλλη κλάση που

υπάρχει ήδη και

o ποια είναι η σχέση της νέας κλάσης με τις συναρτήσεις-μέλη και τις μεταβλητές-μέλη της βασικής

της κλάσης. Επιπλέον, παρουσιάζεται η λέξη-κλειδί protected.

Να δημιουργήσετε μια κλάση, η οποία να αντιπροσωπεύει έναν κύκλο.

Συγκεκριμένα, να αποτελείται

από μια μεταβλητή-μέλος (ιδιότητα), που θα αντιπροσωπεύει την ακτίνα

του (κινητής υποδιαστολής διπλής ακρίβειας), η οποία να μπορεί να

προσπελαστεί απ’ ευθείας από τους απογόνους του και

από μια συνάρτηση-μέλος (μέθοδο), που θα υπολογίζει και επιστρέφει την

περίμετρό του.

Επιπλέον να δημιουργήσετε έναν constructor, ο οποίος θα έχει μια παράμετρο σαν «είσοδο», η

τιμή της οποίας θα αρχικοποιεί την ακτίνα. Η παράμετρος να έχει εξ’ ορισμού τιμή το 1.

και έναν destructor, ο οποίος θα εμφανίζει το μήνυμα: “KATASTROFHKYKLOY”

Να δημιουργήσετε μια ακόμη κλάση, η οποία να αντιπροσωπεύει έναν κύλινδρο και να

προέρχεται από την κλάση (να έχει σαν βασική της κλάση) την κλάση του κύκλου.

Συγκεκριμένα, να αποτελείται

από μια μεταβλητή-μέλος (ιδιότητα), που θα αντιπροσωπεύει

το ύψος του (κινητής υποδιαστολής διπλής ακρίβειας),

από μια μεταβλητή-μέλος (ιδιότητα), που να αντιπροσωπεύει

την πυκνότητα του υλικού του (κινητής υποδιαστολής διπλής

ακρίβειας), και

από μια συνάρτηση-μέλος (μέθοδο), που θα υπολογίζει και

επιστρέφει την μάζα του (όγκος x πυκνότητα), όπου όγκος =

εμβαδό βάσης x ύψος.

Επιπλέον να δημιουργήσετε έναν constructor, ο οποίος θα

έχει 3 παραμέτρους σαν «είσοδο», η 1η θα αρχικοποιεί την

ακτίνα, η 2η το ύψος και η 3η την πυκνότητα του κυλίνδρου. Η 2η και η 3η παράμετρος να έχουν

εξ’ ορισμού τιμή το 1.

και έναν destructor, ο οποίος θα εμφανίζει το μήνυμα: “KATASTROFHKYLINDROY”

Να γράψετε ένα πρόγραμμα, στο οποίο:

Να δημιουργήσετε ένα αντικείμενο της κλάσης κυλίνδρου, με αρχική τιμή ακτίνας το 20,

πυκνότητας το 2 και αρχική τιμή του ύψους το 5.

Στη συνέχεια, το πρόγραμμά σας να υπολογίζει (χωρίς ο χρήστης να δώσει καμιά τιμή από το

πληκτρολόγιο):

o την περίμετρο της βάσης του κυλίνδρου καθώς και

o την μάζα του κυλίνδρου

και να τα εμφανίζει στην οθόνη σε ξεχωριστές γραμμές με ανάλογα μηνύματα.

#include <iostream>

using namespace std;

class kyklos {

protected:

double aktina;

public:

kyklos(double a=1);

~kyklos();

double give_perimetro();

};

kyklos::kyklos(double a) { // Constructor

aktina = a;

}

Η κλάση του κύκλου (1)

Page 17: ΤΕΙ ΔΥΤΙΚΗΣ ΜΑΚΕΔΟΝΙΑΣ Program-Ergast...Ασκήσεις εργαστηρίου ... του και τέλος θα εμφανίζει τον αριθμό και

Τ.Ε.Ι. Δυτικής Μακεδονίας Τμήμα Διοίκ. Επιχειρήσεων (Γρεβενά)

Αντικειμενοστρεφής προγραμματισμός με C++ Δρ. Δημ. Συνδουκάς

Σελίδα 17

kyklos::~kyklos() { // Destructor

cout <<"O KYKLOS KATASTRAFHKE!"<< endl;

}

double kyklos::give_perimetro() {

return 2*3.14*aktina;

}

class kylindros : public kyklos {

private:

double pyknotita;

double ypsos;

public:

kylindros(double a, double p=1, double y=1);

~kylindros();

double give_maza();

};

// Constructor

kylindros::kylindros(double a, double p, double y) : kyklos(a) {

pyknotita = p;

ypsos = y;

}

kylindros::~kylindros() { // Destructor

cout <<"O KYLINDROS KATASTRAFHKE!"<< endl;

}

double kylindros::give_maza() {

return 3.14 * aktina * aktina * ypsos * pyknotita;

}

void main() {

kylindros kyl1(20,2,5); // Δήλωση ενός αντικειμένου,

// τηςκλάσης kylindros

double per, m;

per = kyl1.give_perimetro(); // Κλήσησυνάρτησης-μέλους

cout <<"H PERIMETROS TOY KYLINDROY EINAI: "<< per << endl;

m = kyl1.give_maza(); // Κλήση συνάρτησης-μέλους

cout <<"H MAZA TOY KYLINDROY EINAI: "<< m << endl;

}

Σχόλια: (υπάρχουν αντίστοιχα αριθμημένα βέλη)

(1) Η μεταβλητή-μέλος aktina της κλάσης kyklos είναι protected, που σημαίνει ότι

συμπεριφέρεται σαν private εκτός από τις κλάσεις-απογόνους (όπως η kylindros) για τις

οποίες θα συμπεριφέρεται σαν public. Αυτό σημαίνει ότι τα αντικείμενα της κλάσης kylindros

θα μπορούν να προσπελάζουν απ’ ευθείας την μεταβλητή aktina.

(2) Παρατηρήστε ότι κατά τη δήλωση της κλάσης kylindros, δείχνουμε ότι προέρχεται από την

κλάση kyklos.

(3) Ο constructor της κλάσης kylindros καθορίζει την αρχική τιμή που θα «σταλεί» στον

constructor της κλάσης kyklos. Αυτό γίνεται γράφοντας το :kyklos(a) μετά την δεξιά

παρένθεση του constructor της κλάσης kylindros. Η αρχική αυτή τιμή είναι η 1η παράμετρός

της, δηλαδή το a.

Η κλάση του κυλίνδρου (2)

(3)

Page 18: ΤΕΙ ΔΥΤΙΚΗΣ ΜΑΚΕΔΟΝΙΑΣ Program-Ergast...Ασκήσεις εργαστηρίου ... του και τέλος θα εμφανίζει τον αριθμό και

Τ.Ε.Ι. Δυτικής Μακεδονίας Τμήμα Διοίκ. Επιχειρήσεων (Γρεβενά)

Αντικειμενοστρεφής προγραμματισμός με C++ Δρ. Δημ. Συνδουκάς

Σελίδα 18

Άσκηση 11. Πίνακες (διατάξεις) αντικειμένων.

Σκοπός της άσκησης είναι να δείξει πως δημιουργούμε και χειριζόμαστε πίνακες αντικειμένων.

Να δημιουργήσετε μια κλάση κύκλου, η οποία θα αποτελείται:

από μια μεταβλητή-μέλος (ιδιότητα) που θα αντιπροσωπεύει την ακτίνα του (κινητής

υποδιαστολής διπλής ακρίβειας)

από έναν constructor χωρίς παραμέτρους, ο οποίος αρχικοποιεί την ακτίνα με την τιμή 1,

έναν destructor, που να μην κάνει τίποτα

από μια συνάρτηση-μέλος (μέθοδο) που να μπορεί να αλλάξει την τιμή της ακτίνας και να

ονομάζεται set_aktina (θα δέχεται σαν "είσοδο" έναν κινητής υποδιαστολής διπλής

ακρίβειας αριθμό, ο οποίος θα αποτελεί την τιμή της ακτίνας)

από μια συνάρτηση-μέλος (μέθοδο), χωρίς παραμέτρους, που να επιστρέφει το εμβαδόν του

κύκλου (κινητής υποδιαστολής διπλής ακρίβειας) και να ονομάζεται give_embado.

Να γράψετε ένα πρόγραμμα που:

να δηλώνει έναν πίνακα (διάταξη) τεσσάρων αντικειμένων τύπου κύκλου

κατόπιν, επαναληπτικά:

o να ζητά 4 φορές από τον χρήστη την τιμή της ακτίνας ισάριθμων κύκλων

o και μέσω της συνάρτησης-μέλους της κλάσης κύκλου να "περνά" αυτή την τιμή σε

καθένα από τα 4 αντικείμενα.

Στη συνέχεια, να υπολογίζει επαναληπτικά και να εμφανίζει το εμβαδόν του κάθε

αντικειμένου-κύκλου.

#include <iostream>

using namespace std;

class circle {

private:

double aktina;

public:

circle();

~circle();

void set_aktina(double a);

double give_embado();

};

circle::circle() {

aktina = 1; }

circle::~circle() { }

void circle::set_aktina(double a) {

aktina = a; }

double circle::give_embado() {

return 3.14*aktina*aktina; }

void main() {

circle k[4];

int i;

double ak, emb;

Η κλάση.

default constructor

destructor

συνάρτηση της κλάσης

συνάρτηση της κλάσης

Δήλωση πίνακα με 4 αντικείμενα

Page 19: ΤΕΙ ΔΥΤΙΚΗΣ ΜΑΚΕΔΟΝΙΑΣ Program-Ergast...Ασκήσεις εργαστηρίου ... του και τέλος θα εμφανίζει τον αριθμό και

Τ.Ε.Ι. Δυτικής Μακεδονίας Τμήμα Διοίκ. Επιχειρήσεων (Γρεβενά)

Αντικειμενοστρεφής προγραμματισμός με C++ Δρ. Δημ. Συνδουκάς

Σελίδα 19

for(i=0; i<=3; i++) {

cout <<"DOSE TIMH AKTINAS: ";

cin >> ak;

k[i].set_aktina(ak);

}

cout <<"TA EMBADA TON KYKLON EINAI: "<< endl;

for(i=0; i<=3; i++) {

emb = k[i].give_embado();

cout <<"TO EMBADO TOY "<< i <<" KYKLOY EINAI: "<< emb<< endl;

}

}

Σχόλια:

Ένας πίνακας (οποιουδήποτε τύπου, ακόμη και int, float, κλπ) δηλώνεται δίνοντας τον αριθμό

των θέσεών του μέσα σε τετράγωνες παρενθέσεις, π.χ.

float x[3]; ή char c[10]; ή circle k[4];

Η πρώτη θέση ενός πίνακα στην C++ είναι πάντα η θέση 0 (όχι η 1). Έτσι ο πίνακας x, που

δηλώσαμε παραπάνω, αποτελείται από τους δεκαδικούς x[0], x[1] και x[2]. Ο πίνακας k, θα

αποτελείται από τους κύκλους k[0], k[1], k[2] και k[3].

Φανταστείτε πόσο επίπονο είναι να γράφουμε χωριστά κάθε εντολή για κάθε θέση ενός πίνακα.

Για παράδειγμα, αν θέλουμε να καθορίσουμε πόση είναι η ακτίνα καθενός από τους 4 κύκλους, θα

γράφαμε:

cout << "DOSE TIMH AKTINAS (akeraio): ";

cin >> ak;

k[0].set_aktina(ak);

cout << "DOSE TIMH AKTINAS (akeraio): ";

cin >> ak;

k[1].set_aktina(ak);

... κλπ ...

Παρατηρείστε ότι στην πραγματικότητα έχουμε 3 εντολές που επαναλαμβάνονται και το μόνο που

αλλάζει είναι ο αριθμός μέσα στις τετράγωνες παρενθέσεις, που γίνεται 0, 1, 2, κλπ.

Αν λοιπόν γράψουμε μέσα στις τετράγωνες παρενθέσεις μια μεταβλητή i και κανονίσουμε ώστε

μέσω μιας επαναληπτικής εντολής for να αλλάζει η τιμή του i από 0 μέχρι και 3, τότε η όλη

διαδικασία έχει απλουστευτεί κατά πολύ.

Αυτό κάναμε τόσο για να δώσουμε τιμή ακτίνας για καθέναν από τους 4 κύκλους του πίνακα k,

όσο και για να υπολογίσουμε το εμβαδόν καθενός από αυτούς τους κύκλους στη συνέχεια.

Παρατηρείστε ότι αν το k ήταν ένα απλό αντικείμενο, τότε για να καλέσουμε μια συνάρτησή του

θα γράφαμε π.χ. k.set_aktina(ak); ή emb=k.give_embado();

Όμως από τη στιγμή που το k είναι πίνακας, πρέπει να υπάρχουν οι τετράγωνες παρενθέσεις με

έναν αριθμό ανάμεσά τους ή μια μεταβλητή όπως η i της οποίας η τιμή θα μεταβάλλεται. Εδώ

χρησιμοποιήσαμε μια εντολή for για να μεταβάλλουμε την τιμή του i. Προσέξτε ότι το i είναι

ο μετρητής της for.

Επιπλέον, επειδήη εντολή for επαναλαμβάνει περισσότερες από μία εντολές (η 1ηfor

επαναλαμβάνει 3 εντολές, ενώ η 2ηfor επαναλαμβάνει 2 εντολές), πρέπει να περικλείσουμε τις

εντολές αυτές σε άγκιστρα.

επαναληπτικός κύκλος με

χρήση της for

επαναληπτικός κύκλος με

χρήση της for

Page 20: ΤΕΙ ΔΥΤΙΚΗΣ ΜΑΚΕΔΟΝΙΑΣ Program-Ergast...Ασκήσεις εργαστηρίου ... του και τέλος θα εμφανίζει τον αριθμό και

Τ.Ε.Ι. Δυτικής Μακεδονίας Τμήμα Διοίκ. Επιχειρήσεων (Γρεβενά)

Αντικειμενοστρεφής προγραμματισμός με C++ Δρ. Δημ. Συνδουκάς

Σελίδα 20

Άσκηση 12. Δείκτες (pointers) – Δυναμική δέσμευση μνήμης.

Σκοπός της άσκησης είναι να δείξει τη δυναμική δέσμευση και αποδέσμευση μνήμης. Συγκεκριμένα

δεσμεύεται μνήμη για ένα δεδομένο.

Να γράψετε ένα πρόγραμμα:

Στο οποίο να δηλώσετε έναν δείκτη κατάλληλο να «δείξει» σε δεδομένα τύπου κινητής

υποδιαστολής διπλής ακρίβειας

Στη συνέχεια το πρόγραμμα να δεσμεύει μνήμη αρκετή για την αποθήκευση ενός αριθμού

κινητής υποδιαστολής διπλής ακρίβειας, χρησιμοποιώντας τον παραπάνω δείκτη

Έπειτα, να ζητά από τον χρήστη και να διαβάζει έναν δεκαδικό αριθμό και να τον αποθηκεύει στη

δεσμευμένη μνήμη

Τέλος να εμφανίζει στην οθόνη:

o τη διεύθυνση στην οποία «δείχνει» αυτός ο δείκτης, καθώς και

o τον δεκαδικό αριθμό που έχει αποθηκευθεί σ’ αυτή τη μνήμη

Η δεσμευμένη μνήμη να αποδεσμευτεί πριν τελειώσει το πρόγραμμα.

#include <iostream>

using namespace std;

void main() {

double *p;

p = newdouble;

cout << "DOSE ENAN DEKADIKO ARITHMO: ";

cin >> *p;

cout << "STH DIEYTHYNSH: " << p << endl;

cout << "BRISKETAI O ARITHMOS: " << *p << endl;

delete p;

}

Σχόλια:

Οι new και delete είναι τελεστές της C++.

Ο τελεστής new, εδώ δεσμεύει μνήμη για την αποθήκευση ενός κινητής υποδιαστολής διπλής

ακρίβειας αριθμού (πραγματικού).

Θα μπορούσε φυσικά να δεσμεύσει μνήμη για οποιονδήποτε τύπο. Αν για παράδειγμα, ο δείκτης

pείχε δηλωθεί σαν τύπου int, θα μπορούσαμε να δεσμεύσουμε μνήμη αρκετή για την

αποθήκευση ενός ακέραιου γράφοντας την εντολή: p = new int;

Μετά από αυτή τη δέσμευση, ο δείκτης p θα δείχνει στην αρχή του τμήματος μνήμης που

δεσμεύτηκε (γι’ αυτό ονομάζεται «δείκτης»).

Ο τελεστής deleteκάνει ακριβώς το αντίθετο από τον new, δηλαδή αποδεσμεύει,

απελευθερώνει μνήμη που δεσμεύτηκε πριν αλλά τώρα δεν τη χρειαζόμαστε πια.

Για να αποδεσμευτεί η μνήμη, αρκεί να γράψουμε μετά τη λέξη deleteτο όνομα του δείκτη που

χρησιμοποιήσαμε για τη δέσμευσή της, π.χ. delete p;

Προσοχή!! Όταν αποδεσμεύσετε τη μνήμη στην οποία δείχνει ένας δείκτης, τότε δεν μπορείτε να

χρησιμοποιήσετε τον δείκτη αυτό για να αποθηκεύσετε κάποια τιμή στην θέση όπου δείχνει.

Ένας δείκτης έχει 2 «όψεις». Αυτήν με σκέτο το όνομά του (π.χ την p) και αυτήν με ένα αστεράκι

πριν το όνομά του (π.χ. την *p).

o Αυτή με το αστεράκι (π.χ. το *p) μπορείτε να την αντιμετωπίζετε σαν μια συνηθισμένη

μεταβλητή για να αποθηκεύσετε μια τιμή ή να κάνετε πράξεις με αυτή.

Δυναμική δέσμευση μνήμης για

έναν αριθμό τύπου double.

Αποδέσμευση μνήμης, για έναν μόνο αριθμό.

Page 21: ΤΕΙ ΔΥΤΙΚΗΣ ΜΑΚΕΔΟΝΙΑΣ Program-Ergast...Ασκήσεις εργαστηρίου ... του και τέλος θα εμφανίζει τον αριθμό και

Τ.Ε.Ι. Δυτικής Μακεδονίας Τμήμα Διοίκ. Επιχειρήσεων (Γρεβενά)

Αντικειμενοστρεφής προγραμματισμός με C++ Δρ. Δημ. Συνδουκάς

Σελίδα 21

o Αυτή χωρίς το αστεράκι (π.χ. την p) περιέχει την διεύθυνση του 1ουbyte μνήμης όπου δείχνει

ο δείκτης.

o Προσοχή!! Όταν δηλώνουμε έναν δείκτη, πάντα τον δηλώνουμε με ένα αστεράκι πριν το

όνομά του. Μόνο στις εντολές που ακολουθούν τη δήλωσή του μπορούμε να βάλουμε ή να μη

βάλουμε αστεράκι και τότε ο δείκτης αυτός αντιστοιχεί σε διαφορετικά πράγματα, όπως

αναφέρεται στις δύο παραπάνω κουκκίδες.

Ξανακοιτάξτε την πρώτη από τις 2 «όψεις» που αναφέρθηκαν παραπάνω. Εκεί είπαμε ότι

όταν γράφουμε σε εντολές έναν δείκτη με το αστεράκι πριν το όνομά του, τότε αυτός ο

δείκτης ισοδυναμεί με μια απλή μεταβλητή. Έτσι, για παράδειγμα, η εντολή:

*p = 3; θα αποθηκεύσει την τιμή 3 στην θέση μνήμης όπου δείχνει ο p

cin >> *p; θα αποθηκεύσει την τιμή που θα πληκτρολογήσει ο χρήστης στη θέση

μνήμης όπου δείχνει ο p

*p = x + y -5; θα αποθηκεύσει το αποτέλεσμα των πράξεων x + y – 5 στη θέση

μνήμης όπου δείχνει ο p

z = *p / 2; θα διαιρέσει την τιμή που βρίσκεται αποθηκευμένη εκεί όπου δείχνει

ο p δια 2 και το αποτέλεσμα της διαίρεσης θα το αποθηκεύσει στην

απλή μεταβλητή z.

Αυτό σημαίνει ότι ένας δείκτης χρησιμεύει ως αντικαταστάτης μιας απλής μεταβλητής ίδιου

τύπου. Δηλαδή αντί για τον δείκτη p θα μπορούσα να έχω δηλώσει μια απλή μεταβλητή

δεκαδικού απλής ακρίβειας τύπου, όπως φαίνεται παρακάτω:

float *p; floatx;

και έπειτα αντί για τον δείκτη, να χρησιμοποιήσω την απλή μεταβλητή σε πράξεις. Για

παράδειγμα:

*p = a + b/2; x = a + b/2;

Έτσι, αφού δεν θα χρησιμοποιούσα δείκτη, δεν θα χρειαζόμουν και τις εντολές δέσμευσης-

αποδέσμευσης μνήμης new και delete και όλο το πρόγραμμα θα ήταν πιο απλό! Άρα, γιατί

να χρησιμοποιήσω δείκτη (ή δείκτες) σε ένα πρόγραμμά μου και να μην χρησιμοποιήσω

απλές μεταβλητές;

Η απάντηση είναι απλή: Με τις απλές μεταβλητές δεν μπορώ να δεσμεύω και να αποδεσμεύω

μνήμη όποτε θέλω και όση θέλω, ενώ με τους δείκτες μπορώ. Με τους δείκτες λοιπόν, το

πρόγραμμά μου γίνεται πολύ πιο ευέλικτο.

Φυσικά αυτό δεν σημαίνει ότι σε κάθε πρόγραμμά μου πρέπει να χρησιμοποιώ δείκτες «σώνει

και καλά». Μόνο όταν χρειάζεται να δεσμεύσει και να αποδεσμεύσει το πρόγραμμά μου

δυναμικά μνήμη, τότε θα χρησιμοποιώ δείκτες.

Σκέτο το όνομα ενός δείκτη (π.χ. το p) αντιστοιχεί στην διεύθυνση του 1ουbyte μνήμης όπου

δείχνει ο δείκτης αυτός. Τη διεύθυνση αυτή σπάνια μας χρειάζεται να τη χρησιμοποιήσουμε

κάπου, οπότε σπάνια θα χρειαστεί να γράψουμε σε κάποια εντολή σκέτο το όνομα ενός δείκτη.

Εκτός φυσικά από τις εντολές όπου δεσμεύω και αποδεσμεύω μνήμη, όπου δεν χρησιμοποιώ το

αστεράκι.

αντί γι’ αυτό… να γράψω αυτό

αντί γι’ αυτό… να γράψω αυτό

Page 22: ΤΕΙ ΔΥΤΙΚΗΣ ΜΑΚΕΔΟΝΙΑΣ Program-Ergast...Ασκήσεις εργαστηρίου ... του και τέλος θα εμφανίζει τον αριθμό και

Τ.Ε.Ι. Δυτικής Μακεδονίας Τμήμα Διοίκ. Επιχειρήσεων (Γρεβενά)

Αντικειμενοστρεφής προγραμματισμός με C++ Δρ. Δημ. Συνδουκάς

Σελίδα 22

Άσκηση 13. Δείκτες (pointers) – Δυναμική δέσμευση μνήμης.

Σκοπός της άσκησης είναι να δείξει τη δυναμική δέσμευση και αποδέσμευση μνήμης. Συγκεκριμένα

δεσμεύεται μνήμη για τρία δεδομένα και υποδεικνύεται ο τρόπος με τον οποίο προσπελάζεται το κάθε

δεδομένο σ’ αυτό το τμήμα μνήμης.

Να γράψετε ένα πρόγραμμα:

Στο οποίο να δηλώσετε έναν δείκτη κατάλληλο να «δείξει» σε δεδομένα τύπου κινητής

υποδιαστολής διπλής ακρίβειας

Στη συνέχεια το πρόγραμμα να δεσμεύει μνήμη αρκετή για την αποθήκευση τριών αριθμών

κινητής υποδιαστολής διπλής ακρίβειας, χρησιμοποιώντας τον παραπάνω δείκτη

Έπειτα, να ζητά από τον χρήστη και να διαβάζει δύο αριθμούς και να τους αποθηκεύει στις δύο

πρώτες θέσεις της δεσμευμένης μνήμης

Τέλος να προσθέτει τους δύο αριθμούς και να αποθηκεύει το άθροισμα στην τρίτη από τις

δεσμευμένες θέσεις μνήμης. Επιπλέον να εμφανίζει στην οθόνη το άθροισμα με ανάλογο μήνυμα

Η δεσμευμένη μνήμη να αποδεσμευτεί πριν τελειώσει το πρόγραμμα.

#include <iostream>

using namespace std;

void main() {

double *p;

p = newdouble[3];

cout <<"DOSE 2 ARITHMOYS: ";

cin >> *p >> *(p+1);

*(p+2) = *p + *(p+1);

cout <<"TO ATHROISMA EINAI: "<< *(p+2) << endl;

delete [] p;

}

Άσκηση 14. Δείκτες (pointers) – Δυναμική δέσμευση μνήμης.

Σκοπός της άσκησης είναι να δείξει τη δυναμική δέσμευση και αποδέσμευση μνήμης. Συγκεκριμένα

δεσμεύεται μνήμη για πολλά δεδομένα και υποδεικνύεται ο τρόπος με τον οποίο προσπελάζεται το

κάθε δεδομένο σ’ αυτό το τμήμα μνήμης.

Να γράψετε ένα πρόγραμμα:

Στο οποίο να δηλώσετε έναν δείκτη κατάλληλο να «δείξει» σε δεδομένα τύπου κινητής

υποδιαστολής διπλής ακρίβειας

Στη συνέχεια το πρόγραμμα να ρωτήσει τον χρήστη πόσους αριθμούς θέλει να προσθέσει και να

δεσμεύσει μνήμη αρκετή για την αποθήκευσή τους, χρησιμοποιώντας τον παραπάνω δείκτη

Έπειτα, να ζητά επαναληπτικά από τον χρήστη και να διαβάζει τους αριθμούς και να τους

αποθηκεύει σε διαδοχικές θέσεις της δεσμευμένης μνήμης

Τέλος να υπολογίζει το άθροισμά τους σε μια χωριστή μεταβλητή. Επιπλέον να το εμφανίζει στην

οθόνη με ανάλογο μήνυμα

Η δεσμευμένη μνήμη να αποδεσμευτεί πριν τελειώσει το πρόγραμμα.

#include <iostream>

using namespace std;

void main() {

double *p, sum;

int plithos, i;

Δυναμική δέσμευση μνήμης για

τρεις αριθμούς τύπου double.

Αποδέσμευση μνήμης, για πολλούς αριθμούς.

Page 23: ΤΕΙ ΔΥΤΙΚΗΣ ΜΑΚΕΔΟΝΙΑΣ Program-Ergast...Ασκήσεις εργαστηρίου ... του και τέλος θα εμφανίζει τον αριθμό και

Τ.Ε.Ι. Δυτικής Μακεδονίας Τμήμα Διοίκ. Επιχειρήσεων (Γρεβενά)

Αντικειμενοστρεφής προγραμματισμός με C++ Δρ. Δημ. Συνδουκάς

Σελίδα 23

cout <<"POSOYS ARITHMOYS THA DOSEIS? ";

cin >> plithos;

p = newdouble[plithos];

for(i=0; i<plithos; i++) {

cout <<"DOSE TON EPOMENO ARITHMO: ";

cin >> *(p+i);

}

sum = 0;

for(i=0; i<plithos; i++)

sum = sum + *(p+i);

cout <<"TO ATHROISMA EINAI: "<< sum << endl;

delete [] p;

}

Σχόλια:

α) Σε ένα πρόγραμμα όπου γίνεται υπολογισμός του μέσου όρου ενός συνόλου βαθμών με χρήση

πίνακα, θα πρέπει να δηλώσουμε το μέγεθος του πίνακα. Αυτό είναι δεσμευτικό γιατί σημαίνει ότι

όταν τρέχουμε το πρόγραμμα δεν μπορούμε να πληκτρολογήσουμε περισσότερους αριθμούς από

όσους χωρά ο πίνακας.

Ωστόσο, επειδή εδώ δεσμεύουμε όση μνήμη θέλουμε τη στιγμή που τρέχει το πρόγραμμα, δεν

τίθεται περιορισμός στο άνω όριο, δηλαδή πόσους αριθμούς μπορεί να δώσει ο χρήστης. Εφόσον ο

υπολογιστής έχει διαθέσιμη μνήμη, θα την παρέχει, όση κι αν ζητήσουμε.

Βέβαια, αν θέλαμε να ήμασταν πιο σωστοί, θα έπρεπε να ελέγξουμε αν το πλήθος των αριθμών

που θέλει να πληκτρολογήσει ο χρήστης είναι παράλογο (π.χ. δεν μπορώ να πω ότι θα

πληκτρολογήσω 0 ή –5 αριθμούς!)

β) Ο τελεστής new αναλαμβάνει να δεσμεύσει την απαιτούμενη μνήμη για την αποθήκευση των

αριθμών. Η χρήση του είναι ως εξής:

δείκτης = newτύπος_δεδομένων [πλήθος δεδομένων];

Μέσα στις τετράγωνες παρενθέσεις αναφέρουμε το πλήθος των δεδομένων που θα αποθηκεύσουμε

στην μνήμη μας και ο τελεστής new τοποθετεί μέσα στον δείκτη τη διεύθυνση του πρώτου byte της

μνήμης που δεσμεύτηκε. Ο δείκτης λοιπόν θα δείχνει στην αρχή του κομματιού μνήμης που

δεσμεύτηκε. (Κοίτα σχήμα παρακάτω, όπου ο δείκτης ονομάζεται p).

γ) Από κει και πέρα μπορούμε να χρησιμοποιήσουμε τις

δεσμευμένες θέσεις μνήμης μέσω του δείκτη p. Το

μόνο που πρέπει να προσέξουμε είναι να μην

υπερβούμε τα όρια της μνήμης που δεσμεύσαμε. Θα

αποθηκεύσουμε «plithos» αριθμών, άρα το i θα

μεταβάλλεται από το 0 ως και το (plithos-1).

δ) Όταν δεν χρειαζόμαστε ένα κομμάτι μνήμης που

δεσμεύσαμε με τον τελεστή new [], μπορούμε να το

αποδεσμεύσουμε με τον τελεστή delete []. Μετά

από τις παρενθέσεις του delete πρέπει να γράψουμε το όνομα του δείκτη που χρησιμοποιήσαμε

στον new, άρα στην περίπτωσή μας delete [] p.

RAM

p

*(p+3)

*(p+2)

*(p+1)

*p

p+1

p+2

p+3

Δυναμική δέσμευση μνήμης για

“plithos” αριθμούς τύπου double.

Αποδέσμευση μνήμης, για πολλούς αριθμούς.

Page 24: ΤΕΙ ΔΥΤΙΚΗΣ ΜΑΚΕΔΟΝΙΑΣ Program-Ergast...Ασκήσεις εργαστηρίου ... του και τέλος θα εμφανίζει τον αριθμό και

Τ.Ε.Ι. Δυτικής Μακεδονίας Τμήμα Διοίκ. Επιχειρήσεων (Γρεβενά)

Αντικειμενοστρεφής προγραμματισμός με C++ Δρ. Δημ. Συνδουκάς

Σελίδα 24

Άσκηση 15. Δυναμική δέσμευση μνήμης μέσα σε αντικείμενα κλάσεων.

Σκοπός της άσκησης είναι να δείξει πως δεσμεύουμε δυναμικά μνήμη μέσα σε ένα αντικείμενο και

πως αποδεσμεύουμε τη μνήμη αυτή όταν το αντικείμενο καταστρέφεται.

Θέλουμε να δημιουργήσουμε μια κλάση πολύπλευρου. Προσέξτε ότι θέλουμε η κλάση να είναι

«ελαστική», δηλαδή να δημιουργούμε από αυτή αντικείμενα (δηλαδή πολύπλευρα) με οσεσδήποτε

πλευρές θέλουμε κάθε φορά. Δηλαδή ένα πολύπλευρό μας να είναι τετράπλευρο, ένα άλλο να είναι

πεντάπλευρο, κλπ.

Επομένως, για κάθε πολύπλευρό μας θέλουμε να αποθηκεύονται 2 «πράγματα»: πόσες πλευρές έχει το

πολύπλευρο και τα μήκη των πλευρών (κάθε πλευρά θα έχει το δικό της μήκος).

Για παράδειγμα, αν το πολύπλευρο έχει 4 πλευρές θα χρειαστεί να αποθηκεύσουμε 4 μήκη, αν έχει 5

πλευρές θα αποθηκεύσουμε 5 μήκη, κοκ. Καταλαβαίνετε ότι αφού το πλήθος των πλευρών δεν μας

είναι εκ των προτέρων γνωστό θα χρησιμοποιήσουμε δείκτη και δυναμική δέσμευση μνήμης για να

αποθηκεύσουμε τα μήκη των πλευρών.

Επομένως, η κλάση θα έχει 2 μεταβλητές-μέλη (ιδιότητες):

έναν ακέραιο που θα αντιπροσωπεύει τον αριθμό (το πλήθος) των πλευρών του και

από έναν δείκτη τύπου double που θα χρησιμοποιούμε για να αποθηκεύσουμε τα μήκη των

πλευρών (πραγματικοί).

Θέλουμε, όταν δημιουργούμε πολύπλευρα (δηλαδή αντικείμενα της κλάσης), αρχικά αυτά να μην

έχουν καθόλου πλευρές (άρα πλήθος πλευρών ίσο με 0) και φυσικά ο δείκτης της κλάσης να έχει την

τιμή NULL. Φτιάξτε έναν κατασκευαστή (constructor) που να κάνει τα παραπάνω.

Θέλουμε όταν ένα πολύπλευρο (δηλαδή αντικείμενο της κλάσης) διαγράφεται από την μνήμη να

απελευθερώνεται η μνήμη στην οποία δείχνει ο δείκτης της κλάσης. Φτιάξτε έναν καταστροφέα

(destructor) που κάνει αυτό.

Αφού όταν δημιουργούμε ένα νέο αντικείμενο (πολύπλευρο) αυτό δεν έχει αρχικά καθόλου πλευρές,

θα πρέπει να μπορούμε να το αλλάξουμε αυτό μέσα στο πρόγραμμά μας καλώντας μια συνάρτηση-

μέλος της κλάσης.

Δηλαδή, θέλουμε να υπάρχει μια συνάρτηση-μέλος με μια παράμετρο («είσοδο») που να

αντιπροσωπεύει το πλήθος των πλευρών του πολύπλευρου.

Η συνάρτηση αυτή, όταν την καλούμε, θα αλλάζει την τιμή της μεταβλητής-μέλους που καθορίζει

το πλήθος των πλευρών στην τιμή που γράψαμε μέσα στις παρενθέσεις της συνάρτησης.

Επιπλέον, θα δεσμεύει μνήμη για όσες πλευρές χρειάζεται, με τη βοήθεια του δείκτη της κλάσης.

Θέλουμε να μπορούμε να αλλάζουμε το μήκος κάποιας πλευράς του πολύπλευρου, καλώντας μια

συνάρτηση-μέλος της κλάσης. Πως θα το κάνουμε αυτό; Θα «λέμε» στο υπολογιστή: για την πλευρά

«τάδε» κάνε το μήκος «τόσο».

Επομένως, να φτιάξετε μια συνάρτηση-μέλος που να έχει 2 παραμέτρους («εισόδους»). Η μία να είναι

ο αύξοντας αριθμός της πλευράς (δηλαδή ποιας πλευράς θα αλλάξουμε το μήκος;) και η δεύτερη να

είναι το μήκος της πλευράς αυτής. Η συνάρτηση να αλλάζει το μήκος της πλευράς, με τη βοήθεια του

δείκτη της κλάσης.

Θέλουμε να μπορούμε να βρούμε το μήκος της περιμέτρου του πολυπλεύρου μας, δηλαδή το

άθροισμα των μηκών των πλευρών του. Να φτιάξετε μια συνάρτηση-μέλος που να υπολογίζει και να

επιστρέφει το μήκος της περιμέτρου του πολύπλευρου.

Και τώρα θα δοκιμάσετε την κλάση που φτιάξατε, μέσα από ένα πρόγραμμα.

Να γράψετε ένα πρόγραμμα που:

αρχικά να γίνεται δήλωση ενός αντικείμενου της κλάσης πολύπλευρου

να ζητά από τον χρήστη τον αριθμό (πλήθος) των πλευρών ενός πολύπλευρου και να τον

διαβάζει, ώστε να κάνει την ανάλογη ρύθμιση στο παραπάνω αντικείμενο, καλώντας την

ανάλογη συνάρτηση.

να ζητά και να διαβάζει επαναληπτικά τα μήκη των πλευρών (π.χ. της 1ης πλευράς, της 2ης,

κλπ), ώστε να τα αποθηκεύει στο παραπάνω αντικείμενο, με τη βοήθεια της ανάλογης

συνάρτησης-μέλους

να υπολογίζει και να εμφανίζει στην οθόνη την περίμετρο του πολύπλευρου

Page 25: ΤΕΙ ΔΥΤΙΚΗΣ ΜΑΚΕΔΟΝΙΑΣ Program-Ergast...Ασκήσεις εργαστηρίου ... του και τέλος θα εμφανίζει τον αριθμό και

Τ.Ε.Ι. Δυτικής Μακεδονίας Τμήμα Διοίκ. Επιχειρήσεων (Γρεβενά)

Αντικειμενοστρεφής προγραμματισμός με C++ Δρ. Δημ. Συνδουκάς

Σελίδα 25

#include <iostream>

using namespace std;

class polyplevro {

private:

double *mikos;

int plithos_plevron ;

public:

polyplevro();

~polyplevro();

void set_plithos_plevron(int a) ;

void set_mikos(int i, double m);

double give_perimetro();

};

polyplevro::polyplevro() {

mikos = NULL;

plithos_plevron = 0;}

polyplevro::~polyplevro() { delete [] mikos; }

void polyplevro::set_plithos_plevron(int a) {

mikos = newdouble[a];

plithos_plevron = a; }

void polyplevro::set_mikos(int i, double m) {

*(mikos+i) = m; }

double polyplevro::give_perimetro() {

int i;

double per=0;

for(i=0; i<=plithos_plevron-1; i++)

per = per + *(mikos+i);

return per; }

void main() {

polyplevro pol1;

int a, i;

double m, p ;

cout <<"POSES EINAI OI PLEVRES TOY POLYPLEYROY: ";

cin >> a;

pol1.set_plithos_plevron(a);

for(i=0; i<=a-1; i++) {

cout <<"DOSE MHKOS PLEVRAS "<< i <<": ";

cin >> m ;

pol1.set_mikos(i, m);

}

p = pol1.give_perimetro();

cout <<"H PERIMETROS TOY POLYPLEYROY EINAI: "<< p << endl;

}

Στον constructor αρχικοποιούμε τον

δείκτη στην τιμή NULL και τον «αριθμό

πλευρών» στην τιμή 0.

Στον

destructorαπελευθερώνου

με την δεσμευμένη μνήμη.

Στη συνάρτηση

set_plithos_plevron() ορίζουμε πόσες

πλευρές (a) θα έχει το σχήμα και

δεσμεύουμε μνήμη για αυτές.

Στη συνάρτηση set_mikos() ορίζουμε

το μήκος m της πλευράς i.

Στη συνάρτηση give_perimetro() υπολογίζεται και επιστρέφεται η

περίμετρος του σχήματος.

Δήλωση αντικειμένου

Ζητά και διαβάζει το

πλήθος των πλευρών

Ζητά και διαβάζει επαναληπτικά

τα μήκη των πλευρών

Υπολογίζει και

εμφανίζει την περίμετρο

Page 26: ΤΕΙ ΔΥΤΙΚΗΣ ΜΑΚΕΔΟΝΙΑΣ Program-Ergast...Ασκήσεις εργαστηρίου ... του και τέλος θα εμφανίζει τον αριθμό και

Τ.Ε.Ι. Δυτικής Μακεδονίας Τμήμα Διοίκ. Επιχειρήσεων (Γρεβενά)

Αντικειμενοστρεφής προγραμματισμός με C++ Δρ. Δημ. Συνδουκάς

Σελίδα 26

Άσκηση 16. Δυναμική δέσμευση μνήμης για αντικείμενα κλάσεων.

Σκοπός της άσκησης είναι να δείξει πως δημιουργούμε ένα αντικείμενο δεσμεύοντας δυναμικά μνήμη

και πως αποδεσμεύουμε τη μνήμη αυτή όταν δεν τη χρειαζόμαστε.

Να δημιουργήσετε μια κλάση κύκλου, η οποία θα αποτελείται:

από μια μεταβλητή-μέλος (ιδιότητα) που θα αντιπροσωπεύει την ακτίνα του (κινητής

υποδιαστολής διπλής ακρίβειας)

από έναν constructor με μια παράμετρο, η οποία θα καθορίζει την τιμή της ακτίνας. Η

προκαθορισμένη τιμή της ακτίνας να είναι το 1,

έναν destructor, που να εμφανίζει απλώς το μήνυμα ότι ο κύκλος καταστράφηκε

από μια συνάρτηση-μέλος (μέθοδο), με μία παράμετρο, που να αλλάζει την ακτίνα του

κύκλου και να ονομάζεται set_aktina.

από μια συνάρτηση-μέλος (μέθοδο), χωρίς παραμέτρους, που να επιστρέφει το εμβαδόν του

κύκλου (κινητής υποδιαστολής διπλής ακρίβειας) και να ονομάζεται give_embado.

Να γράψετε ένα πρόγραμμα που:

να δημιουργεί ένα νέο αντικείμενο κύκλου (με αρχική τιμή ακτίνας 5) δεσμεύοντας μνήμη.

Να χρησιμοποιήσετε δείκτη τύπου "κλάσης κύκλου".

στη συνέχεια, να ζητά από τον χρήστη μια νέα τιμή για την ακτίνα του κύκλου, να τη διαβάζει

και να καλεί την κατάλληλη συνάρτηση της κλάσης ώστε να την αλλάξει (την ακτίνα) για το

αντικείμενο που δημιούργησε παραπάνω

να υπολογίζει (καλώντας την κατάλληλη συνάρτηση της κλάσης) και να εμφανίζει το

εμβαδόν του κύκλου

να αποδεσμεύει τη δεσμευμένη μνήμη.

#include <iostream>

using namespace std;

class circle {

private:

double aktina;

public:

circle(double a=1);

~circle();

void set_aktina(double a);

double give_embado();

};

circle::circle(double a) {

aktina = a; }

circle::~circle() { cout <<"KATRASTROFH KYKLOY"<< endl; }

void circle::set_aktina(double a) {

aktina = a; }

double circle::give_embado() {

return 3.14*aktina*aktina; }

void main() {

circle *p;

double ak, e;

p = new circle(5);

cout << "DOSE NEA AKTINA KYKLOY (akeraio): ";

cin >> ak;

p->set_aktina(ak);

e = p->give_embado();

cout << "TO EMBADO TOY KYKLOY EINAI: " << e << endl;

delete p;

}

Page 27: ΤΕΙ ΔΥΤΙΚΗΣ ΜΑΚΕΔΟΝΙΑΣ Program-Ergast...Ασκήσεις εργαστηρίου ... του και τέλος θα εμφανίζει τον αριθμό και

Τ.Ε.Ι. Δυτικής Μακεδονίας Τμήμα Διοίκ. Επιχειρήσεων (Γρεβενά)

Αντικειμενοστρεφής προγραμματισμός με C++ Δρ. Δημ. Συνδουκάς

Σελίδα 27

Σχόλια πάνω στους δείκτες:

Στις προηγούμενες ασκήσεις ασχοληθήκαμε με τη δυναμική δέσμευση μνήμης, η οποία γίνεται με τον

τελεστή new και την δυναμική αποδέσμευσή της, η οποία γίνεται με τον τελεστή delete.

Εκτός από τους δύο αυτούς τελεστές, για να δεσμεύσετε / αποδεσμεύσετε δυναμικά μνήμη χρειάζεστε και

έναν δείκτη.

o Ο δείκτης πρέπει να είναι ίδιου τύπου με τα δεδομένα στα οποία θα δείχνει.

o Χρησιμοποιώντας τον τελεστή new, δεσμεύετε όση μνήμη χρειάζεστε και ταυτόχρονα τοποθετείτε

στον δείκτη την διεύθυνση του πρώτου από τα δεσμευμένα bytes της μνήμης. Άρα ο δείκτης θα δείχνει

στην κορυφή (στην αρχή) της δεσμευμένης μνήμης.

Έστω ότι ένας δείκτης, που ονομάζεται p, δείχνει σε κάποια θέση μνήμης. Πως συμβολίζεται το δεδομένο

(π.χ. ο αριθμός) που είναι αποθηκευμένος σ’ αυτή τη θέση μνήμης; Απάντηση: συμβολίζεται με *p.

Όμως, εμείς μπορεί να δεσμεύσαμε τόση μνήμη που να χωρά όχι μόνο ένα, αλλά αρκετά δεδομένα. Ο

δείκτης θα δείχνει στην αρχή της μνήμης, δηλαδή στο πρώτο δεδομένο που είναι αποθηκευμένο εκεί. Ποιος

δείχνει στις επόμενες θέσεις και πως συμβολίζονται τα δεδομένα (π.χ. οι αριθμοί) που βρίσκονται

αποθηκευμένοι εκεί; Απάντηση: Στην πρώτη θέση είπαμε ότι δείχνει ο p, άρα το δεδομένο που είναι

αποθηκευμένο εκεί συμβολίζεται με *p. Στην επόμενη θέση δείχνει ο p+1, άρα το δεδομένο που είναι

αποθηκευμένο εκεί συμβολίζεται με *(p+1), κ.ο.κ. Στην γενική περίπτωση, λοιπόν, σεi θέσεις παρακάτω

από την αρχή της δεσμευμένης μνήμης θα δείχνει ο p+i, άρα το δεδομένο που βρίσκεται εκεί συμβολίζεται

με *(p+i).

Συνήθως, η αποθήκευση δεδομένων στις θέσεις της δεσμευμένης μνήμης γίνεται με τη βοήθεια

επαναληπτικής εντολής. Η ίδια τεχνική με τις επαναλήψεις χρησιμοποιείται και για να χρησιμοποιήσουμε τα

δεδομένα αυτά σε πράξεις (π.χ. για να υπολογίσουμε το άθροισμά τους, αν είναι αριθμοί).

Όπως είδατε, μπορείτε να δεσμεύσετε μνήμη για έναν αριθμό ή για περισσότερους. Η εντολή δέσμευσης

διαφέρει ελαφρώς σε κάθε περίπτωση και παρομοίως διαφέρει και η εντολή αποδέσμευσής της. Δείτε τον

παρακάτω πίνακα, όπου δεσμεύεται μνήμη για έναν πραγματικό (κινητής υποδιαστολής απλής ακρίβειας),

έπειτα για 4 πραγματικούς και έπειτα για n πραγματικούς αριθμούς:

Δέσμευση Αποδέσμευση p = newfloat; delete p;

p = new float[4]; delete [] p;

p = new float[n]; delete [] p;

Για τον παραπάνω πίνακα, υποθέστε ότι ο δείκτης p έχει δηλωθεί με την εντολή: float *p; και το n

είναι μια ακέραια μεταβλητή στην οποία έχουμε αποθηκεύσει κάποια τιμή.

Μπορείτε να δεσμεύσετε μνήμη για την αποθήκευση δομών ή και αντικειμένων που προέρχονται από

κλάσεις. Αν έχουμε να κάνουμε με κλάση, τότε ο τύπος του δείκτη πρέπει να είναι ο ίδιος με τον τύπο του

αντικειμένου στο οποίο θα δείχνει. Άρα, αν θέλουμε έναν δείκτη που να δείχνει σε αντικείμενα της κλάσης

circle, τότε η δήλωση του δείκτη πρέπει να είναι: circle *p;

Η δέσμευση μνήμης για ένα αντικείμενο-κύκλο θα γίνει με την εντολή: p = newcircle;

Εδώ μπορείτε να καθορίσετε και αρχική τιμή ακτίνας γράφοντάς την μέσα σε παρενθέσεις, όπως κάναμε

στην άσκηση. Ενώ η δέσμευση μνήμης για 4 κύκλους θα γίνει με την εντολή: p = newcircle[4];

Εδώ δεν μπορείτε να καθορίσετε αρχική τιμή ακτίνας, άρα είναι απαραίτητο να υπάρχει defaultconstructor.

Όμως, όταν χρειαστεί να καλέσετε μια συνάρτηση της κλάσης circle, θα πρέπει να χρησιμοποιήσετε την

τεχνική με το «βελάκι». Για παράδειγμα, αν η κλάση circle διαθέτει μια συνάρτηση με όνομα

give_embado, ώστε να υπολογίζει το εμβαδόν ενός αντικειμένου-κύκλου, τότε η κλήση αυτής της

συνάρτησης ΔΕΝ θα γίνει με την εντολή:

e = p.give_embado(); (Λάθος)

αλλά με την εντολή:

e = p->give_embado(); (Σωστό)

Εναλλακτικά, μπορεί να χρησιμοποιηθεί και ο συμβολισμός με την τελεία αλλά σε συνδυασμό με το *, όμως

αυτός συνήθως δεν χρησιμοποιείται:

e = (*p).give_embado(); (Επίσης σωστό)

Για τον υπολογισμό του εμβαδού του 4ου κύκλου (αν είχατε δεσμεύσει μνήμη για 4 αντικείμενα-κύκλους) θα

ήταν: e = (p+3)->give_embado();

ενώ στη γενική περίπτωση θα ήταν:

e = (p+i)->give_embado(); όπου το i θα μεταβάλλεται μέσω μιας επαναληπτικής εντολής for.

Page 28: ΤΕΙ ΔΥΤΙΚΗΣ ΜΑΚΕΔΟΝΙΑΣ Program-Ergast...Ασκήσεις εργαστηρίου ... του και τέλος θα εμφανίζει τον αριθμό και

Τ.Ε.Ι. Δυτικής Μακεδονίας Τμήμα Διοίκ. Επιχειρήσεων (Γρεβενά)

Αντικειμενοστρεφής προγραμματισμός με C++ Δρ. Δημ. Συνδουκάς

Σελίδα 28

Άσκηση 17. Υπερφόρτωση τελεστών (operator overloading) μιας κλάσης, με συναρτήσεις-μέλη

της κλάσης.

Σκοπός της άσκησης είναι να δείξει πότε χρειάζεται και πως υπερφορτώνουμε τελεστές. Η

υπερφόρτωση υλοποιείται με συναρτήσεις-μέλη της κλάσης.

Να δημιουργήσετε μια κλάση κύκλου, η οποία θα αποτελείται:

από μια μεταβλητή-μέλος (ιδιότητα) που θα αντιπροσωπεύει την ακτίνα του (κινητής

υποδιαστολής διπλής ακρίβειας)

από έναν constructor με μια παράμετρο, η οποία θα καθορίζει την τιμή της ακτίνας. Η

προκαθορισμένη τιμή της ακτίνας να είναι το 1,

έναν destructor, που να μην κάνει τίποτα. Θα ρωτήσετε: «Να μην κάνει τίποτα; Τότε γιατί να

τον φτιάξουμε;» Και η απάντηση είναι: «Μα για να δείξετε ότι ξέρετε πως φτιάχνουμε έναν

destructor!»

από μια συνάρτηση-μέλος (μέθοδο), χωρίς παραμέτρους, που να επιστρέφει το εμβαδόν του

κύκλου (κινητής υποδιαστολής διπλής ακρίβειας) και να ονομάζεται give_embado.

από μια συνάρτηση υπερφόρτωσης του τελεστή *, η οποία θα αναλαμβάνει να αυξήσει ή

μειώσει την ακτίνα του κύκλου κατά το δεκαδικό ποσοστό που θα καθορίσει ο χρήστης. Π.χ.

με την εντολή: Κύκλος2 = Κύκλος1 * n;

ο Κύκλος2 θα πρέπει να έχει ακτίνα n-πλάσια από τον Κύκλο1.Η συνάρτηση αυτή να είναι

συνάρτηση-μέλος της κλάσης.

από μια συνάρτηση υπερφόρτωσης του τελεστή +, η οποία θα αναλαμβάνει να προσθέσει

τις ακτίνες δύο κύκλων. Π.χ. με την εντολή: Κύκλος3 = Κύκλος1 + Κύκλος2;

ο Κύκλος3 θα πρέπει να έχει ακτίνα ίση με το άθροισμα των ακτίνων του Κύκλος1 και του

Κύκλος2.Η συνάρτηση αυτή να είναι συνάρτηση-μέλος της κλάσης.

Να γράψετε ένα πρόγραμμα που:

να δημιουργεί 3 αντικείμενα της κλάσης κύκλου, το ένα με αρχική τιμή ακτίνας 10, ενώ τα

άλλα δύο χωρίς αρχική τιμή ακτίνας (οπότε θα πάρει την προκαθορισμένη 1)

να υπολογίζει και εμφανίζει το εμβαδόν του 1ου κύκλου.

Έπειτα, να ρωτά τον χρήστη το ποσοστό αύξησης ή μείωσης της ακτίνας και να το διαβάζει

να πολλαπλασιάζει τον 1ο κύκλο επί το ποσοστό αύξησης/μείωσης και να αποθηκεύει το

αποτέλεσμα στον 2ο κύκλο

να υπολογίζει και να εμφανίζει το εμβαδόν του 2ου κύκλου.

να προσθέτει τον 1ο κύκλο με τον 2ο κύκλο και να αποθηκεύει το αποτέλεσμα στον 3ο κύκλο.

να υπολογίζει και να εμφανίζει το εμβαδόν του 3ου κύκλου.

Αν τρέξετε το πρόγραμμα, δίνοντας σαν ποσοστό το 2, θα δείτε στην οθόνη τα παρακάτω:

TO EMBADO TOY 1ou KYKLOY EINAI: 314

POIO EINAI TO POSOSTO AYKSHSHS-MEIOSHS THS AKTINAS? 2

TO EMBADO TOY 2ou KYKLOY EINAI: 1256

TO EMBADO TOY 3ou KYKLOY EINAI: 2826

Πιέστε ένα πλήκτρο για συνέχεια. . .

Page 29: ΤΕΙ ΔΥΤΙΚΗΣ ΜΑΚΕΔΟΝΙΑΣ Program-Ergast...Ασκήσεις εργαστηρίου ... του και τέλος θα εμφανίζει τον αριθμό και

Τ.Ε.Ι. Δυτικής Μακεδονίας Τμήμα Διοίκ. Επιχειρήσεων (Γρεβενά)

Αντικειμενοστρεφής προγραμματισμός με C++ Δρ. Δημ. Συνδουκάς

Σελίδα 29

#include <iostream>

using namespace std;

class circle {

private:

double aktina;

public:

circle(double a=1);

~circle();

double give_embado();

circle operator*(double pososto);

circle operator+(circle c2);

};

circle::circle(double a) {

aktina = a;

}

circle::~circle() { }

double circle::give_embado() {

return 3.14*aktina*aktina;

}

circle circle::operator*(double pososto) {

circle cTemp;

cTemp.aktina = this->aktina * pososto;

return cTemp;

}

circle circle::operator+(circle c2){

circle cTemp;

cTemp.aktina = this->aktina + c2.aktina;

return cTemp;

}

void main() {

circle kyklos1(10); // 1st Circle is being created - radius=10

circle kyklos2, kyklos3; // 2nd and 3rd Circles are being created -

// - no radius, default=1

double e, pos;

e = kyklos1.give_embado();

cout << "TO EMBADO TOY 1ou KYKLOY EINAI: " << e << endl;

cout << "POIO EINAI TO POSOSTO AYKSHSHS-MEIOSHS THS AKTINAS? ";

cin >> pos;

kyklos2 = kyklos1 * pos;

e = kyklos2.give_embado();

cout << "TO EMBADO TOY 2ou KYKLOY EINAI: " << e << endl;

kyklos3 = kyklos1 + kyklos2;

e = kyklos3.give_embado();

cout << "TO EMBADO TOY 3ou KYKLOY EINAI: " << e << endl;

}

Υπερφόρτωση τελεστών *

και +, ως συναρτήσεις της

κλάσης.

constructor

destructor

συνάρτηση της κλάσης

Αναλυτική περιγραφή

των συναρτήσεων

υπερφόρτωσης των

τελεστών * και +.

Και αυτές είναι

συναρτήσεις-μέλη της

κλάσης.

Page 30: ΤΕΙ ΔΥΤΙΚΗΣ ΜΑΚΕΔΟΝΙΑΣ Program-Ergast...Ασκήσεις εργαστηρίου ... του και τέλος θα εμφανίζει τον αριθμό και

Τ.Ε.Ι. Δυτικής Μακεδονίας Τμήμα Διοίκ. Επιχειρήσεων (Γρεβενά)

Αντικειμενοστρεφής προγραμματισμός με C++ Δρ. Δημ. Συνδουκάς

Σελίδα 30

Άσκηση 18. Υπερφόρτωση τελεστών (operatoroverloading) με φιλικές συναρτήσεις (friends) μιας

κλάσης.

Σκοπός της άσκησης είναι να δείξει πότε χρειάζεται και πως υπερφορτώνουμε τελεστές.

Να δημιουργήσετε μια κλάση κύκλου, η οποία θα αποτελείται:

από μια μεταβλητή-μέλος (ιδιότητα) που θα αντιπροσωπεύει την ακτίνα του (κινητής

υποδιαστολής διπλής ακρίβειας)

από έναν constructor με μια παράμετρο, η οποία θα καθορίζει την τιμή της ακτίνας. Η

προκαθορισμένη τιμή της ακτίνας να είναι το 1,

έναν destructor, που να μην κάνει τίποτα. Θα ρωτήσετε: «Να μην κάνει τίποτα; Τότε γιατί να

τον φτιάξουμε;» Και η απάντηση είναι: «Μα για να δείξετε ότι ξέρετε πως φτιάχνουμε έναν

destructor!»

από μια συνάρτηση-μέλος (μέθοδο), χωρίς παραμέτρους, που να επιστρέφει το εμβαδόν του

κύκλου (κινητής υποδιαστολής διπλής ακρίβειας) και να ονομάζεται give_embado.

από μια, φιλική προς την κλάση κύκλου, συνάρτηση υπερφόρτωσης του τελεστή *, η

οποία θα αναλαμβάνει να αυξήσει ή μειώσει την ακτίνα του κύκλου κατά το δεκαδικό

ποσοστό που θα καθορίσει ο χρήστης. Π.χ. με την εντολή: Κύκλος2 = Κύκλος1 * n;

ο Κύκλος2 θα πρέπει να έχει ακτίνα n-πλάσια από τον Κύκλο1.

από μια, φιλική προς την κλάση κύκλου, συνάρτηση υπερφόρτωσης του τελεστή +, η

οποία θα αναλαμβάνει να προσθέσει τις ακτίνες δύο κύκλων. Π.χ. με την εντολή: Κύκλος3 = Κύκλος1 + Κύκλος2;

ο Κύκλος3 θα πρέπει να έχει ακτίνα ίση με το άθροισμα των ακτίνων του Κύκλος1 και του

Κύκλος2.

Να γράψετε ένα πρόγραμμα που:

να δημιουργεί 3 αντικείμενα της κλάσης κύκλου, το ένα με αρχική τιμή ακτίνας 10, ενώ τα

άλλα δύο χωρίς αρχική τιμή ακτίνας (οπότε θα πάρει την προκαθορισμένη 1)

να υπολογίζει και εμφανίζει το εμβαδόν του 1ου κύκλου.

Έπειτα, να ρωτά τον χρήστη το ποσοστό αύξησης ή μείωσης της ακτίνας και να το διαβάζει

να πολλαπλασιάζει τον 1ο κύκλο επί το ποσοστό αύξησης/μείωσης και να αποθηκεύει το

αποτέλεσμα στον 2ο κύκλο

να υπολογίζει και να εμφανίζει το εμβαδόν του 2ου κύκλου.

να προσθέτει τον 1ο κύκλο με τον 2ο κύκλο και να αποθηκεύει το αποτέλεσμα στον 3ο κύκλο.

να υπολογίζει και να εμφανίζει το εμβαδόν του 3ου κύκλου.

Συμπλήρωση:

Αν δοκιμάσετε να αλλάξετε την εντολή πολλαπλασιασμού του αντικειμένου στο κυρίως πρόγραμμα,

ώστε ο πραγματικός αριθμός να είναι αριστερά του συμβόλου *, δηλαδή στο κυρίως πρόγραμμα αντί

για την εντολή: Κύκλος2 = Κύκλος1 * a;

γράψετε την εντολή: Κύκλος2 = a * Κύκλος1;

και ξανατρέξετε το πρόγραμμα, θα δείτε ότι ο compilerδεν θεωρεί αποδεκτή αυτή την πράξη. Τι πρέπει

να κάνετε για να μην υπάρχει το παραπάνω πρόβλημα;

Αν τρέξετε το πρόγραμμα, δίνοντας σαν ποσοστό το 2, θα δείτε στην οθόνη τα παρακάτω:

TO EMBADO TOY 1ou KYKLOY EINAI: 314

POIO EINAI TO POSOSTO AYKSHSHS-MEIOSHS THS AKTINAS? 2

TO EMBADO TOY 2ou KYKLOY EINAI: 1256

TO EMBADO TOY 3ou KYKLOY EINAI: 2826

Πιέστε ένα πλήκτρο για συνέχεια. . .

Page 31: ΤΕΙ ΔΥΤΙΚΗΣ ΜΑΚΕΔΟΝΙΑΣ Program-Ergast...Ασκήσεις εργαστηρίου ... του και τέλος θα εμφανίζει τον αριθμό και

Τ.Ε.Ι. Δυτικής Μακεδονίας Τμήμα Διοίκ. Επιχειρήσεων (Γρεβενά)

Αντικειμενοστρεφής προγραμματισμός με C++ Δρ. Δημ. Συνδουκάς

Σελίδα 31

#include <iostream>

using namespace std;

class circle {

private:

double aktina;

public:

circle(double a=1);

~circle();

double give_embado();

friend circle operator*(circle c1, double pososto);

friend circle operator+(circle c1, circle c2);

};

circle::circle(double a) {

aktina = a;

}

circle::~circle() { }

double circle::give_embado() {

return 3.14*aktina*aktina;

}

circle operator*(circle c1, double pososto) {

circle cTemp;

cTemp.aktina = pososto * c1.aktina;

return cTemp;

}

circle operator+(circle c1, circle c2){

circle cTemp;

cTemp.aktina = c1.aktina + c2.aktina;

return cTemp;

}

void main() {

circle kyklos1(10); // 1st Circle is being created - radius=10

circle kyklos2, kyklos3; // 2nd and 3rd Circles are being created -

// - no radius, default=1

double e, pos;

e = kyklos1.give_embado();

cout <<"TO EMBADO TOY 1ou KYKLOY EINAI: "<< e << endl;

cout <<"POIO EINAI TO POSOSTO AYKSHSHS-MEIOSHS THS AKTINAS? ";

cin >> pos;

kyklos2 = kyklos1 * pos;

e = kyklos2.give_embado();

cout <<"TO EMBADO TOY 2ou KYKLOY EINAI: "<< e << endl;

kyklos3 = kyklos1 + kyklos2;

e = kyklos3.give_embado();

cout <<"TO EMBADO TOY 3ou KYKLOY EINAI: "<< e << endl;

}

Διαβάστε και τη σελίδα 6 στο φυλάδιο 8 σελίδων «Δομές και Κλάσεις στη C++» που δίνονται μαζί

με τις σημειώσεις της θεωρίας.

Υπερφόρτωση τελεστών *

και +, ως φιλικές

συναρτήσεις της κλάσης.

constructor

destructor

συνάρτηση της κλάσης

Αναλυτική περιγραφή

των συναρτήσεων

υπερφόρτωσης των

τελεστών * και +.

Προσοχή: δεν είναι

συναρτήσεις της κλάσης!

Απλώς είναι φίλοι της!

Page 32: ΤΕΙ ΔΥΤΙΚΗΣ ΜΑΚΕΔΟΝΙΑΣ Program-Ergast...Ασκήσεις εργαστηρίου ... του και τέλος θα εμφανίζει τον αριθμό και

Τ.Ε.Ι. Δυτικής Μακεδονίας Τμήμα Διοίκ. Επιχειρήσεων (Γρεβενά)

Αντικειμενοστρεφής προγραμματισμός με C++ Δρ. Δημ. Συνδουκάς

Σελίδα 32

Άσκηση 19. Υπερφόρτωσητελεστών (operatoroverloading) με φιλικές συναρτήσεις (friends) μιας

κλάσης αλλά και με συναρτήσεις που ανήκουν στην κλάση (συναρτήσεις-μέλη).

Σκοπός της άσκησης είναι να δείξει πότε χρειάζεται και πως υπερφορτώνουμε τελεστές.

Να δημιουργήσετε μια κλάση παραλληλογράμμου, η οποία θα αποτελείται:

από δύο μεταβλητές-μέλη (ιδιότητες) που θα αντιπροσωπεύουν το μήκος και το πλάτος του

(κινητής υποδιαστολής διπλής ακρίβειας)

από έναν constructor με δύο παραμέτρους, η οποίες θα καθορίζουν τις τιμές του μήκους και

του πλάτους

από μια συνάρτηση υπερφόρτωσης του τελεστή +, η οποία θα αναλαμβάνει να προσθέσει

τα μήκη δύο παραλληλογράμμων μεταξύ τους και τα πλάτη μεταξύ τους. Π.χ. με την εντολή: Παραλληλόγραμμο3 = Παραλληλόγραμμο1 + Παραλληλόγραμμο2;

το Παραλληλόγραμμο3 θα πρέπει να έχει μήκος ίσο με το άθροισμα των μηκών του

Παραλληλόγραμμο1 και του Παραλληλόγραμμο2. Το ίδιο να ισχύει για το πλάτος.Η

συνάρτηση αυτή να είναι συνάρτηση-μέλος της κλάσης.

από μια συνάρτηση υπερφόρτωσης του τελεστή ==, η οποία θα αναλαμβάνει να συγκρίνει

τα μήκη δύο παραλληλογράμμων μεταξύ τους και τα πλάτη μεταξύ τους. Π.χ. με την εντολή: Παραλληλόγραμμο1 == Παραλληλόγραμμο2

στην περίπτωση που τα μήκη και πλάτη των δύο παραλληλογράμμων είναι ίσα, να επιστρέφει

«αληθές» αλλιώς να επιστρέφει «ψευδές». Η συνάρτηση αυτή να είναι συνάρτηση-μέλος της

κλάσης.

από μια, φιλική προς την κλάση κύκλου, συνάρτηση υπερφόρτωσης του τελεστή >>, η

οποία θα αναλαμβάνει να διαβάσει από το πληκτρολόγιο τις διαστάσεις ενός

παραλληλογράμμου στη μορφή: μήκος x πλάτος. Π.χ.: 3 x 4

από μια, φιλική προς την κλάση κύκλου, συνάρτηση υπερφόρτωσης του τελεστή <<, η

οποία θα αναλαμβάνει να εμφανίσει στην οθόνη τις διαστάσεις ενός παραλληλογράμμου στη

μορφή: μήκος x πλάτος. Π.χ.: 3 x 4

Να γράψετε ένα πρόγραμμα που:

να δημιουργεί 3 αντικείμενα της κλάσης παραλληλογράμμου, όλα με αρχική τιμή μήκους 0

και πλάτους 0.

να ζητά από τον χρήστη να δώσει νέες διαστάσεις για το 1ο και το 2ο παραλληλόγραμμο

να προσθέτει το 1οπαραλληλόγραμμο με το 2οπαραλληλόγραμμο και να αποθηκεύει το

αποτέλεσμα στο 3οπαραλληλόγραμμο.

να εμφανίζει τις διαστάσεις του 3ουπαραλληλόγραμμου στην οθόνη

να συγκρίνει το 1ο παραλληλόγραμμο με το 2ο παραλληλόγραμμο για ισότητα και να

εμφανίζει μήνυμα για το αν είναι ίδια ή όχι

Αν τρέξετε το πρόγραμμα, δίνοντας σαν διαστάσεις των δύο παραλληλογράμμων τα: 2x3 και 4x5, θα

δείτε στην οθόνη τα παρακάτω:

DOSE DIASTASEIS 1ou KAI 2ou PARAL-MOY: 2x3 4x5

DIASTASEIS TOY 3ou PARAL-MOY EINAI: 6x8

TA DYO PARAL-MA DEN EINAI IDIA.

Πιέστε ένα πλήκτρο για συνέχεια. . .

Page 33: ΤΕΙ ΔΥΤΙΚΗΣ ΜΑΚΕΔΟΝΙΑΣ Program-Ergast...Ασκήσεις εργαστηρίου ... του και τέλος θα εμφανίζει τον αριθμό και

Τ.Ε.Ι. Δυτικής Μακεδονίας Τμήμα Διοίκ. Επιχειρήσεων (Γρεβενά)

Αντικειμενοστρεφής προγραμματισμός με C++ Δρ. Δημ. Συνδουκάς

Σελίδα 33

#include <iostream>

using namespace std;

class paral {

private:

double mikos, platos;

public:

paral(double m, double p);

paral operator+(paral p2);

bool operator==(paral p2);

friend istream& operator>>(istream &istr, paral&p);

friend ostream& operator<<(ostream &ostr, paral&p);

};

paral::paral(double m, double p) {

mikos = m; platos = p ;

}

paral paral::operator+(paral p2){

paral pTemp;

pTemp.mikos = this->mikos + p2.mikos;

pTemp.platos = this->platos + p2.platos;

return pTemp;

}

Bool paral::operator==(paral p2){

if((this->mikos == p2.mikos) && (this->platos == p2.platos))

return true;

else

return false;

}

istream& operator>>(istream &istr, paral &p) {

char c;

istr >> p.mikos >> c >> p.platos;

return istr;

}

ostream& operator<<(ostream &ostr, paral &p){

return ostr << p.mikos <<"x" << p.platos;

}

void main() {

paral p1(0,0), p2(0,0), p3(0,0);

cout <<"DOSE DIASTASEIS 1ou KAI 2ou PARAL-MOY: ";

cin >> p1 >> p2;

p3 = p1 + p2;

cout <<"DIASTASEIS TOY 3ou PARAL-MOY EINAI: "<< p3<< endl;

if(p1 == p2)

cout <<"TA DYO PARAL-MA EINAI IDIA."<< endl;

else

cout <<"TA DYO PARAL-MA DEN EINAI IDIA."<< endl;

}

Υπερφόρτωση

τελεστών>> και <<, ως

φιλικές συναρτήσεις της

κλάσης.

constructor

Υπερφόρτωση τελεστών+

και ==, ως συναρτήσεις-

μέλη της κλάσης.

Αναλυτική περιγραφή

των συναρτήσεων

υπερφόρτωσης των

τελεστών + και ==.

Aυτές είναι

συναρτήσεις της

κλάσης.

Αναλυτική περιγραφή

των συναρτήσεων

υπερφόρτωσης των

τελεστών >> και <<.

Aυτές δεν είναι

συναρτήσεις της

κλάσης, αλλά φιλικές

αυτής.

Page 34: ΤΕΙ ΔΥΤΙΚΗΣ ΜΑΚΕΔΟΝΙΑΣ Program-Ergast...Ασκήσεις εργαστηρίου ... του και τέλος θα εμφανίζει τον αριθμό και

Τ.Ε.Ι. Δυτικής Μακεδονίας Τμήμα Διοίκ. Επιχειρήσεων (Γρεβενά)

Αντικειμενοστρεφής προγραμματισμός με C++ Δρ. Δημ. Συνδουκάς

Σελίδα 34

Άσκηση 20. Υπερφόρτωση τελεστών (operator overloading) μιας κλάσης. Συναρτήσεις

προθέματος ++c και επιθέματος c++.

Σκοπός της άσκησης είναι να δείξει πότε χρειάζεται και πως υπερφορτώνουμε τελεστές.

Να δημιουργήσετε μια κλάση κύκλου, η οποία θα αποτελείται:

από μια μεταβλητή-μέλος (ιδιότητα) που θα αντιπροσωπεύει την ακτίνα του (κινητής

υποδιαστολής διπλής ακρίβειας)

από έναν constructor με μια παράμετρο, η οποία θα καθορίζει την τιμή της ακτίνας.

από μια συνάρτηση-μέλος (μέθοδο), χωρίς παραμέτρους, που να επιστρέφει την ακτίνα του

κύκλου (κινητής υποδιαστολής διπλής ακρίβειας) και να ονομάζεται give_aktina.

από μια συνάρτηση υπερφόρτωσης του τελεστή προθέματος ++, η οποία θα αναλαμβάνει

να αυξήσει την ακτίνα ενός κύκλου κατά 1. Π.χ. με την εντολή: Κύκλος2 = ++Κύκλος1;

ο Κύκλος1 θα πρέπει να έχει ακτίνα αυξημένη κατά 1. Την ίδια τιμή ακτίνας πρέπει να έχει

και ο Κύκλος3. Η συνάρτηση αυτή να είναι συνάρτηση-μέλος της κλάσης.

από μια συνάρτηση υπερφόρτωσης του τελεστή επιθέματος ++, η οποία θα αναλαμβάνει

να αυξήσει την ακτίνα ενός κύκλου κατά 1. Π.χ. με την εντολή: Κύκλος 3 = Κύκλος2++;

ο Κύκλος2 θα πρέπει να έχει ακτίνα αυξημένη κατά 1. Όμως ο Κύκλος3 πρέπει να έχει την

τιμή ακτίνας που είχε ο Κύκλος2πριν την αύξηση. Η συνάρτηση αυτή να είναι συνάρτηση-

μέλος της κλάσης.

Να γράψετε ένα πρόγραμμα που:

να δημιουργεί 3 αντικείμενα της κλάσης κύκλου, το ένα με αρχική τιμή ακτίνας 10, το

δεύτερο με αρχική τιμή ακτίνας 10 επίσης, ενώ το τρίτο με αρχική τιμή ακτίνας 0.

να αυξάνει τον 1ο κύκλο κατά 1, με τον τελεστή προθέματος ++, και να αποθηκεύει το

αποτέλεσμα στον 3ο κύκλο.

να εμφανίζει την ακτίνατου 1ου και του 3ου κύκλου.

να αυξάνει τον 2ο κύκλο κατά 1, με τον τελεστή επιθέματος ++, και να αποθηκεύει το

αποτέλεσμα στον 3ο κύκλο.

να εμφανίζει την ακτίνατου 2ου και του 3ου κύκλου.

Αν τρέξετε το πρόγραμμα, θα δείτε στην οθόνη τα παρακάτω:

H AKTINA 1ou KAI TOY 3ou KYKLOY EINAI: 11 11

TO EMBADO TOY 2ou KAI TOY 3ou KYKLOY EINAI: 11 10

Πιέστε ένα πλήκτρο για συνέχεια. . .

Page 35: ΤΕΙ ΔΥΤΙΚΗΣ ΜΑΚΕΔΟΝΙΑΣ Program-Ergast...Ασκήσεις εργαστηρίου ... του και τέλος θα εμφανίζει τον αριθμό και

Τ.Ε.Ι. Δυτικής Μακεδονίας Τμήμα Διοίκ. Επιχειρήσεων (Γρεβενά)

Αντικειμενοστρεφής προγραμματισμός με C++ Δρ. Δημ. Συνδουκάς

Σελίδα 35

#include <iostream>

using namespace std;

class circle {

private:

double aktina;

public:

circle(double a);

double give_aktina();

circle operator++();

circle operator++(int);

};

circle::circle(double a) {

aktina = a;

}

double circle::give_aktina() {

return aktina;

}

circle circle::operator++() {

++this->aktina;

return*this;

}

circle circle::operator++(int){

circle cTemp;

cTemp.aktina = this->aktina;

this->aktina++;

return cTemp;

}

void main() {

circle kyklos1(10), kyklos2(10), kyklos3(0);

double a1, a2, a3;

kyklos3 = ++kyklos1;

a1 = kyklos1.give_aktina();

a3 = kyklos3.give_aktina();

cout <<"H AKTINA 1ou KAI TOY 3ou KYKLOY EINAI:"<< a1 << a3 << endl;

kyklos3 = kyklos2++;

a2 = kyklos2.give_aktina();

a3 = kyklos3.give_aktina();

cout <<"H AKTINA 2ou KAI TOY 3ou KYKLOY EINAI:"<< a2 << a3 << endl;

}

Υπερφόρτωση τελεστών προθέματος++ και

επιθέματος++, ως συναρτήσεις

της κλάσης.

constructor

συνάρτηση της κλάσης

Αναλυτική περιγραφή

των συναρτήσεων

υπερφόρτωσης των

τελεστών προθέματος++

και επιθέματος++.

Αυτές είναι

συναρτήσεις της

κλάσης.

Χρήση του τελεστήπροθέματος++

Χρήση του τελεστήεπιθέματος++

Page 36: ΤΕΙ ΔΥΤΙΚΗΣ ΜΑΚΕΔΟΝΙΑΣ Program-Ergast...Ασκήσεις εργαστηρίου ... του και τέλος θα εμφανίζει τον αριθμό και

Τ.Ε.Ι. Δυτικής Μακεδονίας Τμήμα Διοίκ. Επιχειρήσεων (Γρεβενά)

Αντικειμενοστρεφής προγραμματισμός με C++ Δρ. Δημ. Συνδουκάς

Σελίδα 36

Άσκηση 21. Χειρισμός ακολουθιών χαρακτήρων (string).

Σκοπός της άσκησης είναι να δείξει πως χειριζόμαστε τις ακολουθίες χαρακτήρων στην C++.

α) Γράψτε ένα πρόγραμμα, το οποίο να ζητά από τον χρήστη να δώσει το όνομά του, το οποίο

ακολούθως θα διαβάζει ο υπολογιστής και θα τοποθετεί σε ένα αντικείμενο τύπου string. Στη

συνέχεια θα ζητάει και το επώνυμό του, το οποίο θα τοποθετεί σε άλλο αντικείμενο.

β) Το όνομα και το επώνυμο να συγκριθούν και να εμφανιστεί ανάλογο μήνυμα αν είναι ίδια ή όχι.

γ) Το όνομα και το επώνυμο να συγκριθούν και να εμφανιστεί ανάλογο μήνυμα αν έχουν ίσα μήκη ή

όχι.

δ) Το όνομα και το επώνυμο να συνενωθούνμέσα σε ένα καινούργιο τρίτο αντικείμενο με ένα κενό

ανάμεσά τους και το συνενωμένο ονοματεπώνυμο να εμφανιστεί στην οθόνη.

ε) Να υπολογιστεί το μήκος του ονοματεπώνυμου (δηλαδή πόσους χαρακτήρες περιέχει) και να

εμφανιστεί ο αριθμός αυτός στην οθόνη, με μήνυμα.

στ) Να εμφανιστεί το ονοματεπώνυμο στην οθόνη γραμμένο αντίστροφα.

#include <iostream>

#include <string>

using namespace std;

void main() {

string onoma, epon, onep;

int mikos, i;

cout <<"DOSE TO ONOMA SOU: ";

cin >> onoma; // getline(cin, onoma);

cout <<"DOSE TO EPONYMO SOU: ";

cin >> epon; // getline(cin, epon);

if(onoma == epon)

cout <<"TO ONOMA KAI TO EPONYMO EINAI IDIA"<< endl;

else

cout <<"TO ONOMA KAI TO EPONYMO DEN EINAI IDIA"<< endl;

if(onoma.length() == epon.length())

cout <<"TO ONOMA KAI TO EPONYMO EXOYN ISO MHKOS"<< endl;

else

cout <<"TO ONOMA KAI TO EPONYMO DEN EXOYN ISO MHKOS"<< endl;

onep = onoma + ' ' + epon;

cout <<"TO ONOMATEPONYMO EINAI: "<< onep << endl;

mikos = onep.length();

cout <<"TO ONOM/MO SOU EXEI "<< mikos <<" GRAMMATA"<< endl;

for(i=onep.length()-1; i>=0; i--)

cout << onep[i];

}

(α)

(β)

(γ)

(δ)

(ε)

(στ)

Χρειάζεται και την κατάλληλη #include!

Η κλάση string υπάρχει έτοιμη! Εμείς

απλώς δηλώνουμε αντικείμενά της.

Page 37: ΤΕΙ ΔΥΤΙΚΗΣ ΜΑΚΕΔΟΝΙΑΣ Program-Ergast...Ασκήσεις εργαστηρίου ... του και τέλος θα εμφανίζει τον αριθμό και

Τ.Ε.Ι. Δυτικής Μακεδονίας Τμήμα Διοίκ. Επιχειρήσεων (Γρεβενά)

Αντικειμενοστρεφής προγραμματισμός με C++ Δρ. Δημ. Συνδουκάς

Σελίδα 37

Παρατηρήσεις:

1. Στην C++ υπάρχει μια ενσωματωμένη κλάση που ονομάζεται string και μπορεί να

χρησιμοποιηθεί για να αποθηκεύουμε ακολουθίες χαρακτήρων. Στην C θα χρησιμοποιούσαμε

πίνακες χαρακτήρων, κάτι που μπορούμε βέβαια να κάνουμε και στη C++. Απλώς η χρήση της

string μας διευκολύνει. Για τη χρήση της απαιτείται η εντολή: #include<string>.

Γιατί μας διευκολύνει; Γιατί δεν μας απασχολεί το μέγεθος της ακολουθίας χαρακτήρων – δεν

χρειάζεται να δηλώσουμε μέγεθος για το string. Όταν θέλουμε να συνενώσουμε 2 ή περισσότερα

string και μαζί τους ίσως να συνενώσουμε και χαρακτήρες, τότε το κάνουμε με το σύμβολο της

πρόσθεσης +. Όταν θέλουμε να συγκρίνουμε δύο string για να δούμε αν είναι ίδια, χρησιμοποιούμε

τον τελεστή == ή για έλεγχο ανισότητας τον !=. Είναι δυνατό να συγκρίνουμε και για >, >=, <,

<=, οπότε και θα γίνει λεξικογραφική σύγκριση.

2. Για να διαβάσει ο υπολογιστής μια ακολουθία χαρακτήρων από το πληκτρολόγιο και να την

αποθηκεύσει σε ένα αντικείμενο τύπου string μπορούμε να χρησιμοποιήσουμε κανονικά την cin.

Ωστόσο, αν η ακολουθία χαρακτήρων περιέχει ένα ή περισσότερα κενά η cin θα διαβάσει μόνο

μέχρι το πρώτο κενό και όχι μέχρι το τέλος της ακολουθίας. Για να διαβάσει ο υπολογιστής

ολόκληρη την πρόταση που θα πληκτρολογήσουμε, χρησιμοποιούμε την εντολή getline(cin,

x), όπου x είναι έναν αντικείμενο τύπου string.

3. Το μήκος της λέξης που περιέχει ένα string παίρνουμε αν γράψουμε δίπλα από το string το:

.length(). Έτσι για να πάρουμε το μήκος του onoma γράφουμε: onoma.length().

Παρόμοια έχουμε για το επώνυμο και για το ονοματεπώνυμο: epon.length() και

onep.length().

4. Στο βήμα (στ) το να εμφανιστεί αντίστροφα το ονοματεπώνυμο, δηλαδή από το τελευταίο γράμμα

προς το πρώτο, δεν γίνεται με μια απλή εντολή. Γι’ αυτό χρησιμοποιούμε μια εντολή for η οποία

θα εμφανίσει ένα-ένα τα γράμματα (και όχι όλο το ονοματεπώνυμο μαζί). Σε ποια θέση όμως

βρίσκεται το τελευταίο γράμμα του ονοματεπώνυμου; Αν το μήκος του ονοματεπώνυμου είναι

onep.length(), τότε το τελευταίο γράμμα θα είναι μια θέση πιο πίσω, δηλαδή στην

onep.length()-1. Αυτό συμβαίνει γιατί οι θέσεις των γραμμάτων σε ένα string αριθμούνται

ξεκινώντας από το 0 και όχι από το 1. Δείτε το παρακάτω παράδειγμα.

Στο παραπάνω string το μήκος είναι 7 (3 για το «ΕΝΑ» + 3 για το «ΔΥΟ» + 1 κενό). Αν αρχίζαμε

να εμφανίζουμε τα γράμματα ξεκινώντας από την θέση 7, τότε θα ξεφεύγαμε κατά μια θέση

δεξιότερα απ’ ότι το τέλος του string. Έτσι στην εντολή for που εμφανίζει αντίστροφα τα

γράμματα βάζουμε τον μετρητή να αρχίζει από τη θέση onep.length()-1.

5. Όταν θέλετε να αποκτήστε πρόσβαση σε μεμονωμένους χαρακτήρες ενός string, τότε

χρησιμοποιήστε το σαν να ήταν πίνακας. Έτσι ο πρώτος χαρακτήρας του ονοματεπώνυμου είναι ο

onep[0], ο δεύτερος είναι ο onep[1], κλπ. Γενικώς θα έχουμε onep[i]. Εναλλακτικά,

μπορούμε να γράψουμε onep.at(i).

Ε Ν Α Δ Υ Ο

0 1 2 3 4 5 6 7 8

Page 38: ΤΕΙ ΔΥΤΙΚΗΣ ΜΑΚΕΔΟΝΙΑΣ Program-Ergast...Ασκήσεις εργαστηρίου ... του και τέλος θα εμφανίζει τον αριθμό και

Τ.Ε.Ι. Δυτικής Μακεδονίας Τμήμα Διοίκ. Επιχειρήσεων (Γρεβενά)

Αντικειμενοστρεφής προγραμματισμός με C++ Δρ. Δημ. Συνδουκάς

Σελίδα 38

Άσκηση 22. Εικονικές (virtual) συναρτήσεις και αμιγώς εικονικές (pure virtual) συναρτήσεις –

Αφηρημένες (abstract) κλάσεις.

Σκοπός της άσκησης είναι να δείξει πως μπορούμε να χρησιμοποιήσουμε τις εικονικές συναρτήσεις.

Να δημιουργήσετε μια κλάση, η οποία να αντιπροσωπεύει γενικώς ένα όχημα. Συγκεκριμένα:

να μην περιέχει μεταβλητές-μέλη (member-variables) ή ιδιότητες (attributes),

να περιέχει 1 συνάρτηση-μέλος (member-function) ή μέθοδο (method) με όνομα print που να

εμφανίζει στην οθόνη τη λέξη: OXHMA, μόνο. Να μην επιστρέφει τίποτα.Να είναι εικονική.

Να δημιουργήσετε μια κλάση, η οποία να αντιπροσωπεύει ένααυτοκίνητο, και να είναι απόγονος της

κλάσης όχημα. Συγκεκριμένα:

να περιέχει μία μεταβλητή-μέλος (member-variable) ή ιδιότητα (attribute), η οποία να

αντιπροσωπεύει τονκυβισμό του αυτοκινήτου

να περιέχει 2 συναρτήσεις-μέλη (member-functions) ή μεθόδους (methods) που να ενεργούν

πάνω στις μεταβλητές του:

o έναν κατασκευαστή (constructor) μια που δέχεται σαν «είσοδό του» (παράμετρο) μια τιμή, η

οποία να καθορίζει τονκυβισμό.

o μια συνάρτηση με όνομα print που να εμφανίζει κατευθείαντονκυβισμό του αυτοκινήτου

στη μορφή: ΚΥΒΙΣΜΟΣ: 1800 Να μην επιστρέφει τίποτα.

Να δημιουργήσετε μια κλάση, η οποία να αντιπροσωπεύει ένα σπορ αυτοκίνητο, και να είναι

απόγονος της κλάσης όχημα. Συγκεκριμένα:

να περιέχει μιαμεταβλητή-μέλος (member-variable) ή ιδιότητα (attribute), ηοποία θα

αντιπροσωπεύειτην ιπποδύναμή του

να περιέχει 2 συναρτήσεις-μέλη (member-functions) ή μεθόδους (methods) που να ενεργούν

πάνω στις μεταβλητές του:

o έναν κατασκευαστή (constructor) μια που δέχεται σαν «είσοδό του» (παράμετρο) μία τιμή,

που θα καθορίζει την ιπποδύναμή του.

o μια συνάρτηση με όνομα print που να εμφανίζει κατευθείαντην ιπποδύναμη του σπορ

αυτοκινήτου στη μορφή: IPODYNAMH: 120 Να μην επιστρέφει τίποτα.

Στη συνέχεια, να γράψετε ένα πρόγραμμα, στο οποίο:

Να δηλώσετε 2 αντικείμενα της κλάσης αυτοκίνητο, με αρχικές τιμές κυβισμού 1800 και 1600,

αντίστοιχα.

Να δηλώσετε 2 αντικείμενα της κλάσης σπορ αυτοκίνητο, με αρχικές τιμές ιπποδύναμης 120 και

180 αντίστοιχα.

Να δηλώσετε έναν πίνακα δεικτών του τύπου όχημα, με 4 θέσεις.

Κατόπιν, να αποθηκεύσετε στις θέσεις 0 έως 3 του παραπάνω πίνακα τις διευθύνσεις των 2

αυτοκινήτων και των 2 σπορ αυτοκινήτων που δηλώσατε παραπάνω.

Έπειτα, χρησιμοποιώντας μια εντολή επανάληψης, να καλέσετε τη συνάρτηση print και για τα 4

αντικείμενα των οποίων τις διευθύνσεις περιέχει ο πίνακας δεικτών, ώστε να εμφανιστούν οι

κυβισμοί (για τα αυτοκίνητα) και οι ιπποδυνάμεις τους (για τα σπορ αυτοκίνητα).

Αν τρέξετε το πρόγραμμα, θα δείτε στην οθόνη τα παρακάτω:

KYBISMOS: 1200

KYBISMOS: 1600

IPODYNAMI: 120

IPODYNAMI: 160

Πιέστε ένα πλήκτρο για συνέχεια. . .

Page 39: ΤΕΙ ΔΥΤΙΚΗΣ ΜΑΚΕΔΟΝΙΑΣ Program-Ergast...Ασκήσεις εργαστηρίου ... του και τέλος θα εμφανίζει τον αριθμό και

Τ.Ε.Ι. Δυτικής Μακεδονίας Τμήμα Διοίκ. Επιχειρήσεων (Γρεβενά)

Αντικειμενοστρεφής προγραμματισμός με C++ Δρ. Δημ. Συνδουκάς

Σελίδα 39

#include <iostream>

using namespace std;

class oxima {

public:

virtual void print(); // virtualvoid print()=0;

};

void oxima::print(){

cout << "OXHMA" << endl;

}

class car:public oxima{

private:

int kybismos;

public:

car(int k);

void print();

};

car::car(int k) {

kybismos = k;

}

void car::print() {

cout << "KYBISMOS: " << kybismos << endl;

}

class spor_car:public oxima {

private:

int ipodynami;

public:

spor_car(int i);

void print();

};

spor_car::spor_car(int i) {

ipodynami = i;

}

void spor_car::print() {

cout << "IPODYNAMI: " << ipodynami << endl;

}

void main() {

car c1(1200), c2(1600);

spor_car s1(120), s2(160);

oxima *p[4];

p[0] = &c1;

p[1] = &c2;

p[2] = &s1;

p[3] = &s2;

for(int i=0; i<4; i++)

p[i]->print();

}

Τι εμφανίζεται στην οθόνη, αν δεν είναι virtual η συνάρτηση;

Τι σημαίνει η δήλωση της συνάρτησης

σαν «αμιγώς εικονικής» (pure virtual):

(α) για την συνάρτηση;

(β) για την κλάση;

Και πως ονομάζεται τότε η κλάση;

Αν η συνάρτηση print() δεν είναι virtual, τότε

καλείται η συνάρτηση print()της κλάσης του

δείκτη, δηλαδή της κλάσης oxima.

Αν όμως η συνάρτηση print()είναιvirtual, τότε

καλείται κάθε φορά η συνάρτηση print()της

κλάσης του αντικειμένου στο οποίο δείχνει ο

δείκτης, δηλαδή της κλάσης car ή της spor_car.

Ο δείκτης p δείχνει σε αντικείμενα

των κλάσεων car καιspor_car,

δηλαδή των απογόνων του.

Χρειάζεται υλοποίηση

αυτής της συνάρτησης;

Μπορούμε να δηλώσουμε

αντικείμενα αυτής της

κλάσης;

Page 40: ΤΕΙ ΔΥΤΙΚΗΣ ΜΑΚΕΔΟΝΙΑΣ Program-Ergast...Ασκήσεις εργαστηρίου ... του και τέλος θα εμφανίζει τον αριθμό και

Τ.Ε.Ι. Δυτικής Μακεδονίας Τμήμα Διοίκ. Επιχειρήσεων (Γρεβενά)

Αντικειμενοστρεφής προγραμματισμός με C++ Δρ. Δημ. Συνδουκάς

Σελίδα 40

Άσκηση 23. Χειρισμός εξαιρέσεων (exception handling).

Σκοπός της άσκησης είναι να δείξει πως χειριζόμαστε τις εξαιρέσεις (exceptions) στην C++.

Μεταβίβαση αριθμού μέσω της εξαίρεσης.

Να γράψτε ένα πρόγραμμα, το οποίο:

Να ζητά από τον χρήστη να δώσει δύο πραγματικούς αριθμούς, τους οποίους θα διαβάζει και θα

αποθηκεύει σε αντίστοιχες μεταβλητές.

Στη συνέχεια, το πρόγραμμα να διαιρεί τους αριθμούς αυτούς και να εμφανίζει το πηλίκο τους με

ανάλογο μήνυμα.

Να προσθέσετε έλεγχο του διαιρέτη, ώστε αν βρεθεί ίσος με το μηδέν, το πρόγραμμά σας να

«ρίχνει» (throw) μια εξαίρεση (exception).

o Η εξαίρεση αυτή να μεταβιβάζει τον διαιρέτη, δηλαδή έναν πραγματικό αριθμό.

Το πρόγραμμά σας να συλλαμβάνει (catch) την εξαίρεση αυτή και τότε να εμφανίζει το μήνυμα:

LATHOS: Epixeireite diairesi me to: και δίπλα να εμφανίζεται ο διαιρέτης

(δηλαδή το μηδέν).

Να προσθέσετε και ένα ακόμη τμήμα σύλληψης που να συλλαμβάνει όλα τα αντικείμενα

εξαίρεσης που δεν συλλαμβάνονται από το παραπάνω catch. Αυτό το τμήμα σύλληψης να

εμφανίζει στην οθόνη το μήνυμα: AGNOSTH EKSAIRESH!

#include <iostream>

using namespace std;

void main() {

double diaireteos, diairetis, piliko;

cout << "DOSE DIAIRETEO: ";

cin >> diaireteos;

cout << "DOSE DIAIRETH: ";

cin >> diairetis;

try

{

if(diairetis == 0)

throw diairetis ;

piliko = diaireteos / diairetis;

cout << "TO PHLIKO EINAI: " << piliko << endl;

}

catch(double d)

{

cout << "LATHOS: Epixeireite diairesi me to:" << d << endl;

}

catch (...)

{

cout << "AGNOSTH EKSAIRESH!" << endl;

}

}

Page 41: ΤΕΙ ΔΥΤΙΚΗΣ ΜΑΚΕΔΟΝΙΑΣ Program-Ergast...Ασκήσεις εργαστηρίου ... του και τέλος θα εμφανίζει τον αριθμό και

Τ.Ε.Ι. Δυτικής Μακεδονίας Τμήμα Διοίκ. Επιχειρήσεων (Γρεβενά)

Αντικειμενοστρεφής προγραμματισμός με C++ Δρ. Δημ. Συνδουκάς

Σελίδα 41

Άσκηση 24. Χειρισμός εξαιρέσεων (exception handling).

Σκοπός της άσκησης είναι να δείξει πως χειριζόμαστε τις εξαιρέσεις (exceptions) στην C++.

Μεταβίβαση αντικειμένου κλάσης μέσω της εξαίρεσης.

Να γράψτε ένα πρόγραμμα, το οποίο:

Να ζητά από τον χρήστη να δώσει δύο πραγματικούς αριθμούς, τους οποίους θα διαβάζει και θα

αποθηκεύει σε αντίστοιχες μεταβλητές.

Στη συνέχεια, το πρόγραμμα να διαιρεί τους αριθμούς αυτούς και να εμφανίζει το πηλίκο τους με

ανάλογο μήνυμα.

Να προσθέσετε έλεγχο του διαιρέτη, ώστε αν βρεθεί ίσος με το μηδέν, το πρόγραμμά σας να

«ρίχνει» (throw) μια εξαίρεση (exception).

o Η εξαίρεση αυτή να είναι ένα αντικείμενο μιας κλάσης εξαίρεσης που να ονομάζεται

DivideByZero, την οποία θα δημιουργήσετε εσείς. Η κλάση αυτή να είναι στοιχειώδης,

δηλαδή χωρίς μεταβλητές και συναρτήσεις.

Το πρόγραμμά σας να συλλαμβάνει (catch) την εξαίρεση αυτή και τότε να εμφανίζει το μήνυμα:

“LATHOS: Diairesimetomiden!”

Να τροποποιήσετε την κλάση ώστε να μεταβιβάζεται ο διαιρέτης κατά την εξαίρεση.

Σημείωση: Οι τροποποιήσεις φαίνονται παρακάτω μέσα σε πλαίσια.

#include <iostream>

using namespace std;

class DivideByZero

{ };

void main() {

double diaireteos, diairetis, piliko;

cout << "DOSE DIAIRETEO: ";

cin >> diaireteos;

cout << "DOSE DIAIRETH: ";

cin >> diairetis;

try

{

if(diairetis == 0)

throw DivideByZero() ;

piliko = diaireteos / diairetis;

cout << "TO PHLIKO EINAI: " << piliko << endl;

}

catch(DivideByZero)

{

cout << "LATHOS: Diairesi me to miden!" << endl;

}

}

class DivideByZero {

public:

double div;

DivideByZero(double d) {

div = d;

}

};

throw DivideByZero(diairetis) ;

catch(DivideByZero antik)

{

cout << "LATHOS: Epixeireite diairesi me to: " << antik.div << endl;

}

Page 42: ΤΕΙ ΔΥΤΙΚΗΣ ΜΑΚΕΔΟΝΙΑΣ Program-Ergast...Ασκήσεις εργαστηρίου ... του και τέλος θα εμφανίζει τον αριθμό και

Τ.Ε.Ι. Δυτικής Μακεδονίας Τμήμα Διοίκ. Επιχειρήσεων (Γρεβενά)

Αντικειμενοστρεφής προγραμματισμός με C++ Δρ. Δημ. Συνδουκάς

Σελίδα 42

Άσκηση 25. Χώροι ονομάτων (namespaces).

Σκοπός της άσκησης είναι να δείξει πως δημιουργούμε χώρους ονομάτων (namespaces) και πως

μπορούμε να χρησιμοποιήσουμε συστατικά τους σε ένα πρόγραμμα, στη συνέχεια.

Να ορίσετε δύο χώρους ονομάτων. Συγκεκριμένα:

Να περιέχει έναν χώρο ονομάτων με όνομα: mikri_akribeia και να περιέχει:

o Μια μεταβλητή με όνομα pi η οποία να συμβολίζει το γνωστό από τα μαθηματικά π και να

ισούται με 3,14

o Μια συνάρτηση που να ονομάζεται embado και η οποία να υπολογίζει και επιστρέφει το

εμβαδόν ενός κύκλου. Η συνάρτηση να έχει μια παράμετρο που να αντιστοιχεί στην ακτίνα

του κύκλου.

Να περιέχει έναν χώρο ονομάτων με όνομα: megali_akribeia και να περιέχει:

o Μια μεταβλητή με όνομα pi η οποία να συμβολίζει το γνωστό π και να ισούται με

3,141592653589

o Μια συνάρτηση που να ονομάζεται embado και η οποία να υπολογίζει και επιστρέφει το

εμβαδόν ενός κύκλου. Η συνάρτηση να έχει μια παράμετρο που να αντιστοιχεί στην ακτίνα

του κύκλου.

Στη συνέχεια, να γράψτε ένα πρόγραμμα, το οποίο:

Να ζητά από τον χρήστη να δώσει την ακτίνα ενός κύκλου, να τη διαβάζει και αποθηκεύει σε

μεταβλητή.

Να καλεί την συνάρτηση υπολογισμού εμβαδού του χώρου ονομάτων mikri_akribeia, για να

υπολογίσει το εμβαδόν του κύκλου. Έπειτα να το εμφανίζει στην οθόνη με κατάλληλο μήνυμα.

Να καλεί την συνάρτηση υπολογισμού εμβαδού του χώρου ονομάτων megali_akribeia, για

να υπολογίσει το εμβαδόν του κύκλου. Έπειτα να το εμφανίζει στην οθόνη με κατάλληλο μήνυμα.

Σημείωση: να μην χρησιμοποιήσετε την εντολή using για τους 2 παραπάνω χώρους ονομάτων.

#include<iostream>

usingnamespacestd;

namespacemikri_akribeia {

double pi = 3.14;

double embado(doublea) {

return pi*a*a;

}

}

namespace megali_akribeia {

double pi = 3.141592653589;

double embado(double a) {

return pi*a*a;

}

}

void main() {

double aktina, emb;

cout <<"DOSE AKTINA KYKLOY: ";

cin >> aktina;

emb = mikri_akribeia::embado(aktina);

cout <<"TO EMBADO (me mikri akribeia) EINAI: "<< emb << endl;

emb = megali_akribeia::embado(aktina);

cout <<"TO EMBADO (me megali akribeia)EINAI: "<< emb << endl;

}

Page 43: ΤΕΙ ΔΥΤΙΚΗΣ ΜΑΚΕΔΟΝΙΑΣ Program-Ergast...Ασκήσεις εργαστηρίου ... του και τέλος θα εμφανίζει τον αριθμό και

Τ.Ε.Ι. Δυτικής Μακεδονίας Τμήμα Διοίκ. Επιχειρήσεων (Γρεβενά)

Αντικειμενοστρεφής προγραμματισμός με C++ Δρ. Δημ. Συνδουκάς

Σελίδα 43

Άσκηση 26. Αρχεία κειμένου (text files).

Σκοπός της άσκησης είναι να δείξει πως μπορούμε να διαβάσουμε και να γράψουμε μέσα σε αρχεία

τύπου κειμένου (text) με ένα πρόγραμμα.

Προετοιμασία:

Κάντε διπλό κλικ στο εικονίδιο «Υπολογιστής» στην επιφάνεια εργασίας του

υπολογιστή σας.

Πηγαίνετε στον δίσκο C: και κάνετε διπλό κλικ για να τον

ανοίξετε.

Με δεξί κλικ μέσα στο παράθυρο του

C: επιλέξτε από το μενού που θα

ανοίξει: Δημιουργία > Έγγραφο

κειμένου. Ονομάστε το αρχείο αυτό:

input.txt

Κάντε διπλό κλικ για να ανοίξει το αρχείο αυτό και

πληκτρολογήστε μέσα του τους αριθμούς: 1 2 3 4 5 σε

διαφορετικές γραμμές. Κατόπιν αποθηκεύστε και κλείστε το

αρχείο.

Στη συνέχεια, να γράψτε ένα πρόγραμμα, το οποίο:

Να ανοίγει το αρχείοκειμένου input.txt για ανάγνωση.

Να ανοίγειένα νέοαρχείοκειμένου output.txt για εγγραφή.

Κατόπιν, να κάνει επαναληπτικά, και μέχρι να φτάσει στο τέλος του αρχείου input.txt, τα

εξής:

o Να διαβάζει από το αρχείο input.txt έναν αριθμό κάθε φορά

o Να υπολογίζει το τετράγωνό του

o Να αποθηκεύει στο αρχείο output.txt τον αριθμό και δίπλα το τετράγωνό του, με:

ελάχιστο εύρος 8 θέσεις, δεξιά στοίχιση, κανονικό τρόπο (fixed) και 2 δεκαδικά ψηφία.

Να κλείνει και τα δύο αρχεία κειμένου που άνοιξε παραπάνω (έξω από τον κύκλο επανάληψης).

Σαν τελευταία εντολή του προγράμματος (έξω από τον κύκλο επανάληψης) να εμφανίζεται στην

οθόνη το μήνυμα: TOPROGRAMMATELEIOSE.

Αφού τρέξει το πρόγραμμα, να ελέγξτε αν δημιούργησε το

αρχείο output.txt και αν μέσα του αποθήκευσε κάθε

αριθμό του αρχείου input.txt και δίπλα το τετράγωνό του.

Page 44: ΤΕΙ ΔΥΤΙΚΗΣ ΜΑΚΕΔΟΝΙΑΣ Program-Ergast...Ασκήσεις εργαστηρίου ... του και τέλος θα εμφανίζει τον αριθμό και

Τ.Ε.Ι. Δυτικής Μακεδονίας Τμήμα Διοίκ. Επιχειρήσεων (Γρεβενά)

Αντικειμενοστρεφής προγραμματισμός με C++ Δρ. Δημ. Συνδουκάς

Σελίδα 44

#include <iostream>

#include <fstream>

#include <iomanip>

using namespace std;

void main() {

ifstream ifile;

ofstream ofile;

double arithmos, tetragono;

ifile.open("C:\\input.txt");

ofile.open("C:\\output.txt");

while(ifile>>arithmos) {

tetragono = arithmos * arithmos;

ofile<<setw(8) << right << fixed <<setprecision(2) <<arithmos<< " " <<setw(8) << right << fixed <<setprecision(2) <<tetragono<<endl;

}

ifile.close();

ofile.close();

cout << "TO PROGRAMMA TELEIOSE!" << endl;

}

Παρατηρήσεις:

1. Απαιτείται η συμπερίληψη του αρχείου fstreamμε μια εντολή #include.

2. Για να ανοίξουμε ένα αρχείο, πρέπει να δηλώσουμε ένα αντικείμενο της κλάσης ifstream(για να

διαβάσουμε δεδομένα από αυτό) ή ofstream(για να γράψουμε δεδομένα σε αυτό).

Στο παραπάνω πρόγραμμα δηλώσαμε τα αντικείμενα ifileκαι ofile.

3. Το άνοιγμα ενός αρχείου γίνεται με τη συνάρτηση open(). Η συνάρτηση καλείται για καθένα από

τα αντικείμενα ifileκαι ofile.

Μέσα στις παρενθέσεις της συνάρτησης openγράφουμε τη διαδρομή για το αρχείο, π.χ.:

C:\\κατάλογος\\κατάλογος\\ κλπ κλπ \\όνομα _αρχείου. Με αυτόν τον τρόπο συσχετίζουμε το κάθε

αντικείμενο εισόδου-εξόδου με το αντίστοιχο αρχείο στον σκληρό δίσκο.

Προσέξτε ότι οι κεκλιμένες πρέπει να είναι διπλές και η διαδρομή γράφεται μέσα σε διπλά

εισαγωγικά.

4. Η ανάγνωση γίνεται γράφοντας το αντικείμενο (π.χ.: ifile), μετά τα διπλά βέλη προς τα δεξιά

και μετά μια μεταβλητή όπου αποθηκεύεται η τιμή (π.χ. arithmos). Π.χ. ifile>>arithmos;

5. Η εντολή ανάγνωσης (π.χ.: ifile>>arithmos) επιστρέφει την τιμή trueόσο δεν έχουμε

φτάσει ακόμη στο τέλος του αρχείου. Μόλις φτάσουμε στο τέλος, επιστρέφει την τιμή false.

Τότε θα σταματήσει τις επαναλήψεις της η εντολή while.

6. Η εγγραφή σε ένα αρχείο εξόδου (όπως π.χ. το output.txt) γίνεται γράφοντας το αντικείμενο

(π.χ. το ofile) που έχει συσχετιστεί με το αρχείο αυτό, έπειτα τα διπλά βέλη προς τα αριστερά

και έπειτα τη μεταβλητή ή τις μεταβλητές. Για παράδειγμα: ofile<<arithmos;

7. Όταν δεν χρειαζόμαστε πια ένα αρχείο για να διαβάσουμε από αυτό ή να γράψουμε σε αυτό, το

κλείνουμε καλώντας τη συνάρτηση close(). Π.χ. γράφουμε: ifile.close() ή

ofile.close().

Χρειάζεται για τον χειρισμό αρχείων.

Χρειάζεται για την μορφοποίηση της

εξόδου (setw, right, fixed, setprecision).