1 ההההה ההההה הההההההההההה הההההההההההה ררר ר ררר רר ררר רר ררררר
Jan 12, 2016
1
הורשה הורשה ופולימורפיזםופולימורפיזם
צורה
עיגולריבוע משושה
2
מוטיבציה:מוטיבציה:אפליקציית חלונות טיפוסית – נעזרת בפקדים
(Widgets)
Button
Textbox
Label
Form
3
פקדים הם אובייקטים לכל דבר, ומוגדרים.GUIבספריות מיוחדות שמספקות ממשקי
:לפקדים שראינו יש תכונות משותפות קוארדינטותx,y.על גבי הטופס .אורך ורוחב.טקסט
:כמו כן אפשר לחשוב על פונקציות משותפות.שינוי טקסט/גודל/מיקום.הסתרה.נעילה.ציור
4
"היינו רוצים להגדיר אובייקט שייקרא "פקדויכיל את כל התכונות המשותפות הללו.
לאחר מכן, כאשר מגדירים כל אחד מהפקדיםהספציפיים )כפתור, תיבת טקסט...( נוכל
להשתמש באובייקט ה"פקד" הכללי שלנו כדי לציין את התכונות המשותפות הללו.
המטרה: התוכנית שלנו תוכל לחשוב על"כפתור" גם כעל "פקד", בלי להתעניין
בתכונות הספציפיות של "כפתור".?בשביל מה זה טוב
5
( אובייקט טופסform מכיל רשימה של כל הפקדים )שנמצאים על הטופס.
?רשימה לכל אחד מסוגי הפקדים מה עדיף, או רשימה של *voidהאפשריים, רשימה של אובייקטים מסוג "פקד"?
נניח שצריך לצייר את כל הטופס מחדש. הטופסיצטרך לקרוא לפונקצית הציור של כל אחד מהפקדים
שנמצאים בו. מה עדיף? לבצע קריאה מיוחדת לפונקצית הציור
לכל סוג אפשרי של פקד, או לתת את אותה פקודת ציור לכולם, אבל ש"בדרך קסם" כל אחד מהם יפעל
בצורה המתאימה לו?
6
הורשה בתוכנית.is-ais-aהורשה הינה הדרך בה מביעים יחסי
:שונותנעזרים בהורשה לצורך שתי מטרות code reusecode reuse כאשר נרצה כי מספר מחלקות יהיו -
בעלות התנהגות זהה, כולן תירשנה ממחלקת אב משותפת אשר תממש התנהגות זו. בדרך זו נימנע
משכפול של הקוד.polymorphic behaviorpolymorphic behavior כאשר נרצה כי מספר -
מחלקות יחשפו ממשק זהה אך יתנהגו בצורה שונה. בשני המקרים, ההורשה תאפשר לנו להתייחס לכל
אובייקט בן כאילו היה מטיפוס אובייקט האב.
7
?is-aמה זה נניח ש"כפתור" יורש מ"פקד". במקרה זה אומרים
פקד" )באנגלית זה נשמע יותר טוב(. is-aש"כפתור בעברית: "כפתור הוא סוג מיוחד של פקד".
פירוש הדבר הוא שבכל מקום שבו ניתן להשתמשבפקד, אפשר להשתמש גם בכפתור.
,למשל, אם יש לנו פונקציה שמקבלת פקד כפרמטראפשר להעביר כפתור בתור אותו פרמטר. הפונקציה תתייחס לכפתור כאל פקד )כלומר, תתייחס לתכונות
של הכפתור שמשותפות לכל הפקדים, ולא תתעניין בתכונות הייחודיות לכפתור(.
( כל זה נכון רק להורשה ציבוריתpublic היחידה – )שנלמד בקורס הזה.
8
הורשה לשם שימוש מחדש בקוד
הידועה את הפונקציה:Stackנרצה להוסיף למחלקה ( popk)int k - אשר תוציא מהמחסניתk .איברים
.MultiStackלמחלקה המשופרת נקרא
קיימות שלוש דרכים לבצע זאת: לכתוב את MultiStack( מהתחלה cut & paste.)-להיעזר ב Stack.כשדה -לרשת מ Stack.
9
כשדה 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)האם
10
כשדה Stackשימוש באובייקט II
בעיה נוספת לשיטה זו: אם יש לנו קוד כתוב אשר נעזר במחסניות )מקבל כפרמטר מצביע או
reference לאובייקט מטיפוס Stack לא נוכל )אינו MultiStack כפרמטר כי MultiStackלשלוח לו
Stack.
int sumAndPop)Stack & s( {
int s = 0;
while )! s.empty)(( { s+=s.top)(; s.pop)( ;}
return s ;
}
11
Stackירושה מ
class MultiStack :
public Stack {public Stack {
public:
MultiStack )int sz( :
Stack(sz) {}Stack(sz) {}
~MultiStack)( {}
popk)int k( ;
};
בכדי להביע כיMultiStack הינו סוג נגדיר Stackמיוחד של
כיורש מ MultiStackאת Stack.
באופן זה כל הפונקציות מוגדרות Stackשל
באופן אוטומטי )עם אותה משמעות( עבור
. MultiStackהמחלקה
12
Stackירושה מ
ירושה כpublic היחידה אותה נלמד( גורמת( MultiStackלכך שכל משתמש של המחלקה
וגם Stackיוכל להיעזר במתודות של המחלקה .MultiStackבמתודות של
כל משתמש שלStack -יוכל להיעזר ב MultiStack-כב Stack.רגיל
13
ירושה ובונים והורסים בכל פעם שיוצרים אובייקט מהסוג היורש אנו בעצם
.Cיוצרים גם אובייקט מסוג אב. זהו המימוש ב ++
-אתחול שדות האב )ע”י הC’tor של האב, שנקרא דרך שורת האתחול של הבן( נעשה לפני יצירת שדה
של הבן.c’torכלשהו של בנו, ובפרט לפני שנקרא הריסת האב נעשית לאחר הריסת בנו ובפרט אחרי
d’tor.של הבן
שדות של האב
שדות הבן של
אובייקט אב
בן אובייקט
14
protected fields
איך נראית הפונקציהpopk האם ניתן ?
לגשת לשדות המימוש ?Stackשל המחלקה
כדי שבמחלקההיורשת ניתן יהיה
לגשת לשדות של האב יש להגדיר את השדות
.protectedכ
(ופונקציות) שדותprivate ניתנים לגישה ע”י פונקציות של
.friendsהמחלקה ו ( ופונקציות)שדותprotected
ע”י הקודמים + מחלקות יורשות
class Stack {
public : ….
protected :
int* array;
int top_index, size ;
};
15
גישה לשדות בהורשה גישה לשדות בהורשה publicpublic ( (מסוגמסוג))
StackStack Private Members Protected Members Public Members
MultiStackMultiStack Private MembersProtected Members Public Members
MultiMultiStackMultiMultiStack Private MembersProtected Members Public Members
User
17
ירושה פולימורפית בדוגמאות הקודמות האב והבן חלקו את אותה
התנהגות. התנהגות זו הייתה תקפה לשתי המחלקות ולכן שתי המחלקות חלקו:
.את אותו ממשק: אותה חתימה וערך מוחזר של הפונקציה.את אותו מימוש: אותו קוד פעל בשניהם
לעיתים צורת התנהגות זו לא טובה לנו ונרצהשלמרות שניתן יהיה לפנות לבן כמו שפונים לאב )ובפרט שישתפו את הממשק( הבן יתנהג בצורה
שונה.
18
מחלקות מעולם החי כדוגמא למחלקות בעלות התנהגות
פולימורפית. חיה
. לידה , , ת גובה משקלמזון סוגי הדפס
קול השמע
19
מחלקות בעלות התנהגות Iפולימורפית
class Animal {
public:
int getAge)( ;
virtual void makeSound)(;
private:
int weight,age ;
};
class Dog : public Animal{
void makeSound)( ;
} ;
כל בעלי החיים חולקיםדברים משותפים:
,לכולם יש משקל, גובהגיל
כולם אוכלים ומשמיעיםקולות
נרצה לתאר מחלקותמעולם החי בתוכניתנו
ולהראות קשר זה יחד עם זאת לאפשר
גמישות של התנהגות שונה כאשר הדבר נדרש
20
מחלקות בעלות התנהגות IIפולימורפית
ניתן במחלקה היורשת ממחלקה אחרתלהגדיר מחדש פונקציות אשר הוגדרו
במחלקת האב. אולם הדבר יגרום לכך שהפונקציה שתיקרא
תלויה בדרך בא קראנו לה:Dog * d = new Dog)(;Animal * a = d ; a->makeSound)(; d->makeSound)( ;
אם נרצה שההתנהגות השונה תחול גםכאשר ניגשים לפונקציה דרך מצביע לאב -
נעזר בפונקציות ווירטואליות.
21
מחלקות בעלות התנהגות IIIפולימורפית
כאשר מגדירים פונקציה וירטואלית בעצם אומרים שהאופןהמדויק בו יתנהג האובייקט תלוי בטיפוס הבן עימו אנו
עובדים. למי שנעזר באובייקט האב לא משנה מה הטיפוס המדויק של הבן והוא יכול לעבוד עם כולם באופן אחיד.
class Cat : public Animal{
public:
void makeSound)( {
cout << “miao\n”;
}
} ;
class Dog : public Animal{
public:
void makeSound)( {
cout << “vuf vuf\n”;
}
} ;
22
מחלקות בעלות התנהגות פולימורפית IV
main )( {
Animal* dog = new Dog)(;
Animal* cat = new Cat)(;
Animal* whoami = new Bear)(;
dog->makeSound)(;
cat->makeSound)(;
whoami->makeSound)(;
}
פלט התוכנית
vuf vuf
miao
orrrr
23
שיטה חליפית להתנהגות פולימורפית
בC מקובל להיעזר בשדות type לכל חיה . היינו שומרים קוד משלה, ובכל פונקציה היינו
ענק שהיה אומר מה switchנעזרים במשפט לעשות לכל טיפוס.
הבעיות בגישה זו הינן שבכל פעם שנרצהלהוסיף חיה למערכת נדרשת לשנות קוד
בהרבה פונקציות - מאוד רגיש ובעייתי.
24
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 ;
};
25
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;} ;
דוגמא מסכמת: צורותדוגמא מסכמת: צורות
26
int main)( {…Shape* p[N];
// an array of rectangles & circles // initialization…double total_area=0; for )int j = 0; j < N; ++ j total_area += p[j] -> area) (;
}
דוגמא מסכמת: צורותדוגמא מסכמת: צורות
27
Exceptions
הסטייל החדש לטיפול בשגיאות
main)(
return BAD_ARG
catch
throw
BAD_ARG
func)(
28
C Styleint DoSomething)( {
long *a, c; FILE *b; a = malloc)sizeof)long( * 10(; if )a == NULL(
return ERR_MEM; b = fopen)"something.bah", "rb"(; if )b == NULL( {
free)a(; return ERR_FILE;
} fread)a, sizeof)long(, 10, b(; if )a[0] != 0x10( {
free)a(; fclose)b(; return ERR_INPUT;
} fclose)b(; c = a[1]; free)a(; return SUCEES;
}
29
Try-catch-throw
try - הגדרת בלוקExceptionsCatch תפיסת – ExceptionThrow זריקת – Exception
30
<include <iostream.h#?מה פלט התוכניתvoid func)({ throw "ERROR";
cout << "Does this code happened?" << endl;
return;}
int main)( {try{ func)(;}catch )char* string({ cout << string << endl;}cout << "END OF PROGRAM" << endl;return 0;
}
31
Exceptions
// bad_alloc standard exception #include <iostream> #include <exception>
using namespace std;
int main )( { try {
int* myarray= new int[1000]; } catch )exception& e( {
cout << "Standard exception: " << e.what)( << endl; } return 0;
}