38
1 ללללל לללללל: - ייייי ייייTemplates ייייי יייייייייייי

1 נושאי התרגול : תכנות גנרי - Templates ירושה ופולימורפיזם

  • View
    225

  • Download
    6

Embed Size (px)

Citation preview

Page 1: 1 נושאי התרגול : תכנות גנרי - Templates ירושה ופולימורפיזם

1

:נושאי התרגול

Templatesתכנות גנרי - •

ירושה ופולימורפיזם•

Page 2: 1 נושאי התרגול : תכנות גנרי - Templates ירושה ופולימורפיזם

2

Templatesתכנות גנרי -

- מחלקות Containersמשמש בעיקר כאשר בונים •אשר מכילות עצמים אחרים, אולם אין חשיבות

לתכונותיו הייחודיות של אותו עצם: ללא קשר Containerאותן פעולות מוגדרות על ה •

לעצם שבו. לדוגמא עבור מחסנית תמיד יוגדרו :– push– pop– top

.String או int , charללא חשיבות אם זו מחסנית של

Page 3: 1 נושאי התרגול : תכנות גנרי - Templates ירושה ופולימורפיזם

3

דוגמת המחסנית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();

};

Page 4: 1 נושאי התרגול : תכנות גנרי - Templates ירושה ופולימורפיזם

4

דוגמת המחסנית

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];

}

Page 5: 1 נושאי התרגול : תכנות גנרי - Templates ירושה ופולימורפיזם

5

מחלקות גנריותבכדי להימנע משכפול הקוד (ליתר דיוק: כדי לבצע •

.Templateשכפול קוד מבוקר) נעזר ב מקבל טיפוס(ים) כפרמטר, ויכול Templateה-•

להשתמש בפרמטר שכזה כאילו היה טיפוס רגיל. הנו בעצם תבנית ליצירת מחלקות (מעין Templateה •

את Template“מקרו” מתוחכם). לאחר שהעברנו ל-הטיפוס עמו הוא עובד (ע”י הוספת > טיפוס < לשם

מחלקה רגילה לכל דבר. נקבלTemplateה-

Page 6: 1 נושאי התרגול : תכנות גנרי - Templates ירושה ופולימורפיזם

6

מה קורה בפועל? כמו שאנחנו כותבים Templateאנחנו כותבים מחלקה שהיא •

>template <class Tמחלקה רגילה, פרט לתוספת השורה לפני הגדרת המחלקה.

Tכעת נוכל לכתוב את קוד המחלקה תוך שאנחנו מתייחסים ל-•כאל טיפוס כלשהו, שיועבר כפרמטר רק מאוחר יותר.

Templateבתוך התוכנית, כאשר אנחנו רוצים להשתמש ב-•, מעבירים את הערך הזה גם כן Tעבור ערך מסוים של

בסוגריים משולשים )ראו דוגמאות בהמשך(.מה שיקרה הוא שבזמן הקומפילציה יתבצע שכפול של הקוד •

ייכתב T ובכל מקום שבו מופיע Templateשכתבנו עבור ה- במקומו.Templateהערך שהועבר ל-

Page 7: 1 נושאי התרגול : תכנות גנרי - Templates ירושה ופולימורפיזם

7

מחסנית גנריתstack.h:template <class T>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();

};

Page 8: 1 נושאי התרגול : תכנות גנרי - Templates ירושה ופולימורפיזם

8

מחסנית גנריתstack.h (חלקי):

template >class T<

stack>T<::stack (int s) {

top_index = 0 ; size = s ;

array = new T[s];

}

template >class T<

T

stack>T<:: 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];

}

Page 9: 1 נושאי התרגול : תכנות גנרי - Templates ירושה ופולימורפיזם

9

שמוש במחסנית הגנריתint main() {

stack>int< si(100);stack>char*< 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();

}

Page 10: 1 נושאי התרגול : תכנות גנרי - Templates ירושה ופולימורפיזם

10

Templates

•Templates הינם כלי מאוד שמושי לצורך .Containersהגדרת

ב +Templatesלמרבה הצער המימוש של •+C מזכיר macro חכם ולכן כל הקוד של ה

Template נמצא ב header file כפי שהוצג או ..inline functionכ

