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

39
1 ההההה ההההה הההההההההההה הההההההההההה ררר ר ררר רר ררר רר ררררר

Upload: aloysius-caleb

Post on 31-Dec-2015

27 views

Category:

Documents


1 download

DESCRIPTION

הורשה ופולימורפיזם. צורה. ריבוע. משושה. עיגול. מוטיבציה: אפליקציית חלונות טיפוסית – נע זרת בפקדים ( Widgets ). Form. Button. Label. Textbox. פקדים הם אובייקטים לכל דבר, ומוגדרים בספריות מיוחדות שמספקות ממשקי GUI . לפקדים שראינו יש תכונות משותפות: קוארדינטות x,y על גבי הטופס. - PowerPoint PPT Presentation

TRANSCRIPT

Page 1: הורשה   ופולימורפיזם

1

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

צורה

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

Page 2: הורשה   ופולימורפיזם

2

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

(Widgets)

Button

Textbox

Label

Form

Page 3: הורשה   ופולימורפיזם

3

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

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

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

Page 4: הורשה   ופולימורפיזם

4

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

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

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

לציין את התכונות המשותפות הללו.:התוכנית שלנו תוכל לחשוב על המטרה

"כפתור" גם כעל "פקד", בלי להתעניין בתכונות הספציפיות של "כפתור".

?בשביל מה זה טוב

Page 5: הורשה   ופולימורפיזם

5

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

:מימוש

רשימה לכל אחד מסוגי הפקדים האפשריים :Cב- )כאשר נצטרך לזכור איכשהו *voidאו רשימה של

מה הטיפוס האמיתי של כל איבר ברשימה(.

רשימה של אובייקטים מסוג "פקד".++:Cב-

ירושה - מוטיבציה

Page 6: הורשה   ופולימורפיזם

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

אחד מהפקדים שנמצאים בו.:פיתרון

מבצעים קריאה מיוחדת לפונקצית הציור :Cב-לכל סוג אפשרי של פקד.

נותנים את אותה פקודת ציור לכולם, ++:Cב-אבל "בדרך קסם" כל אחד מהם יפעל בצורה

המתאימה לו )עוד על הקסמים הללו בעוד מספר שקפים(

ירושה - מוטיבציה

6

Page 7: הורשה   ופולימורפיזם

7

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

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

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

זו. בדרך זו נימנע משכפול של הקוד.polymorphic behaviorpolymorphic behavior כאשר נרצה כי -

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

בשני המקרים, ההורשה תאפשר לנו להתייחס לכל אובייקט בן כאילו היה מטיפוס אובייקט האב.

Page 8: הורשה   ופולימורפיזם

סינטקס של ירושה:class widget {

int xCoordinate, yCoordinate;String text; … // more fields common to all widgets

public:void draw)(; void hide)(; … // more functionality

// common to all widgets};

class button: public widget {… // additions and specificationsvoid push)(;

};

סינטקס של ירושה public סוג -

הירושה היחיד שנלמד בקורס הזה

8

Page 9: הורשה   ופולימורפיזם

9

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

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

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

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

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

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

בקורס הזה.

Page 10: הורשה   ופולימורפיזם

10

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

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

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

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

Page 11: הורשה   ופולימורפיזם

11

כשדה Stackשימוש באובייקט Iclass MultiStack {

public:

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

~MultiStack)( {}

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

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

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

bool isEmpty)( {

return _s.isEmpty)(; }

void popk(int k) ;private:

Stack _s;

};

חסרונות/פגמים/ליקויים/מגרעות...

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

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

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

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

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

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

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

Page 12: הורשה   ופולימורפיזם

12

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

נעזר במחסניות )מקבל כפרמטר מצביע או reference לאובייקט מטיפוס Stack לא נוכל לשלוח )

.Stackאינו MultiStack כפרמטר כי MultiStackלו

