Presentation is loading. Please wait.

Presentation is loading. Please wait.

1 נושאי התרגול : Copy constructorCopy constructor Assignment operatorAssignment operator המרת טיפוסים אוטומטיות המרת טיפוסים אוטומטיות תכנות גנרי – Templates.

Similar presentations


Presentation on theme: "1 נושאי התרגול : Copy constructorCopy constructor Assignment operatorAssignment operator המרת טיפוסים אוטומטיות המרת טיפוסים אוטומטיות תכנות גנרי – Templates."— Presentation transcript:

1 1 נושאי התרגול : Copy constructorCopy constructor Assignment operatorAssignment operator המרת טיפוסים אוטומטיות המרת טיפוסים אוטומטיות תכנות גנרי – Templates תכנות גנרי – Templates

2 2 Copy constructor Assignment operator

3 3 Copy constructor & Assignment operator מה קורה כאשר מבצעים s1 = s2? מה קורה כאשר מבצעים Stack s1 = s2? מה ההבדל ? מה הסכנה ? מה קורה כאשר קוראים לפונקציה : f(Stack s) ; f(Stack& s) ; פתרון copy c’tor - לאתחול, assign. Op. - להשמה

4 4 Copy constructor & Assignment operator עבור כל מחלקה חדשה, מוגדרות באופן אוטומטי שתי פונקציות: copy constructor – –משמש לאתחול של עצם אחד של המחלקה ע"י עצם אחר של אותה מחלקה –משמש לאתחל פרמטרים בקריאה לפונקציות, כלומר כאשר מעבירים פרמטר מסוג מחלקה מסוימת by value, ערכי השדות של הפרמטרים מאותחלים ע"י קריאה לפונקציה זאת (כנ"ל לגבי החזרת ערכים) X(const X&) מובטח שלא נשנה את הפרמטר המועבר אי אפשר להגדיר copy constructor באמצעות copy constructor

5 5 אופרטור ההשמה (=) – – משמש להשמה של עצמים מהמחלקה זה לזה פרט לאתחול של עצם אחד של המחלקה ע " י עצם אחר של אותה מחלקה ( במקרה של אתחול ייקרא ה -copy c’tor, אפילו אם משתמשים בסימן = בביצוע האתחול ) בשני המקרים, בפונקצית ברירת המחדל ההעתקה היא איבר איבר. יש מקרים שבהם העתקה איבר איבר אינה טובה ( למשל, במקרה בו יש מצביעים כשדות במחלקה ). במקרים האלה, על המשתמש להגדיר פונקציות אלו מחדש Copy constructor & Assignment operator

6 6 כלל אצבע : בכל מחלקה בה יש שדות שהם מצביעים, יש להגדיר מחדש : Copy Constructor Assignment Operator Destructor

7 7 The Final Stack class Stack { int* array; int top_index, size; public: Stack (int s = 100) ; Stack (const Stack&) ; Stack& operator=(const Stack&); ~Stack() ; Result push(int e); Result pop() ; Result top(int& e); void print() ; };

8 8 Copy constructor Stack::Stack(const Stack & st) { array = new int [st.size]; if (array == 0) error(“out of memory”); // assumes error exits size = st.size; top_index = st.top_index; for (int top = 0 ; top<st.top_index; top++) array[top] = st.array[top]; }

9 9 Assignment operator Stack& Stack::operator=(const Stack& st) { if (this == &st) return *this; if (st.size != size) { delete[] array; array = new int[size = st.size]; } for (int top = 0 ; top<st.top; top++) array[top] = st.array[top]; top_index = top; return *this ; } חמשת הצעדים : בדיקת הצבה עצמית שחרור משאבים הקצאת משאבים חדשים אתחול השדות החזרת this*

10 10 המרת טיפוסים אוטומטיות

11 11 User Defined Type Conversions ב ++C קיימים שני סוגי המרות טיפוסים אוטומטיות : Conversion by constructor Conversion by conversion operator

12 12 Conversion by constructor בעזרת c’tors של מחלקה T אפשר להמיר כל מחלקה אחרת או טיפוסים פנימיים של השפה כך שיהפכו לאיבר מסוג T ההמרה מתבצעת ע”י הגדרת Constructor המקבל ארגומנט יחיד, מהטיפוס הנ”ל. T(class C); //converts from class C to T ההמרה תתבצע אוטומטית על ידי הקומפיילר ההמרה מאפשרת לקרוא לפונקציות המצפות לקבל ארגומנט מטיפוס T עם ארגומנט מטיפוס C במקום דוגמא: –במחלקה Complex : המרה מ-double (עוד מעט) – המרה מ-* const char למחלקה String (תרגול קודם)

13 13 דוגמא - המחלקה Complex נירצה להגדיר מחלקה של מספרים מרוכבים. נירצה גם לאפשר את פעולות החשבון הרגילות בין מספרים מרוכבים ומספרים שלמים. דרך אחת לעשות זאת היא להגדיר את כל האפשרויות עבור כל אופרטור, בדומה לדוגמא הבאה: class complex { double re,im; public: complex (double r, double i) {re = r; im = i;} friend complex operator+(complex, complex); friend complex operator+(complex, double); friend complex operator+(double, complex); // Do the same for the rest of the operators… }; שיטה זו מייגעת ומלאה חזרות. דרך נוספת לעשות את אותו הדבר היא להגדיר constructor ל-complex אשר מקבל פרמטר יחיד מטיפוס double. כעת ההמרה תתבצע אוטומטית באמצעות constructor זה

14 14 דוגמא - המחלקה Complex class complex { //... complex(double r) {re = r; im = 0;} friend complex operator+(complex,complex); }; המהדר יבצע את ההמרה באופן אוטומטי. לדוגמא : main() { complex a; complex b; a=b+23; } מה שמתבצע זה : 1.23 מומר ל - complex ע " י ה - constructor. 2. מתבצע חיבור בין שני complex. 3.a מקבל את התוצאה ע " י אופרטור ההשמה המוגדר כברירת מחדל ע " י המהדר ( העתקה איבר איבר ).

15 15 Conversion by conversion operator בעזרת אופרטורים מיוחדים שמוגדרים במחלקה T אפשר להמיר את T לטיפוסים פנימיים של השפה או למחלקות אחרות שכבר הוגדרו הדרך היחידה להגדיר המרה לטיפוסים פנימיים של השפה (למה?) המרה זו מבוצעת ע ” י הגדרת conversion operator ( מתודה של המחלקה T) operator C() ; // converts from T to C. דוגמא : class Price { int Shekel, agorot ; … public: …. operator double() { return shekel + agorot / 100.0 ;} … }; שימו לב שלאופרטור אין ערך החזרה אבל השתמשנו ב -return בתוכו עם ערך החזרה... מנפלאות הסינטקס של C++ ( אז מה כן מחזירים ?)

16 16 בעיות עם המרות אוטומטיות class x { //... x(int); x(char*); … }; class y{ //... y(int); …. }; class z {//... z(x); …. }; x f(x); y f(y); z g(z); void k1() { f(1);// Illegal: ambiguous f(x(1)) or f(y(1)) f(x(1)); f(y(1)); g("asdf") ; // Illegal: g(z(x("asdf"))) not tried g(z("asdf")); // O.k.: x(char*) is carried out } פרט לכך קיימות שתי בעיות עם המרות: – מתבצעת רק המרה אחת – עלולה להיווצר דו משמעות (ambiguity)

17 17 המרות ואופרטורים כזכור operators הם בעצם פונקציות. לכן גם עבורם יכולה להתבצע המרה. לדוגמה, אופרטור החיבור במחלקה Complex יכול להיקרא: c2 = c1 + 5 ; אולם אם אופרטור מוגדר כ method לא תתבצע המרה על הארגומנט הראשון שלו. בגלל בעיה זו, עדיף בד"כ להגדיר אופרטור ע"י פונק' חיצונית. כך, הטיפול בשני האופרנדים יהיה סימטרי class complex {... public: complex(double r) {re = r; im = 0;} operator+(const complex&); friend operator-(const complex&, const complex&); }; main() { complex c2,c1; c1=2.0+c2;// Error: 2.0 will not be converted c2=2.0-c2;// O.k.: 2.0 will be converted }

18 18 תכנות גנרי – Templates

19 19 תכנות גנרי - Templates Containers משמש בעיקר כאשר בונים Containers - מחלקות אשר מכילות עצמים אחרים, אולם אין חשיבות לתכונותיו הייחודיות של אותו עצם אותן פעולות מוגדרות על ה Container ללא קשר לעצם שבו. לדוגמא עבור מחסנית תמיד יוגדרו : –push –pop –top ללא חשיבות אם זו מחסנית של int, char או String

20 20 דוגמת המחסנית int_stack.h: class int_stack { int top_index,size; int* array ; public: int_stack(int s) ; void pop() ; void push(int e); int top() ; int size(); }; char_stack.h: class char_stack { int top_index,size; char* array ; public: char_stack(int s) ; void pop() ; void push(char e); char top() ; int size(); }; String_stack.h: class string_stack { int top_index,size; String* array ; public: string_stack(int s) ; void pop() ; void push(String e); String top() ; int size(); };

21 21 int_stack.cc ( חלקי ): int_stack::int_stack (int s) { top_index = 0 ; size = s ; array = new int[s]; } int int_stack::top() { return array[top_index-1]; } string_stack.cc ( חלקי ): string_stack::string_stack (int s) { top_index = 0 ; size = s ; array = new String[s]; } String string_stack::top() { return array[top_index-1]; } דוגמת המחסנית

22 22 Templateבכדי להימנע משכפול הקוד (ליתר דיוק: כדי לבצע שכפול קוד מבוקר) נעזר ב Template ה-Template מקבל טיפוס(ים) כפרמטר, ויכול להשתמש בפרמטר זה כאילו היה טיפוס רגיל ה Template הנו בעצם תבנית ליצירת מחלקות (מעין “מקרו” מתוחכם). לאחר שהעברנו ל-Template את הטיפוס עמו הוא עובד (ע”י הוספת לשם ה- Template נקבל מחלקה רגילה לכל דבר מחלקות גנריות

23 23 מה קורה בפועל ? כותבים מחלקה שהיא Template כמו שאנחנו כותבים מחלקה רגילה, פרט לתוספת השורה template לפני הגדרת המחלקה כעת נוכל לכתוב את קוד המחלקה תוך שאנחנו מתייחסים ל -T כאל טיפוס כלשהו, שיועבר כפרמטר רק מאוחר יותר בתוך התוכנית, כאשר נירצה להשתמש ב -Template עבור ערך מסוים של T, נעביר את ערך זה גם כן בסוגריים משולשים ( ראו דוגמאות בהמשך ) בזמן הקומפילציה יתבצע שכפול של הקוד שכתבנו עבור ה -Template ובכל מקום שבו מופיע T ייכתב הערך שהועבר ל -Template במקומו

24 24 מחסנית גנרית stack.h: template class stack { int top_index,size; T* array ; public: stack(int s=100) ; void pop() ; void push(T e); T top() ; int size(); }; int_stack.h: class int_stack { int top_index,size; int* array ; public: int_stack(int s) ; void pop() ; void push(int e); int top() ; int size(); };

25 25 מחסנית גנרית stack.h ( חלקי ): template stack ::stack (int s) { top_index = 0 ; size = s ; array = new T[s]; } template T stack :: top() { return array[top_index-1]; } int_stack.cc ( חלקי ): int_stack::int_stack (int s) { top_index = 0 ; size = s ; array = new int[s]; } int int_stack::top() { return array[top_index-1]; }

26 26 שימוש במחסנית הגנרית int main() { stack si(100); stack sc(3); si.push(5); sc.push(“xxx”); sc.push(6); // error ! si.size(); sc.size(); } int main() { int_stack si(100); si.push(5); si.push(“xxx”); // error ! si.size(); }

27 27 Templates Templates הינם כלי מאוד שמושי לצורך הגדרת Containers למרבה הצער המימוש של Templates ב ++C מזכיר macro חכם ולכן כל הקוד של ה Template נמצא ב header file, כפי שהוצג, או כ inline function ישנן לא רק מחלקות שהן גנריות אלא גם פונקציות גנריות

28 28 פונקציות גנריות int major (int a, int b, int c ) { if (a == b || a == c) return a ; if (b == c) return b ; exit(1); } שימוש : int j = major (1,3,3); // ok? char c = major (‘w’,’w’,’w’);//ok? String s1 = major(s1,s2,s3); //ok ? int j = major (1,’a’,’a’); //ok ? template T major (T a,T b, T c ) { if (a == b || a == c) return a ; if (b == c) return b ; exit(1); } שימוש : int j = major (1,3,3); // ok ? char c= major (‘w’,’w’,’w’); //ok? String s1 = major(s1,s2,s3); // ok? int j = major (1,’a’,’a’); //ok ?

29 29 Templates - advanced issues למרות ש ה Template לא “מתעניין” בתכונותיו המיוחדות של הטיפוס המועבר כפרמטר הוא יכול להניח הנחות לגבי קיומם של פונקציות או מתודות מסוימות בו. –אילו הנחות הניח major על T ? אילו stack ? ניתן להעביר כמה טיפוסים שונים בפרמטר: template class hashtable { bool find (const K &k, D &d) ; … };

30 30 פרמטרים ל Template ניתן להעביר ל Template פרמטר שאינו טיפוס. פרמטר יכול להיות מחרוזת, שם פונקציה או קבוע: template class Vector { T vec[Dim] ; … }; Vector v ; Vector v1; Vector v2; Vector v3 ; מה היתרון בכך שגודל ה buffer הנו חלק מהטיפוס ? (רמז מה יקרה ב v=v3 ? )

31 31 Templates - advanced issues טיפוס שנוצר ע ” י template הינו טיפוס לכל דבר. אולם בדרך כלל כתיבת שמו המלא מסובכת לכן נעזרים בקיצור הבא : typedef stack stack_int ; אם נרצה להגדיר מחסנית של מחסניות אזי נגדיר את הטיפוס typedef stack stack_stack_int; ונעזר בו : stack_int s1(100); stack_stack_int s2(5); s2.push(s1); // in this case push should have better // accepted const T& instead of T...


Download ppt "1 נושאי התרגול : Copy constructorCopy constructor Assignment operatorAssignment operator המרת טיפוסים אוטומטיות המרת טיפוסים אוטומטיות תכנות גנרי – Templates."

Similar presentations


Ads by Google