E N D
תרגול מס' 13 שאלות ממבחנים - C++
שאלה 1 • מבנה הנתונים תור (queue) הוא מבנה הדומה למחסנית (stack) שנלמדה בקורס.לתור ניתן להוסיף איברים (ע"י פעולה הנקראת enqueue) וניתן להסיר את האיבר שבראש התור (dequeue), כלומר האיבר הוותיק ביותר בתור (בניגוד למחסנית בה באיבר שמוסר הוא האחרון שנוסף). • כלומר מבנה הנתונים תור צריך לתמוך בפעולות הבאות: • יצירה של תור חדש. • הריסה של תור קיים. • העתקה של תור קיים. • השמה מתור א' לתור ב'. כך שלאחר הפעולה שני התורים יהיו זהים. • הוספת איבר לסוף התור. • הסרת האיבר הראשון בתור. • אם התור ריק תיזרק חריגה מסוג QueueEmpty. • החזרת האיבר הראשון (הוותיק ביותר) בתור. יש להחזיר את האיבר עצמו ללא העתקה. • גם במקרה זה אם התור ריק תיזרק חריגה מסוג QueueEmpty. • ממשו תור גנרי בשפת ++C. הקפידו לכתוב רק את הקוד הדרוש. • ניתן להשתמש ב-std∷listשל שפת ++C כמו שנלמד בתרגול על ה-STL. מבוא לתכנות מערכות - 234122
שאלה 1 - פתרון template<typenameT> classQueue { std::list<T> items; public: classQueueEmpty: publicstd::exception {}; voidenqueue(constT& t) { items.push_back(t); } voiddequeue() { if (items.empty()) throwQueueEmpty(); items.pop_front(); } T& front() { returnitems.front(); } constT& front() const { returnitems.front(); } }; מבוא לתכנות מערכות - 234122
שאלה 2 • נתונות שתי המחלקות הבאות: • כתוב תכנית קצרה ככל הניתן המדפיסה פלט שונה לכל אחת מהמחלקות שהוצגו.כלומר, עליכם לכתוב קוד המכיל פונקצית main ומשתמש במחלקה A כך שהפלט המודפס בהרצת הקוד שונה כאשר מקמפלים אותו עם כל אחת מהמחלקות הנתונות. classA { public: voidf() { cout << "1" << endl; } }; classA { public: virtualvoidf() { cout << "1" << endl; } }; מבוא לתכנות מערכות - 234122
שאלה 2 - פתרון classB : publicA { public: voidf() { cout << "2" << endl; } }; intmain(intargc, char **argv) { A* a = new B(); a->f(); return 0; } מבוא לתכנות מערכות - 234122
שאלה 3 • הנכם נדרשים להרחיב את המחלקה String כפי שנלמדה בתרגול 10. עליכם להוסיף תמיכה באיטרטור אשר נע לכיוון הנגדי (reverse iterator) כך שהקוד הבא יתקמפל והפלט המתקבל בהרצתו יהיה cba. #include"string.h"intmain() {String s("abc"); for (String::reverse_iterator i = s.rbegin(); i != s.rend(); ++i) { std::cout << *i;}return 0;} • הוסיפו וממשו את ההגדרות המתאימות עבור הטיפוס String∷reverse_iterator. • אין צורך להוסיף תמיכה גם ב-const_reverse_iterator. מבוא לתכנות מערכות - 234122
שאלה 3 class String { char* data; intlength; public: String(); String(constchar*); String(const String&); ~String(); String& operator=(const String&); intsize() const; constchar& operator[](int) const; char& operator[](int); typedefchar* iterator; typedefconstchar* const_iterator; iteratorbegin() { returndata; } const_iteratorbegin() const { returndata; } iteratorend() { returndata + length; } const_iteratorend() const { returndata + length; } // ... more code ... }; • תזכורת, מנשק המחלקה String: (חלקי) מבוא לתכנות מערכות - 234122
שאלה 3 - פתרון • נוסיף בתוך המחלקה String את הקוד הבא: class String {// ... more code ...public: classreverse_iterator { char* index; public: explicitreverse_iterator(char* i) : index(i) {} reverse_iterator& operator++() { --index; return *this; } char& operator*() const{ return*index; } booloperator!=(constreverse_iterator& i) const{ returnindex != i.index;} }; reverse_iteratorrbegin() { returnreverse_iterator(data + length - 1); } reverse_iteratorrend() { returnreverse_iterator(data- 1); } }; מבוא לתכנות מערכות - 234122
שאלה 4 • בתרגול 12 ראינו את אוסף המחלקות עבור צורות, להלן תזכורת של הקוד עבור המחלקות האלו: • ברצוננו לאפשר הדפסת של צורות ע"יאופרטור ההדפסה >> כך שעבור עיגוליודפס שרדיוסו 3 יודפס Circle: radius=3ואילו עבור ריבוע שאורך הצלע שלו היא 2יודפס Square: side length=2. • הוסיפו תמיכה באופרטור ההדפסה למחלקותהנ"ל. תארו במדויק את שינויי הקוד שלכםוהיכן הם צריכים להתבצע. classCircle : publicShape { intradius; public: Circle(int x, int y, int radius) : Shape(x,y), radius(radius) {} virtualdoublearea() const{ returnradius*radius*PI;}}; classSquare : publicShape { intedge; public: Square(int x, int y, int edge) : Shape(x,y), edge(edge) {} virtualdoublearea() const{ returnedge*edge;}}; classShape { intcenter_x, center_y; public: Shape(int x, int y) : center_x(x), center_y(y) {} virtual~Shape() {} virtualdoublearea() const = 0;}; מבוא לתכנות מערכות - 234122
שאלה 4 - פתרון class Square: publicShape { //... protected: virtualvoidprint(ostream& os) const { os << "Square: side length=" << edge; } }; ostream& operator<<(ostream& os, constShape& s) { s.print(os); returnos; } class Shape { //... protected: friendostream& operator<<(ostream& os, constShape& s); virtualvoidprint(ostream& os) const = 0; }; class Circle: publicShape { //... protected: virtualvoidprint(ostream& os) const { os << "Circle: radius=" << radius; } }; מבוא לתכנות מערכות - 234122
שאלה 5 • עליכם לממש מחלקות גנריות עבור "מערכים בטוחים". מערך בטוח הוא מערך המכיל מידע על אורכו, המאפשר הגנה מפני גלישה בשימוש. הגנריות מתבטאת בעובדה שהמימוש מאפשר ליצור מערכים שונים עבור סוגי עצמים שונים. למשל, הפקודה • array<double> vec(12) • תיצור מערך של double בגודל 12. כדי למנוע שכפול קוד ע"י הקומפיילר (לכל instance של ה-template), יש לאסוף את החלקים המשותפים במחלקת בסיס class arrayBase ואח"כ לבצע הורשה: • template <class T> class array: public arrayBase {...} • יש לממש מחלקות כדי שהתוכנית למטה תתבצע כפי שנדרש. שימו לב: בראש הקוד הושמטו שמות המחלקות; עליכם להשלים את הקוד. מומלץ לקרוא את כל הקוד לפני פתרון השאלה. • סעיף א (15 נקודות): הגדרת המחלקות: • הגדירו את המחלקות 1T, 2T, 3T, ו-T4 עם מתודות סבירות לשימוש קל ונוח במערכים (כולל קלט/פלט). שימו לב כי יש להגדיר את כל שדות הנתונים ולהצהיר על כל הפונקציות הנדרשות. אין צורך לממש שום פונקציה. הגדירו גם את המחלקה לטיפול בחריגות. • סעיף ב (20 נקודות): מימוש (חלק מהפונקציות של) המחלקות: • ממשו את הפונקציות הבאות בכל מחלקה בה הן מופיעות: בנאים (constructors) אין צורך לאפס ערכים לא מאותחלים, הורסים (destructors), אופרטור פלט (operator<<), ופעולת אינדקס (operator[]), טפלו נכון בשגיאות. מבוא לתכנות מערכות - 234122
קוד השימוש במחלקות • typedef ........ T1; • typedef ........ T2; • typedef ........ T3; • typedef........ T4; • //... more code? ... • intmain () { • try { // משמעות + תוצאה • T1 a1(12), a11(10); //הגדרת 2 מערכים של • //בגודל 12 ו-10 double • T2 a2(10); // 10 בגודלintהגדרת מערך של • a2 = a11; // Syntax error • a1 = a11; // O.K. • a1[5] = a2[4]; // O.K. • cout << a1; // הדפסת מערך שלם • constT1 ca1(a11); // הגדרת מערך קבוע • // עם אתחול • ca1 = a11; // Syntax error • ca1[2] = a11[3]; // Syntax error • a11[3] = ca1[2]; // O.K. • doublec_array[] = {0.5, -7, 3.14, 0.3}; • // "C הגדרת "מערך • T1 a12(c_array, 4); // הגדרת מערך ואתחולו • // "C ע"י "מערך • T3 a3; // בגודל5double הגדרת מערך של • T4 a4; // בגודל8double הגדרת מערך של • a3[1] = a4[2]; // O.K. • a3 = a4; // Syntax error • a4 = a3; // Syntax error • a1 = a4; // O.K. • return 0; • } • catch (Bad_Indexexc) { • cerr << exc; //Bad-Index value is ... :פלט • } • } מבוא לתכנות מערכות - 234122
שאלה 5 - פתרון • typedef Array<double> T1; • typedef Array<int> T2; • typedefSizedArray<double, 5> T3; • typedefSizedArray<double, 8> T4; • classBadIndex { • intindex; • public: • BadIndex(int i) : index(i) {} • friendostream& operator<<(ostream& os, constBadIndex& b); • }; • ostream& operator<<(ostream& os, constBadIndex& b) { • returnos << "Array index " << b.index << " is out of bounds" << endl; • } מבוא לתכנות מערכות - 234122
שאלה 5 - פתרון • classArrayBase { • protected: • intsize; • boolisLegal(int index) const { • return index >= 0 && index < size; • } • public: • ArrayBase(intsz): size(sz) { } • intgetSize() const { • returnsize; • } • }; מבוא לתכנות מערכות - 234122
שאלה 5 - פתרון • template<classT>classArray: publicArrayBase { • T* elements; voidfillArray(T* data,intsz){ • elements= newT[sz]; • size= sz; • for(int i=0;i<sz;i++) • elements[i] = data[i];}public: • Array(intsz) : ArrayBase(sz), elements(newT[sz]) {} • Array(constArray<T>& array2) : ArrayBase(array2.size) { • fillArray(array2.elements,size); } • Array(T* array2, intsz) : ArrayBase(sz) { • fillArray(array2,size);} מבוא לתכנות מערכות - 234122
שאלה 5 - פתרון • ~Array() { delete[] elements; } • T& operator[](int i) { • if (!isLegal(i)) throwBadIndex(i); • returnelements[i]; } • constT& operator[](int i) const { • if (!isLegal(i)) throwBadIndex(i); • returnelements[i];} • array& operator=(const array& other) { • if (this == &other) {return*this; } • delete[] elements; • fillArray(other.elements,other.size()); • return *this;}}; מבוא לתכנות מערכות - 234122
שאלה 5 - פתרון • template<classT> • ostream& operator<< (ostream& out, constArray<T>& array) { • for(inti=0 ; i < array.getSize() ; i++) • out << array[i] << ' '; • returnout << endl; • } • template <classT> • istream& operator>> (istream& in, Array<T>& array) { • for(inti=0 ; i < array.getSize() ; i++) • in >> array[i]; • returnin; • } • template <classT,intN> • classSizedArray: publicArray<T>{ • public: • SizedArray() : Array<T>(N) {}; • }; מבוא לתכנות מערכות - 234122
שאלה 6 • מה מדפיסה התכנית הבאה? intmain() { cout << "--1--" << endl; A<int> a; cout << "--2--" << endl; A<double> a1; cout << "--3--" << endl; B<int> b(a); cout << "--4--" << endl; B<int> b1(b); cout << "--5--" << endl; C c(a); cout << "--6--" << endl; B<int>& b2 = c; cout << "--7--" << endl; return 0; } #include<iostream>usingnamespacestd;template<classT>classA { public: A() { cout << "A::A()" << endl; } A(constA& a) : i(a.i) { cout << "A::A(A&)" << endl; } private: Ti; };template<classT> classB { public: B(A<T> aa) : a(aa) { cout << "B::B(A)" << endl; } B(constB& b) : a(b.a) { cout << "B::B(B&)" << endl; } A<T> a;};classC: publicB<int> { public: C(A<int> aa) : B<int> (aa), a(aa) { cout << "C::C(A aa)" << endl; } ~C() { cout << "C::~C()" << endl; } A<int> a; }; מבוא לתכנות מערכות - 234122
שאלה 6 - פתרון • יודפס: --5-- A::A(A&) A::A(A&) A::A(A&) B::B(A) A::A(A&) C::C(A aa) --6-- --7-- C::~C() --1-- A::A() --2-- A::A() --3-- A::A(A&) A::A(A&) B::B(A) --4-- A::A(A&) B::B(B&) מבוא לתכנות מערכות - 234122
שאלה 7 • הגדר מחלקה/מחלקות הנדרשות בקובץ Array.h על מנת שקטע הקוד הבא יעבור הידור (קומפילציה). • שים לב: רק הצהרת המחלקה/ות נדרשת - ללא מימוש הפונקציות. יש להניח שבמימוש המחלקה ישנם מצביעים. מבוא לתכנות מערכות - 234122
שאלה 7 - קטע הקוד for (int i = 0; i < 20; i++) { cin >> arr[i]; sum += arr[i]; } cout << "Sum is:" << sum << endl; min = arr[0]; for (i = 1; i < 20; i++) if (arr[i] < min) min = arr[i]; cout << "Min is: " << min << endl; if (min == arr[0]) cout <<"The first Array is the minimum"<<endl; const Array<double> c_arr = sum; for (int i = 0; i < c_arr.size(); i++) { cout <<"Element #"<<i<<": "<<c_arr[i]<<endl; } delete a1; Array<A> arr_A(7); Array<A> arr_A2 = arr_A; return 0; } #include"Array.h" #include"iostream.h" class A { inta; public: A(intaa = 0) : a(aa) {} };intmain() { Array<int> *a1 = new Array<int>(3); //An array with 3 elements of type int Array<double> arr[20]; //An array of 20 Arrays, each one of them //is of 100 elements of type double Array<double> sum(100); //An Array of 100 elements of type double Array<double> min(100); //An Array of 100 elements of type double sum[0] = 10; sum[1] = 20; sum[2] = 30; מבוא לתכנות מערכות - 234122
שאלה 7 - פתרון • #ifndef __ARRAY_H_ • #define __ARRAY_H_ • template<classT> • classArray { • public: • Array(int size = 100); • constT& operator[](int i) const; • T& operator[](int i); • Array& operator+=(constArray& arr); • intsize() const; • Array(constArray& src); • Array& operator=(constArray& src); • ~Array(); • private: • //... • }; מבוא לתכנות מערכות - 234122
שאלה 7 - פתרון • // the next operators are global functions • template<classT> • ostream& operator<<(ostream& out, constArray<T>& arr); • template<classT> • istream& operator>>(istream& inp, Array<T>& arr); • // the next operators may be implemented as member functions • template<classT> • booloperator<(constArray<T>& left, constArray<T>& right); • template<classT> • booloperator==(constArray<T>& left, constArray<T>& right); • #endif//__ARRAY_H_ מבוא לתכנות מערכות - 234122