ישנן לא רק מחלקות שהן גנריות אלא גם •פונקציות גנריות.

Page 11: 1 נושאי התרגול : תכנות גנרי - Templates ירושה ופולימורפיזם

11

פונקציות גנריות

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 >class T<

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 ?

Page 12: 1 נושאי התרגול : תכנות גנרי - Templates ירושה ופולימורפיזם

12

Templates - advanced issues

לא “מתעניין” בתכונותיו Templateלמרות ש ה •ניח יכול לההמיוחדות של הטיפוס המועבר כפרמטר הוא

הנחות לגבי קיומם של פונקציות או מתודות מסוימות בו. ? stack ? אילו T על majorאילו הנחות הניח –

ניתן להעביר כמה טיפוסים שונים בפרמטר:•template >class K, class D< class hashtable {

bool find (const K &k, D &d) ;…

};

Page 13: 1 נושאי התרגול : תכנות גנרי - Templates ירושה ופולימורפיזם

13

Templateפרמטרים ל ל להעביר . Templateניתן פרמטר טיפוס שאינו פרמטר

, קבוע או פונקציה שם מחרוזת להיות :יכולtemplate >class T, int Dim< class Vector {

T vec[Dim] ;…

};

Vector>int, 5< v ; Vector > double, 12 < v1; Vector >Complex, 3< v2; Vector >int , 6< v3 ;

ה שגודל בכך היתרון מהטיפוס ? bufferמה חלק הנוב) יקרה מה ? (v=v3רמז

Page 14: 1 נושאי התרגול : תכנות גנרי - Templates ירושה ופולימורפיזם

14

Templates - advanced issues הינו טיפוס לכל דבר. אולם templateטיפוס שנוצר ע”י

בדרך כלל כתיבת שמו המלא מסובכת לכן נעזרים בקיצור הבא:

typedef stack>int< stack_int ;

אם נרצה להגדיר מחסנית של מחסניות אזי נגדיר את הטיפוס

typedef stack>stack_int< 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 ...

Page 15: 1 נושאי התרגול : תכנות גנרי - Templates ירושה ופולימורפיזם

15

הורשה הורשה ופולימורפיזםופולימורפיזם

צורה

עיגולריבוע משושה

Page 16: 1 נושאי התרגול : תכנות גנרי - Templates ירושה ופולימורפיזם

16

מוטיבציה:מוטיבציה:אפליקציית חלונות טיפוסית – נעזרת בפקדים

(Widgets)

Button

Textbox

Label

Form

Page 17: 1 נושאי התרגול : תכנות גנרי - Templates ירושה ופולימורפיזם

17

פקדים הם אובייקטים לכל דבר, ומוגדרים •.GUIבספריות מיוחדות שמספקות ממשקי

לפקדים שראינו יש תכונות משותפות:• על גבי הטופס.x,yקוארדינטות –אורך ורוחב.–טקסט.–

כמו כן אפשר לחשוב על פונקציות משותפות:•שינוי טקסט/גודל/מיקום.–הסתרה.–נעילה.–ציור.–

Page 18: 1 נושאי התרגול : תכנות גנרי - Templates ירושה ופולימורפיזם

18

היינו רוצים להגדיר אובייקט שייקרא "פקד" •ויכיל את כל התכונות המשותפות הללו.

לאחר מכן, כאשר מגדירים כל אחד מהפקדים •הספציפיים )כפתור, תיבת טקסט...( נוכל

להשתמש באובייקט ה"פקד" הכללי שלנו כדי לציין את התכונות המשותפות הללו.

המטרה: התוכנית שלנו תוכל לחשוב על •"כפתור" גם כעל "פקד", בלי להתעניין

בתכונות הספציפיות של "כפתור".בשביל מה זה טוב?•

Page 19: 1 נושאי התרגול : תכנות גנרי - Templates ירושה ופולימורפיזם

19

( מכיל רשימה של כל הפקדים formאובייקט טופס )•שנמצאים על הטופס.

רשימה לכל אחד מסוגי הפקדים מה עדיף?•, או רשימה של *voidהאפשריים, רשימה של אובייקטים מסוג "פקד"?

נניח שצריך לצייר את כל הטופס מחדש. הטופס •יצטרך לקרוא לפונקצית הציור של כל אחד מהפקדים

שנמצאים בו.מה עדיף? לבצע קריאה מיוחדת לפונקצית הציור •

לכל סוג אפשרי של פקד, או לתת את אותה פקודת ציור לכולם, אבל ש"בדרך קסם" כל אחד מהם יפעל

בצורה המתאימה לו?

Page 20: 1 נושאי התרגול : תכנות גנרי - Templates ירושה ופולימורפיזם

20

הורשה בתוכנית.is-ais-aהורשה הינה הדרך בה מביעים יחסי

:שונותנעזרים בהורשה לצורך שתי מטרות •code reusecode reuse כאשר נרצה כי מספר מחלקות יהיו -

בעלות התנהגות זהה, כולן תירשנה ממחלקת אב משותפת אשר תממש התנהגות זו. בדרך זו נימנע

משכפול של הקוד.•polymorphic behaviorpolymorphic behavior כאשר נרצה כי מספר -

מחלקות יחשפו ממשק זהה אך יתנהגו בצורה שונה. בשני המקרים, ההורשה תאפשר לנו להתייחס לכל •

אובייקט בן כאילו היה מטיפוס אובייקט האב.

Page 21: 1 נושאי התרגול : תכנות גנרי - Templates ירושה ופולימורפיזם

21

?is-aמה זה נניח ש"כפתור" יורש מ"פקד". במקרה זה אומרים •

פקד" )באנגלית זה נשמע יותר טוב(. is-aש"כפתור בעברית: "כפתור הוא סוג מיוחד של פקד".

פירוש הדבר הוא שבכל מקום שבו ניתן להשתמש •בפקד, אפשר להשתמש גם בכפתור.

למשל, אם יש לנו פונקציה שמקבלת פקד כפרמטר, •אפשר להעביר כפתור בתור אותו פרמטר. הפונקציה תתייחס לכפתור כאל פקד )כלומר, תתייחס לתכונות