int sumAndPop)Stack & stack( { int sum = 0; while )!stack.isEmpty)(( {

sum+=stack.top)(; stack.pop)( ;

} return sum;}

Page 13: הורשה   ופולימורפיזם

13

הפיתרון הקל והנכון - ירושה מ 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 .

Page 14: הורשה   ופולימורפיזם

14

Stackהורשה מ--ירושה כpublic היחידה אותה נלמד( גורמת(

MultiStackלכך שכל משתמש של המחלקה של המחלקה publicיוכל להיעזר במתודות ה-

MultiStack במתודות של וגם Stack כאילו( (.MultiStack ב-publicהוגדרו כ-

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

Page 15: הורשה   ופולימורפיזם

15

protected fields איך נראית הפונקציה

popk האם ניתן ?לגשת לשדות המימוש

?Stackשל המחלקה כדי שבמחלקה

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

.protectedכ

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

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

protected + ע”י הנ"ל מחלקות יורשות

class Stack {

public : ….

protected :

int* array;

int topIndex, size ;

};

הרשאות גישה וירושה

Page 16: הורשה   ופולימורפיזם

16

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

StackStack Private Members Protected Members Public Members

MultiStackMultiStack Private MembersProtected Members Public Members

MultiMultiStackMultiMultiStack Private MembersProtected Members Public Members

User

Page 17: הורשה   ופולימורפיזם

17

קונפליקט של שמותקונפליקט של שמות

class A { public: … void f) (; void g)int x(; };

class B: public A { public: … void f) (; void g)int x(; };

void B::g)int x({ … f) (; // B גישה לפונקציה של A::g)x(; // A גישה לפונקציה של מחלקת הבסיס … }

הגדרת מתודה עם שם זהה למתודה שקיימת במחלקת האב( את המתודה של האב במחלקה היורשת.override"תבטל" )

-כיצד ניגש לmember function מתודה( של מחלקת האב(כאשר יש פונקציה עם שם זהה במחלקת הבן?

Page 18: הורשה   ופולימורפיזם

18

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

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

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

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

של הבן.d’torה-

שדות של האב

שדות של הבן

אובייקט אב

אובייקט בן

Page 19: הורשה   ופולימורפיזם

של instanceסיכום: סדר בניה של מחלקה

סדר הבנאים בקריאה לבנאי של מחלקה )כולל copy c’tor:)

בנאי מחלקת אב )אם יש כזאת(1.

י השדות - לפי סדר ההצהרה עליהם 2. א\ נ[ ַּב[במחלקה )ולא לפי סדר הקריאה לבנאים

שלהם ברשימת האתחול(

גוף הבנאי של המחלקה.3.

הסדר בהריסה: הפוך.

19

Page 20: הורשה   ופולימורפיזם

20

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

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

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

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

שונה.

Page 21: הורשה   ופולימורפיזם

21

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

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

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

השמע קול

Page 22: הורשה   ופולימורפיזם

class Animal {

public:

int getAge)( ;

virtual void makeSound)(;

private:

int weight,age ;

};

class Dog : public Animal{

void makeSound)( ;

} ;22

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

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

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

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

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

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

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

שהפונקציה באבא וירטואלית

Page 23: הורשה   ופולימורפיזם

23

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

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

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

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

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

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

Page 24: הורשה   ופולימורפיזם

24

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

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

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

class Cat : public Animal{

public:

void makeSound)( {

cout << “miao\n”;

}

} ;

class Dog : public Animal{

public:

void makeSound)( {

cout << “vuf vuf\n”;

}

} ;

Page 25: הורשה   ופולימורפיזם

25

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

void foo )( {

const int arraySize = 3;

Animal* animals[arraySize];

animals[0] = new Dog)(;

animals[1] = new Cat)(;

animals[2] = new Bear)(;

for)int i = 0; i < arraySize; ++i( {

animals[i]->makeSound)(;

}

}

פלט התוכנית

vuf vuf

miao

orrrr

Page 26: הורשה   ופולימורפיזם

26

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

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

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

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

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

Page 27: הורשה   ופולימורפיזם

27

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 ;

};

Pure Virtual Method

Page 28: הורשה   ופולימורפיזם

28

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 Rectangle: public Shape {public:

Rectangle)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;} ;

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

Page 29: הורשה   ופולימורפיזם

29

int main)( {…Shape* shapes[N];

// an array of rectangles & circles // initialization…double totalArea=0; for )int i = 0; i < N; ++i( { totalArea += shapes[i] ->area) (; }

}

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

Page 30: הורשה   ופולימורפיזם

30

Exceptions

הסטייל החדש לטיפול בשגיאות

main)(

return BAD_ARG

catch

throw

BAD_ARG

func)(

Page 31: הורשה   ופולימורפיזם

חריגות - מוטיבציהפונקציה שאמורה להחזיר ערך מטיפוס כלשהו, 1.

ויכולה להחזיר את כל טווח הערכים של הטיפוס, איך תבטא שגיאה?

:Cפיתרונות ב- .החזרת ערכי שגיאה בפרמטרים מיוחדים למטרה זו

הרחבת טווח ערכי ההחזרה ושמירה על ערכיםמיוחדים )מחוץ לטווח טיפוס ההחזרה המקורי(

לשגיאה.

.החזרת טיפוס מיוחד

int function)…( int function)…, Result* res(

int function)…( long long int function)…(

int function)…( Result function)…(

31

Page 32: הורשה   ופולימורפיזם

איזה ערך שגיאה תחזיר פונקציה שאינה מחזירה אף .2 במקרה של c’torערך? למשל, מה אמור להחזיר

כישלון בהקצאת זיכרון )דינמי( לשדותיו, לדוגמה? דוגמה נוספת לפונקציה שקשה\מסורבל\לא הגיוני

שתחזיר ערכי שגיאה: אופרטורים למיניהם.

איזה ערך מייצג שגיאה עבור אופרטור חילוק של שברים ? ואם האופרטור אמור 0כדי לייצג שגיאת חלוקה ב-

להחזיר רפרנס, לאיזה אובייקט נחזיר רפרנס במקרה של שגיאה?

חריגות – מוטיבציה )המשך(

32

Page 33: הורשה   ופולימורפיזם

c שקוראת לפונקציה b קוראת פונקציה aאם פונקציה .4 אשר רק zוכך הלאה והתגלתה שגיאה בפונקציה

אחראית\יודעת איך לטפל בה, אנחנו aפונקציה כמתכנתים נצטרך לכתוב כמות )עצומה( של קוד

"לטפל מבלי לטפל" בשגיאות ברמות הביניים, שאינן יודעות\מעוניינות לטפל בשגיאות.

חריגות – מוטיבציה )המשך(

Function Calls:a)( => b)( => …. =>z)(

Error found in z)( only possible/correct to deal with at a)(.

33

Page 34: הורשה   ופולימורפיזם

חריגות – סמנטיקה:לאפשר העברת ערך שגיאה לרמה הרעיון

שיכולה ומעוניינת לטפל, תוך דילוג על שלבי הביניים.

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

d’tor)תוך שחרור משתנים מקומיים בעזרת ה- המכיל אותה try-catchשלהם( עד לבלוק ה-

הראשון שמתייחס לשגיאה זו.

34

Page 35: הורשה   ופולימורפיזם

35

Try-catch-throw try - הגדרת בלוק בו ייתכנוExceptionscatch תפיסת – Exceptionthrow זריקת – Exception

try {

throw 20;// or more interesting code that might throw)(

}

catch )int param( { cout << "int exception"; }

catch )char param( { cout << "char exception"; }

catch )...( { cout << "default exception"; }

חריגות – סינטקס

Page 36: הורשה   ופולימורפיזם

חריגות – סינטקס )המשך(תיקון לאופרטור[ ] שהגדרנו

:Stringל-(:9לפני )שיעור

void error)const char* str( {cerr << str << endl;exit )1(;

}

char String::operator[](int i) const { if ))i < 0( || )i > length(({ error)"String: index out of range"(; } return value[i];}

char String::operator[](int i) const { if ))i < 0( || )i > length(({

throw "String: index out of range"; } return value[i];}

(:11)שיעור אחרי

36

Page 37: הורשה   ופולימורפיזם

:הערות חשובות

לא תיתכננה שתי חריגות במקביל בתוכנית, לכן מומלץ 1.שלא לזרוק חריגות בהורסים.

נקראים ההורסים רק למשתנים מקומיים, לא לזיכרון 2.שהקוצה דינמית )קיימים פתרונות לבעיה זו. בשיעור

הבא נראה אחד כזה(

מותר לזרוק כל טיפוס, כאשר בתפיסתו, אם משתמשים 3..copy c’tor, ייקרא ה-by value semanticsב-

חריגות )המשך(

37

Page 38: הורשה   ופולימורפיזם

38

<include <iostream.h#?מה פלט התוכניתvoid foo)({ throw "ERROR"; cout << “Is this code executed ?" << endl; return;}

int main)( {try{ foo)(;} catch )const char* string({ cout << string << endl;}cout << "END OF PROGRAM" << endl;return 0;

}

Page 39: הורשה   ופולימורפיזם

39

ExceptionsC++’s answer to C’s if)malloc)…( == NULL(

// bad_alloc standard exception #include <iostream> #include <exception>

using namespace std;

int main )( { try { for);;({

new int[10000000]; }

} catch )exception& e( { cout << "Standard exception: " << e.what)( << endl;

} }