Οικονομικό Πανεπιστήμιο Αθηνών, Τμήμα Πληροφορικής Μάθημα: Προγραμματισμός Υπολογιστών με C++ Εξεταστική περίοδος: Φεβρουαρίου 2010. Διδάσκων: Α. Δημάκης Γράψτε όλες τις απαντήσεις σας πάνω σε αυτό το φυλλάδιο. Χρησιμοποιήστε το τετράδιο μόνο για πρόχειρο. Γράψτε το ονοματεπώνυμό σας στο τετράδιο και σε όλα τα φύλλα αυτού του φυλλαδίου. Ονοματεπώνυμο και ΑΜ: Είχα παραδώσει εργασίες τα προηγούμενα ακαδημαϊκά έτη: ΚΑΛΗ ΕΠΙΤΥΧΙΑ! 1o θέμα (20%): Δίνονται οι παρακάτω ορισμοί τάξεων: // Αρχείο foo.h #include <iostream> using namespace std; class A A() cout << A s constructor\n ; A(const A &) cout << A s copy constructor\n ; void operator=(const A& right) cout << A s =\n ; virtual void f() cout << A s f()\n ; ; class B: public A B() cout << B s constructor\n ; void f() cout << B s f()\n ; ; (α) Τί θα εκτυπώσει η παρακάτω συνάρτηση main(); #include foo.h A func(a& arg) return arg; A a,b; b = a; A c(a); func(a); (β) Τί θα εκτυπώσει η παρακάτω συνάρτηση main(); #include foo.h A a; B b; a.f(); b.f(); B* p1 = new B; p1->f(); A* p2 = &b; p2->f(); (γ) Τί θα εκτυπώσει η παραπάνω συνάρτηση main() εάν η μέθοδος A::f() δε δηλωθεί ως εικονική (virtual);
2o θέμα (40%): (α) Δίνεται ο ορισμός της τάξης Matrix η οποία αναπαριστά (μαθηματικούς) πίνακες με στοιχεία τύπου float και υποστηρίζει πολλαπλασιασμό και πρόσθεση μεταξύ πινάκων. Συμπληρώστε τους ορισμούς στα κενά που ακολουθούν έτσι ώστε (1): οι διαστάσεις n,m ενός πίνακα να μη μπορούν να αλλάξουν μετά την αρχικοποίησή του, και (2) κατά την αρχικοποίησή του, όλα τα στοιχεία λαμβάνουν την ίδια τιμή value (ενώ μπορεί να λάβουν διαφορετική τιμή στη συνέχεια). class Matrix n; // πλήθος γραμμών m; // πλήθος στηλών float *storage; // δείκτης στο χώρο αποθήκευσης των στοιχείων του πίνακα Matrix(unsigned ni, unsigned mi, float value=0f) : n(ni), m(mi), storage(new float[n*m]) for (unsigned i=0; i < ; i++ ) for ( unsigned j=0; j < ; j++ ) (*this)[i][j] = ; Matrix(const Matrix &original); ~Matrix(); const Matrix operator+(const Matrix &obj) const; const Matrix operator*(const Matrix &obj) const; const Matrix operator=(const Matrix &right); float* const operator[](unsigned int i) const return &storage[i*m]; ; friend ostream& operator<<(const ostream &out, const Matrix &matrix); (β) Υλοποιήστε τη συνάρτηση operator<<(ostream&, const Matrix&) έτσι ώστε η παρακάτω συνάρτηση main() να έχει το επιθυμητό αποτέλεσμα. Matrix m(2,3,1.0f); cout << m; // Εκτυπώνει: 1.0 1.0 1.0 // 1.0 1.0 1.0 ostream& operator<<(const ostream &out, const Matrix &matrix) // Συμπληρώστε εδώ:
(γ) Υλοποιήστε τους τελεστές + και *. Δε χρειάζεται να κάνετε έλεγχο λαθών, π.χ., καταλληλία διαστάσεων. const Matrix Matrix::operator+(const Matrix &obj) const /* Υπενθύμιση: το γινόμενο, όπου ο έχει διαστάσεις n m και ο m l, είναι πίνακας διαστάσεων i 0,..., n 1 και 0,..., l 1 j. */ n l και ικανοποιεί const Matrix Matrix::operator*(const Matrix &obj) const ij m 1 k0 ik kj, όπου
(δ) Υλοποιήστε καταστροφέα, κατασκευαστή αντιγράφου και τελεστή εκχώρησης έτσι ώστε να αποφεύγεται η διαρροή μνήμης. Matrix::~Matrix() Matrix::Matrix(const Matrix &original) const Matrix Matrix::operator=(const Matrix &right) (ε) Ορίστε και υλοποιήσετε μία μέθοδο ή συνάρτηση η οποία δίνει τη δυνατότητα πολλαπλασιασμού αριθμό float με πίνακα, έτσι ώστε το ακόλουθο πρόγραμμα να έχει το επιθυμητό αποτέλεσμα: Matrix m(2,3,5.0f); cout << -0.5F*m; // Εκτυπώνει: -2.5-2.5-2.5 // -2.5-2.5-2.5 Συμπληρώστε την υλοποίησή σας στον κενό χώρο που ακολουθεί. Επίσης περιγράψτε τις αλλαγές που απαιτούνται στον ορισμό της τάξης Matrix.
3 ο θέμα (40%): Δίνεται ο ορισμός της τάξης Queue η οποία αναπαριστά τη δομή δεδομένων «ουρά» (=απλά συνδεδεμένη λίστα). Εισάγονται ακέραιες τιμές στο «τέλος» της ουράς χρησιμοποιώντας τη μέθοδο enqueue(int), ενώ γίνεται ανάγνωση και διαγραφή του ακεραίου από την «κεφαλή» της ουράς με τη μέθοδο dequeue(). (Βλέπε παράδειγμα στη main() που ακολουθεί.) class Queue class Node int value; Node* next; Node(int valuein): value(valuein), next(nextin) ; Node* head, *tail; class EmptyQueueException EmptyQueueException(string msg=0) cerr << msg << : empty queue exception\n ; ; Queue(); ~Queue(); Queue(const Queue& original) throw(bad_alloc); Queue& operator=(const Queue& right) throw(bad_alloc); void enqueue(int valuein) throw(bad_alloc); int dequeue() throw(emptyqueueexception); ; class iterator Node* nodeptr; iterator(node* nodeptrin = 0); const iterator operator++(int); bool operator!=(const iterator& right); int operator*() const; ; iterator end() const; iterator firstelement() const; Υλοποιήστε όλες τις παραπάνω μεθόδους (συμπεριλαμβανομένων κατασκευαστών και καταστροφέων) έτσι ώστε η παρακάτω συνάρτηση main() να έχει το επιθυμητό αποτέλεσμα και να αποφεύγεται η διαρροή μνήμης. Μπορείτε να ορίσετε και υλοποιήσετε οποιεσδήποτε επιπλέον ιδιωτικές μεθόδους σας διευκολύνουν, όμως δε μπορείτε να χρησιμοποιήσετε τις δομές δεδομένων της βιβλιοθήκης STL. Δε χρειάζεται να κάνετε έλεγχο λαθών στην τάξη iterator. Απαντήστε στον κενό χώρο που ακολουθεί. (Για σύντομες μεθόδους μπορείτε να γράφετε την υλοποίησή τους δίπλα στη δήλωσή τους στον ορισμό της Queue παραπάνω.) void printqueue(queue &argq) for(queue::iterator it=argq.firstelement(); it!= argq.end(); it++) cout << *it << ; cout << endl; Queue q; try
q.enqueue(20); q.enqueue(-10); q.enqueue(3); printqueue(q); cout << q.dequeue() << endl; printqueue(q); q.dequeue(); q.dequeue(); cout << q.dequeue(); catch(queue::emptyqueueexception e) cerr << exiting \n ; exit(1); catch(bad_alloc e) cerr << Insufficient memory space, exiting \n ; exit(1); // Εκτυπώνεται: 20-10 3 // 20 // -10 3 // dequeue(): empty queue exception // exiting