של הכפתור שמשותפות לכל הפקדים, ולא תתעניין בתכונות הייחודיות לכפתור(.

( – היחידה publicכל זה נכון רק להורשה ציבורית )•שנלמד בקורס הזה.

Page 22: 1 נושאי התרגול : תכנות גנרי - Templates ירושה ופולימורפיזם

22

הורשה לשם שימוש מחדש בקוד

הידועה את הפונקציה:Stackנרצה להוסיף למחלקה •( popk(int k - אשר תוציא מהמחסניתk .איברים

.MultiStackלמחלקה המשופרת נקרא

קיימות שלוש דרכים לבצע זאת:(.cut & paste מהתחלה )MultiStack לכתוב את • כשדה.Stack להיעזר ב-•.Stack לרשת מ-•

Page 23: 1 נושאי התרגול : תכנות גנרי - Templates ירושה ופולימורפיזם

23

כשדה Stackשימוש באובייקט I

class MultiStack{

public:

MultiStack(int sz) : _s(sz)}{

~ MultiStack}{ )(

void push(int i) {_s.push(i);}

void pop() { _s.pop() ; }

int top() { return _s.top();}

int empty() {return _s.empty();}

void popk(int k); private:

Stack _s;

;}

עבור כל פונקציה מקורית של •Stack נדרש לכתוב פונקצית

מעטפת אשר תפנה את הקריאות לאובייקט המחסנית

הפנימי.לקורא הקוד לא ברור •

היא MultiStackמהתוכנית כי סוג מיוחד של מחסנית.

כיצד נראה המימוש של •popk לא נוכל לייעל את ?

העבודה ע”י גישה ישרה למבני הנתונים של המחסנית

הוא פתרון ?(friend)האם

Page 24: 1 נושאי התרגול : תכנות גנרי - Templates ירושה ופולימורפיזם

24

כשדה Stackשימוש באובייקט II

בעיה נוספת לשיטה זו: אם יש לנו קוד כתוב אשר נעזר במחסניות )מקבל כפרמטר מצביע או

reference לאובייקט מטיפוס Stack לא נוכל לשלוח ) .Stackאינו MultiStack כפרמטר כי MultiStackלו

int sumAndPop(Stack & s){

int s = 0 ;

while (! s.empty()) { s+=s.top(); s.pop() ;}

return s;

}

Page 25: 1 נושאי התרגול : תכנות גנרי - Templates ירושה ופולימורפיזם

25

Stackירושה מ

class MultiStack :

public Stackpublic Stack{ {

public:

MultiStack (int sz) :

Stack(sz)Stack(sz)}{ }{

~ MultiStack }{ )(

popk(int k);

;}

בכדי להביע כי •MultiStack הינו סוג נגדיר Stackמיוחד של

כיורש מ MultiStackאת Stack.

באופן זה כל הפונקציות • מוגדרות Stackשל

באופן אוטומטי )עם אותה משמעות( עבור

. MultiStackהמחלקה

Page 26: 1 נושאי התרגול : תכנות גנרי - Templates ירושה ופולימורפיזם

26

Stackירושה מ

)היחידה אותה נלמד( גורמת publicירושה כ • MultiStackלכך שכל משתמש של המחלקה

Stackיוכל להיעזר במתודות של המחלקה .MultiStack במתודות של וגם

יוכל להיעזר ב- Stackכל משתמש של •MultiStack-כב Stack.רגיל

Page 27: 1 נושאי התרגול : תכנות גנרי - Templates ירושה ופולימורפיזם

27

ירושה ובונים והורסיםבכל פעם שיוצרים אובייקט מהסוג היורש אנו בעצם •

.Cיוצרים גם אובייקט מסוג אב. זהו המימוש ב ++

של האב, שנקרא C’torאתחול שדות האב )ע”י ה-•דרך שורת האתחול של הבן( נעשה לפני יצירת שדה

של הבן.c’torכלשהו של בנו, ובפרט לפני שנקרא הריסת האב נעשית לאחר הריסת בנו ובפרט אחרי •

d’tor.של הבן

שדות של

האב

שדות הבן של

אובייקט אב

בן אובייקט

Page 28: 1 נושאי התרגול : תכנות גנרי - Templates ירושה ופולימורפיזם

28

protected fields

איך נראית הפונקציה •popk האם ניתן ?

לגשת לשדות המימוש ?Stackשל המחלקה

כדי שבמחלקה •היורשת ניתן יהיה

לגשת לשדות של האב יש להגדיר את השדות

.protectedכ

privateשדות )ופונקציות( •ניתנים לגישה ע”י פונקציות של

.friendsהמחלקה ו protected( ופונקציות)שדות •

ע”י הקודמים + מחלקות יורשות

class Stack {

public.… :

protected:

int* array ;

int top_index, size;

;}

Page 29: 1 נושאי התרגול : תכנות גנרי - Templates ירושה ופולימורפיזם

29

גישה לשדות בהורשה גישה לשדות בהורשה publicpublic ) )מסוגמסוג((

StackStack Private Members Protected Members Public Members

MultiStackMultiStack Private MembersProtected Members Public Members

MultiMultiStackMultiMultiStack Private MembersProtected Members Public Members

User

Page 30: 1 נושאי התרגול : תכנות גנרי - Templates ירושה ופולימורפיזם

31

ירושה פולימורפיתבדוגמאות הקודמות האב והבן חלקו את אותה •

התנהגות. התנהגות זו הייתה תקפה לשתי המחלקות ולכן שתי המחלקות חלקו:

את אותו ממשק: אותה חתימה וערך מוחזר של הפונקציה.–את אותו מימוש: אותו קוד פעל בשניהם.–

לעיתים צורת התנהגות זו לא טובה לנו ונרצה •שלמרות שניתן יהיה לפנות לבן כמו שפונים לאב )ובפרט שישתפו את הממשק( הבן יתנהג בצורה

שונה.

Page 31: 1 נושאי התרגול : תכנות גנרי - Templates ירושה ופולימורפיזם

32

מחלקות מעולם החי כדוגמא למחלקות בעלות התנהגות

פולימורפית. חיה

. לידה , , ת גובה משקלמזון סוגי הדפס

קול השמע

Page 32: 1 נושאי התרגול : תכנות גנרי - Templates ירושה ופולימורפיזם

33

מחלקות בעלות התנהגות Iפולימורפית

class Animal{

public:

int getAge; )(

virtual void makeSound;)(

private:

int weight,age;

;}

class Dog : public Animal{

void makeSound; )(

; }

כל בעלי החיים חולקים •דברים משותפים:

לכולם יש משקל, גובה, –גיל

כולם אוכלים ומשמיעים –קולות

נרצה לתאר מחלקות •מעולם החי בתוכניתנו

ולהראות קשר זהיחד עם זאת לאפשר •

גמישות של התנהגות שונה כאשר הדבר נדרש

Page 33: 1 נושאי התרגול : תכנות גנרי - Templates ירושה ופולימורפיזם

34

מחלקות בעלות התנהגות IIפולימורפית

ניתן במחלקה היורשת ממחלקה אחרת •להגדיר מחדש פונקציות אשר הוגדרו

במחלקת האב. אולם הדבר יגרום לכך שהפונקציה שתיקרא •

תלויה בדרך בא קראנו לה:Dog * d = new Dog;)(Animal * a = d ; a-<makeSound(); d-<makeSound; )(

אם נרצה שההתנהגות השונה תחול גם •כאשר ניגשים לפונקציה דרך מצביע לאב -

נעזר בפונקציות ווירטואליות.

Page 34: 1 נושאי התרגול : תכנות גנרי - Templates ירושה ופולימורפיזם

35

מחלקות בעלות התנהגות IIIפולימורפית

כאשר מגדירים פונקציה וירטואלית בעצם אומרים •שהאופן המדויק בו יתנהג האובייקט תלוי בטיפוס הבן

עימו אנו עובדים. למי שנעזר באובייקט האב לא משנה מה הטיפוס המדויק של הבן והוא יכול לעבוד עם כולם

באופן אחיד.

class Cat : public Animal{

public:

void makeSound{ )(

cout >> “miao\n;”

}

; }

class Dog : public Animal{

public:

void makeSound{ )(

cout >> “vuf vuf\n;”

}

; }

Page 35: 1 נושאי התרגול : תכנות גנרי - Templates ירושה ופולימורפיזם

36

מחלקות בעלות התנהגות פולימורפית IV

main{ )(

Animal* dog = new Dog;)(

Animal* cat = new Cat;)(

Animal* whoami = new Bear;)(

dog-<makeSound;)(

cat-<makeSound;)(

whoami-<makeSound;)(

}

פלט התוכנית

vuf vuf

miao

orrrr

Page 36: 1 נושאי התרגול : תכנות גנרי - Templates ירושה ופולימורפיזם

37

שיטה חליפית להתנהגות פולימורפית

. לכל חיה type מקובל להיעזר בשדות Cב •היינו שומרים קוד משלה, ובכל פונקציה

ענק שהיה switchהיינו נעזרים במשפט אומר מה לעשות לכל טיפוס.

הבעיות בגישה זו הינן שבכל פעם שנרצה •להוסיף חיה למערכת נדרשת לשנות קוד

בהרבה פונקציות - מאוד רגיש ובעייתי.

Page 37: 1 נושאי התרגול : תכנות גנרי - Templates ירושה ופולימורפיזם

38

Abstract Classesקיימות מחלקות המייצגות רעיון מופשט ויש •

להן משמעות רק כבסיס למחלקות אחרות

)אחת או Pure Virtualמחלקה עם מתודה •מחקלה אבסטרקטיתיותר( היא

לא ניתן ליצור אובייקטים של מחלקה שכזו•

class Shape{ public:

Shape(int x, int y) : center_x(x),center_y(y)}{

virtual double area() const = 0;protected:int center_x, center_y;

;}

Page 38: 1 נושאי התרגול : תכנות גנרי - Templates ירושה ופולימורפיזם

39

class Shape{ public:

Shape(int x, int y) : center_x(x),center_y(y)}{

virtual double area() const = 0;protected:int center_x, center_y;

;}

class Circle: public Shape{ public:

Circle(int x, int y, int r): Shape(x,y), radius(r) }{

double area() const {return (PI*radius*radius)};private: int radius ;

; }

class Rect: public Shape{ public:

Rect(int x, int y, int h, int w): Shape(x,y),height(h),width(w)}{

double area() const {return (height*width)};

private: int height, width;

; }

דוגמא מסכמת: צורותדוגמא מסכמת: צורות