ממיבחניםC שאלות ++
תכנות מונחה עצמים ו C++ (35 נקודות) עליכם לממש מחלקות גנריות עבור "מערכים בטוחים". מערך בטוח הוא מערך המכיל מידע על אורכו, המאפשר הגנה מפני גלישה בשימוש. הגנריות מתבטאת בעובדה שהמימוש מאפשר ליצור מערכים שונים עבור סוגי עצמים שונים. למשל, הפקודה 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[]). טפלו נכון בשגיאות.
int main () { try { T1 a1(12), a11(10); // בגודל 12 ו10double הגדרת 2 מערכים של T2 a2(10); // 10 בגודל int הגדרת מערך של a2 = a11; // Syntax error a1 = a11; // O.K. a1[5] = a2[4]; // O.K. cout << a1; // הדפסת מערך שלם const T1 ca1(a11); // הגדרת מערך קבוע עם אתחול ca1 = a11; // Syntax error ca1[2] = a11[3]; // Syntax error a11[3] = ca1[2]; // O.K. double c_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_Index exc) { cerr << exc; // Bad-Index value is ... : פלט typedef .................. T1; typedef .................. T2; typedef .................. T3; typedef .................. T4; ......... more code? .........
typedef array<double> T1; typedef array<int> T2; typedef arraySize<double,5> T3; typedef arraySize<double,8> T4; class Bad_Index { int index; public: Bad_Index(int i):index(i){} friend ostream& operator<<(ostream& co,const Bad_Index& b) { return co << "Bad_Index value is " << b.index << endl; } };
class arrayBase { int size_; protected: bool legal(int index) const{return index>=0 && index<size_;} void size(int sz) { if (sz<0) size_=0; else size_=sz;} public: arrayBase(int sz) {size(sz);} int size() const {return size_;} };
template <class T> class array: public arrayBase { T* elem_array; void enter_array(T* ar,int sz){ elem_array = new T[sz]; size(sz); for (int i=0;i<sz;i++) elem_array[i] = ar[i];} public: array(int sz):arrayBase(sz){elem_array=new T[sz];} array(const array& ar):arrayBase(ar.size()) { enter_array(ar.elem_array,size());} array(T* ar, int sz):arrayBase(sz) { enter_array(ar,size());}
~array(){delete[] elem_array;} T& operator[](int i){ if (!legal(i)) throw Bad_Index(i); return elem_array[i]; } const T& operator[](int i) const{ array& operator=(const array& ar){ if (this == &ar) return *this; delete[] elem_array; enter_array(ar.elem_array,ar.size()); return *this; friend ostream& operator<< (ostream& co, const array<T>& ar); friend istream& operator>> (istream& ci, array<T>& ar); };
template <class T> ostream& operator<< (ostream& out, const array<T>& ar) { for (int i=0;i<ar.size();i++) out << ar.elem_array[i] << ' '; return out << endl; } istream& operator>> (istream& in, array<T>& ar) { in >> ar.elem_array[i]; return in;
template <class T,int SZ> class arraySize: public array<T>{ public: arraySize():array<T>(SZ){}; };
חלק א' (15 נק') רשמו את הפלט של התוכנית הבאה: #include <iostream.h> template <class T> class A { public: A() { cout << "A::A()" << endl;} A(const A& a) :i(a.i) { cout << "A::A(A&)" << endl;} private: T i; }; class B { B(A<T> aa): a(aa) { cout << "B::B(A)" << endl;} B(const B& b): a(b.a) { cout << "B::B(B&)" << endl;} A<T> a; class C : public B<int> { C(A<int> aa): B<int>(aa),a(aa) { cout << "C::C(A aa)" << endl;} ~C(){ cout << "C::~C()" << endl;} A<int> a; רשמו את הפלט של התוכנית הבאה: void main() { 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; }
--1-- A::A() --5-- A::A(A&) B::B(A) C::C(A aa) --2-- A::A() --3-- פתרון סעיף א': --1-- A::A() --5-- A::A(A&) B::B(A) C::C(A aa) --2-- A::A() --3-- A::A(A&) B::B(A) --6-- --4-- A::A(A&) B::B(B&) --7-- C::~C()
חלק ב' (15 נק') הגדר מחלקה/מחלקות הנדרשות בקובץ Array.h על מנת שקטע הקוד הבא יעבור הידור (קומפילציה). שים לב: רק הצהרת המחלקה/ות נדרשת - ללא מימוש הפונקציות. יש להניח שבמימוש המחלקה ישנם מצביעים.
חלק ב' (15 נק') #include "Array.h" #include "iostream.h" class A { public: A(int aa = 0) : a(aa) {} private: int a; }; int main () { 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); a1[0] = 10; a1[1] = 20; a1[2] = 30; int i; for (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 (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 (1); }
פתרון חלק ב' #ifndef __ARRAY_H_ #define __ARRAY_H_ template <class T> class Array { public: Array(int size=100); T operator[](int i) const; T& operator[](int i); Array& operator+=(const T& elem); int size() const; Array(const Array& src); Array& operator=(const Array& src); ~Array(); private: //... };
פתרון חלק ב' template <class T> ostream& operator<<(ostream& out, const Array<T>& arr); istream& operator>>(istream& inp, Array<T>& arr); //the next operators may be implemented as member bool operator<(const Array<T>& left, const Array<T>& right); bool operator==(const Array<T>& left, const Array<T>& right); #endif //__ARRAY_H_
תכנות מונחה עצמים ו- C++ (40) נקודות. חורף 2005-2006 בשאלה זו נעסוק במטריצות בעלות מימדים כלשהם ובפרט במטריצות ריבועיות. בעוד שפעולות שונות ניתנות לביצוע עם מטריצות בגודל כללי (כמו transpose) ישנן פעולות מסוימות הניתנות להפעלה אך ורק על מטריצות ריבועיות. מבין פעולות אלו נתייחס בשאלה לחישוב הדטרמיננטה שלה (determinant). סעיף א (25 נקודות) סעיף זה מתייחס לקטע הקוד הבא: const double EPSILON = 0.000001; int main(){ //create two 3*1 matrices (3D vectors) //with entries of type double assigned //with zeros: Matrix<double> m1, m2(3,1); const Matrix<double> m3=m1; //assign values to m1 from the file “matrix_1.dat”: ifstream inputFile(“matrix_1.dat”); inputFile >> m1; inputFile.close(); m2 = m1; m2.getEntry(0,0) = m3.getEntry(1,0); //SYNTAX ERROR !!! m3.getEntry(1,0) = m2.getEntry(0,0); Matrix<double> m4(10,3); inputFile.open(“matrix_4.dat”); inputFile >> m4; //create a 3*3 matrix with the multiplication //of m4’s transpose and m4: Matrix<double> m5( m4.transpose() * m4 ); //return 1*3 matrix Matrix<double> secondRow = m5.getRow(1); //return 3*1 matrix Matrix<double> firstColumn = m5.getColumn(0); //create two 3*3 square-matrices. The first equals //to m5, and the second initielied with zeros: SquareMatrix<double> sm6(m5), sm7(3); sm7 = sm6.transpose(); double det6 = sm6.determinant(); double det7 = sm7.determinant(); double diff = (det6 > det7)? det6-det7 : det7-det6 ; if(diff>EPSILON) cout << ”something very strange is going on...”; // save the transposed matrix to the specified file: ofstream outputFile(“transposedMatrix.dat”); outputFile << sm7; outputFile.close(); return 0; }
הגדר\י את המחלקות Matrix ו- SquareMatrix באופן מינימאלי כך שהקוד הנ"ל יוכל לעבור קומפילציה (למעט השורה בה מצוין כי חבויה שגיאה). אין להוסיף פונקציונאליות מעבר לנדרש עבור קוד זה ואין צורך לממש את המתודות השונות. בכדי שהמחלקה תהיה ניתנת למימוש יש להניח הנחות מסוימות לגבי ה- type של ה- entries (המוזן ל-template). ציין\י הנחות אלו ופרט\י מדוע הנחות אילו נחוצות.
פתרון סעיף א' template <class T> class Matrix { protected: T** mat; int x_dim, y_dim; public: Matrix(int x=3, int y=1); Matrix(const Matrix<T>& matrix); Matrix& operator=(const Matrix<T>& matrix); const T& getEntry(int x, int y) const; T& getEntry(int x, int y); Matrix transpose() const; Matrix operator*(const Matrix<T>& matrix) const; Matrix getRow(int x) const; Matrix getColumn(int y) const; ~Matrix(); friend operator >> (ifstream& cin, Matrix<T>& matrix); friend operator << (ofstream& cout, Matrix<T>& matrix); }; template <class T> class SquareMatrix : public Matrix<T> { SquareMatrix(int x=3); SquareMatrix(const Matrix<T>& matrix); T& determinant() const; ~SquareMatrix();
פתרון סעיף א' בכדי שהמחלקה תהיה ניתנת למימוש יש להניח את ההנחות הבאות על ה-type של ה-entries: copy constructor – על מנת שנוכל לממש את ה-copy constructor של Matrix. אופרטור >> על מנת שיהיה ניתן לקלוט data מ-ifstream. אופרטור השמה – על מנת שיהיה אפשר לממש אופרטור השמה של Matrix. אופרטור * ו-+- על מנת שיהיה ניתן לממש את האופרטור * של Matrix. אופרטור +,-,* - לחישוב ה-determinant. default constructor – לאיתחול מערך של entries עבור ה-costructors. אופרטור << - על מנת שנוכל לממש את אופרטור ההדפסה של Matrix.
סעיף ב (15 נקודות) מטריצה סימטרית הינה מטריצה ריבועית השווה ל-transpose של עצמה. בסעיף זה של השאלה הנך נידרש לממש את המחלקה SymetricMatrix. מעבר למתודות הנורשות, למחלקה זו יהיה: בנאי (constructor) המקבל את גודל המטריצה (פרמטר יחיד) ומאתחל אותה כמטריצת היחידה (I) בנאי המקבל SquareMatrix – M כלשהי. היות ו-M אינה סימטרית בהכרח, הבנאי יאתחל את ערכי המטריצה ע"י MTM (שמו לב לכך שביטוי זה הינו סימטרי בהכרח). הגדיר\י וממש\י מחלקה זו. במידה ויש צורך בהנחות נוספות לגבי ה- type של ה- entries ציין\י הנחות אילו.
פתרון סעיף ב' template <class T> class SymetricMatrix : public SquareMatrix<T> { public: SymetricMatrix (int size); SymetricMatrix (const SquareMatrix<T>& matrix); ~ SymetricMatrix (); }; template <class T> SymetricMatrix <T>:: SymetricMatrix (int size): SquareMatrix<T>(size) { for (int i=0;i<size; i++){ for (int j=0; j<size;j++){ if(i!=j) getEntry(i,j) = 0; else getEntry(i,i) = 1; } SymetricMatrix <T>:: SymetricMatrix (const SquareMatrix<T>& matrix) : SquareMatrix<T>(matrix.transpose()* matrix) {}