C++ ו-OOP למתכנת המקצועי

383, [17] עמודים : איורים ; 24 ס"מ + 1 תקליטון. – ISBN 965-361-142-9

OCR (הסבר)
++:) ו- ?()() למתכנת המקצועי הוראות התקנה והפעלה של הדיסקט תמצא בנספח. עיין בהן בתשומת לב לפני ההתקנה. במהלך הספר תמצא התייחסות לקבצים. עורך ראשי: יצחק עמיהוד עריכה מקצועית : צור ריכטר-לוין עריכה לשונית ועיצוב: שרה עמיהוד עיצוב עטיפה : סטודיו מצגר שמות מסחריים שמות המוצריס והשירותים המוזכריס בספר הינס שמות מסחרייס רשומיס של החברות שלהס. הוצאת הוד-עמי עשתה כמיטב יכולתה למסור מידע אודות השמות המסחרייס המוזכריס בספר גה ולציין את שמות החברות, המוצריס והשירותיס. שמות מסחרייס רשומיס (17400141%8 16818%0700) המוזכריס בספר צוינו בהתאמה. הודעה ספר זה מיועד לתת מידע אודות מוצרים שונים. נעשו מאמצים רביס לגרום לכך שהספר יהיה שלם ואמין ככל שניתן, אך אין משתמעת מכך כל אחריות שהיא. המידע ניתן ''כמות שהוא'' (" 5"). הוצאת הוד-עמי אינה אחראית כלפי יחיד או ארגון עבור כל אובדן או נזק אשר ייגרם, אם ייגרם, מהמידע שבספר זִּה, או מהדיסקט שמצורף לו. לשם שטף הקריאה כתוב ספר זה בלשון זכר בלבד. ספר זה מיועד לגברים ונשים כאחד ואין בכוונתנו להפלות או לפגוע בציבור המשתמשים/ות. ב טלפון: 09-9564716 24 שעות נ) פקס: 09-9571582 24 שעות ב דואר אלקטרוני: [1.60.1ההה-200 11000 ב) אתר באינטרנט : [60.1.גַזגּ-100. אוע +ד;), ?()() למתכנת המקצועי שמעון כהן תותג זט 0 07326060 6+ 107 2027) מה ++?) 606 תסומות5 ץע ונת א .1 :107 (6) כל הזכויות שמורות הוצאת הוד-עמי לספרי מחשבים בע''ימ ת.ד. 6108 הרצליה 46160 טלפון: 09-9564716 פקס: 09-9571582 אין להעתיק או לשדר בכל אמצעי שהוא ספר זה או קטעים ממנו בשום צורה ובשום אמצעי אלקטרוני או מכני, לרבות צילום והקלטה, אמצעי אחסון והפצת מידע, ללא אישור בכתב מאת ההוצאה, אלא לשם ציטוט קטעים קצרים בציון שם המקור. הודפס בישראל תשנייו, 1997 6 ות || זאא-פס 8 .ץק 7 ,1 מסת'יב 965-361-142-9 א150 תוכן עניינים מקוצר תוכן העניינים 2 מבוא 7-00 פרק 1 סקירה של 6 00 05 23 פרק 2 תכנות מוכוון אובייקטים 0 פרק 3 המחלקה 1 פרק 4 קלט ופלט 1 פרק 5 ירושה ככלי לשימוש חוזר בקוד 1 פרק 6 פולימורפיזם 03 פרק 7 תבניות ב-++6 ב- 179 פרק 8 טיפול בשגיאות ועוד 22 פרק 9 חידושים ב-++6 2 פרק 10 ספריית התבניות הסטנדרטיות - 511 2 פרק 11 מבני נתונים סדרתיים ב- 511 2 פרק 12 מבנים שאינם סדרתיים ב- 511 3 פרק 13 שילוב סוגי תכנות 0 נספח - דיסקט התוכניות המצורף 3 אינדקס עברי 3 אינדקס לועזי ב תוכן ענייניס מקוצר 5 תוכן העניינים על ++6 5-0 שב פס 2 ל לבפ ספיט סש מ פטס מש ב מ במ 17 על הספר ומה שיש בו - ו הדיסקט המצורף 8 סקירה של שפת 6 1 הקדמה והיסטוריה || 2 תוכנית ראשונה לבל 1 העברת ארגומנטיס לתוכנית הראשית [/|/|/// 0 2 הערות 0 3 משתניס ופעולות אריתמטיות 0 1 מערכים || 1 מערכים כפולים 20 2 דוגמה 0 יפוס שש 5-86 טפט ששב ילל שבי מש טוט שפיט יצ 2 שש 2/0 3 מצביעים 2 1 מצביעים ומערכיס ָ[/// ו 2 שינוי הארגומנטים של פונקציה 0 3 מצביעים לפונקציות ב 4 אופרטוריס להוספה והפחתה 2 5 ביטויים לוגייס 7 6 אופרטוריס הפועלים על סיביות 7[ 1 פעולות לוגיות על סיביות 2 2 פעולות הזזה על סיביות 9 7 מחרוזות 8 0 6 ++6 ו-007 למתכנת המקצועי 4 משפטי בקרה 4.454-.4.-.400 1 משפט הלולאה פווחשש 0 2 משפט התניה זו ו 3 משפט זס1 ל 4211222 4 משפט פווח/-00 1 5 משפט חסזושפ ל 5 רשומות 0 1 שימוש ב-06066 ...7 6 פונקציות רקורסיביות 0 5 0 ל 7 דוגמאות לקלט/פלט בסיסי ב לכש טל מב מש 59 1 ספירת תוויס בקובצ נתון - 1 2 העתקת קבציס ב 3 ספירת בתיסם ושורות 0 8 קדסם-מהדר ב ל 1 הכללת קבציס םב לס 9 527 2 הגדרות של קבועיס 0 5 3 הגדרת תבנית פונקציה 0 9 סיכוס 60 06 טש מכ רש כ 0% מש 5300 0 שאלות 0 1 מקור ב כ 5 ו 0 0 תכנות מוכוון אובייקטים 1 משבר התוכנה || 0 2 מה הם מודולים 0 5090 0 5/0506 1 דוגמה: ספר טלפונים - ניסיון ראשון 0 2 בניית ספר טלפוניס בעזרת מודוליס 0 ו 7 3 טיפול במספר מודולים 5 4 החסרונות של המודוליס 7 3 המחלקה 2 4 סיכוםס - 1 5 תרגילים 0 ל 0 כ מכ ליכ 5/5 המחלקה 1 מבנה המחלקה - אזורי גישה 7009 6 2 הבנאי - פונקציית האתחול של המחלקה ד ה 7.1 רו 7 1 בנאי ברירת המחדל || 2 בנאי עס פרמטריס ו תוכן הענייניס ‏ 7 1 בנאי עס קבועיס 8 3 בנאי העתקה ומושג הייחוס 1 3 המפרק, פונקציית הניקוי של אובייקטיס 0 4 מושג הייחוס ב 1 שילמושי הייחוס 0 5 פונקציות מחלקה - 0 1 פונקציות קבועות 7 2 מנגנון 6חווחו 1 1 פסקודת מאקרו 0 6 אופרטוריס 6 1 אופרטורים אונריס 0 2 אופרטורים בינאריס 0 3 סיכום האופרטורים לפי עדיפות 1 7 שדות סטטייס המשותפים לאובייקטיס 0 1 פונקציות סטטיות ו 2 דוגמה לשימוש בשדות ופונקציות סטטיות . 8 מנגנון החבר (0ח19) 0 1 מנגנון החבר בשימוש 0 1 בנאיס ל-פָח5% 0 2 אופרטוריס ל 9 אובייקטים כשדות של אובייקטיס אחריס 0 1 הגדרת תת-אובייקטיס - 0 2 העתקת אובייקטים מורכביס 1 3 דוגמה לשימוש במצביעיס לתת-אובייקטיס 0 הגדרה מקוננת של מחלקות 7 1 רשומות כמחלקות 7 1 אזורי גישה 0 2 פונקציות של רשומות 7 2 מחלקות חסכוניות 0 1 אלחוד (חסוחט) 0 2 שדות סיביות (פוום) 0 3 מצביעים לשדות ופונקציות במחלקה ב 1 מצביעיס לשדות - 0 2 מצביעים לפונקציות של אובייקטיס ל 4 סיכוס 0 5 שאלות 0 8 ++6 ו-007 למתכנת המקצועי קלט ופלט 1 חסרונות הספרייה הסטנדרטית של 6 0 2 קלט/פלט פשוט ב- ++6 7 1 העמסת אופרטורים י///- 0 2 אובייקטים בסיסייס ב 3 קריאה מקבציס 0 1 קריאה עם עריכה 0 2 קריאה ללא עריכה ל בש ל מל 0 4 כתיבה לקבצים ל 1 כתיבה עס עריכה 0 2 כתיבה בינארית לקבציס 0 5 שילוב קלט ופלט 0 1 שילוב בין אובייקטי קלט לפלט 1 2 שימוש באובייקטי קריאה וכתיבה 2 3 קביעת מיקוס מצביע הקריאה או הכתיבה 7 6 עריכת נתונים בזיכרון 1 7 שילוב פונקציות פלט/קלט ב 8 מניפולטוריםס ב ב ב מש ב ל 2 בש ב 2 456 1 תמיכה במניפולטורים במחלקה נתונה ב 2 מניפולטוריםס במערכת קלט/פלט 0 9 סיכום - ו 0 שאלות 0 פרק 5 | ירושה ככלי לשימוש חוזר בקוד 1 מהי ירושה 0 2 ירושה יחידה 0 1 ירושה פרטית 0 2 ירושה מוגנת || 43 הורשה ציבורית 0 2 דוגמה - רשימה מעגלית כפולה 0 1 צומת ברשימה ל 500 ב סט קט מ ש ששכ פיס/3095-20 2 האיטרטור ה 3 הרשימה 0 4 שימוש ברשימה בעזרת ירושה .|| 3 ירושה מהרשימה - 0 1 מחסנית 7 2 תור 1 תוכן הענייניס 9 4 ניהול זיכרון והגדרת אופרטוריס 1 1 הגדרת אופרטור שפח 1 2 הגדרת האופרטור 66/818 -2- 145 3 שימושים באופרטורי ניהול הזיכרון 1 3 ירושה מרובה 6-0 ל 5 ל מ ל 0 5 שש לב 148 1 הגדרת ירושה מרובה 1 2 אתחול של מחלקות בסיסיות 1 3 ירושה וירטואלית 1 1 אתחול במצב של ירושה וירטואלית 1 4 סדר בנייה ופירוק של אובייקטיס 15 1 סדר בניית אובייקטים 1 2 סדר פירוק אובייקטיס 15 3 דוגמה לסדר בנייה ופירוק של אובייקטיס 1 5 המרות 0 0 0 50500 שש 7 15 1 המרות של סוגים בסיסיים 157 2 המרות של מחלקות 5 3 חיתוך אובייקטיס 1 4 המרות של מצביעים או ייחוס 7 5 המרות המוגדרות על ידי המשתמש 1 6 סדר ההמרות 1 6 סיכום 1 7 שאלות ב 162 פולימורפיזם 1 דוגמה - הדרך הישנה 163 1 הגדרת המסך 7 2 הגדרת הצורות 1 3 הגדרת הפונקציות והפעולות 1 4 ניתוח חסרונות 1 2 מהו פולימורפיוס 2-ב 168 1 הפעלה וירטואלית בש ושע מ ופפ מ שש טכ מ סטש טפ 22 169 3 כיצד מיישמים פונקציות וירטואליות? 1 4 אילו פונקציות יכולות להיות וירטואליות? 1 5 מחלקות מופשטות טהורות ...173 1 נקודת התורפה של מערכת פולימורפית 17 1 ייצור אובייקטיס מופשטים (עזסז80- 051780%) 1 6 סיכום ב 177 7 שאלות 1 0 ++6 ו-007 למתכנת המקצועי תבניות ב-++6 1 לשם מה תבניות 0 2 7 תבניות ב-++6 1 1 פונקציות תבנית 7 1 שלמוש במספר פרמטרים בתבנית ב 2 תכנות גנרי 0 2 מחלקות תבנית - ו 1 אובייקטי פונקציות 0 2 שימוש בפרמטר קבוע למחלקת תבנית 0 3 דוגמה - רשימה מקושרת. 3 אפליקטוריס 0 1 הדפסה בעזרת האפליקטור 7 2 פירוק בעזרת האפליקטור 4 דוגמה - מערך דינמי 7 1 מבנה המערך ל 3 ירושה ותבניות | 1 ירושה מהמחלקה ץפזזה ב 2 שימוש באובייקט מסוג מערך בטות 0 1 פונקציות וירטואליות ל 3 מתאמים 2 1 תור 0 2 מחסנית 2 43 מתאמים גנריס ל 4 סיכוסם 2 ל 5 ש:כו2 5 7 שאלות 0 טיפול בשגיאות 1 מדוע צריך לטפל בשגיאות 0 2 פונקציות טיפול בשגיאות 0 3 טיפול בסיסי בעזרת מבני ++6 0 1 לעורר שגיאה (זסזזם ח3 פחואוסזחד) 2 אופן הטיפול בשגיאה 0 3 דוגמה - מערך בטוח ו 4 חריגים וירושה 0 ועוד 1 ירושה ללא פונקציות וירטואליות 0 2 שילמוש בפונקציות וירטוא 3 לכידת כל השגיאות מ 4 לעורר מחדש את השגיאה ליות 2 תוכן הענייניס 11 5 סימון מצביס חריגיס 0 6 טיפול בחריגיס שאינס צפוייס 7 4 שלמוש וטכניקות טיפול במצביס חריגיס 1 1 טיפול בזיכרון 4 1 מצביעיס אוטומטייס לאובייקטיס 8 2 מצביע אוטומטי למערך של אובייקטיס 2 שימוש במשאבים 7 5 שילוב בין תבניות למצבים חריגיס ב 1 מחלקת התבנית - מחסנית 2 2 השימוש במחלקה 5180 לש 3 טיפול במצב1יס חריגים 0 1 מצבים חריגים מקומיים ל 2 מצבים חריגים חיצוניים 0 6 סיכום ב בכ 0 7 שאלות 2 חידושים ב-++6 1 מידע בזמן ריצה ל לש לטו ל מ ל ל 1 האופרטור 0610 מ ב 2 המחלקה סוחו 08 ו 3 האופרטור 688% סווחהחץ ב 2 המרות נוספות של מצביעיס ב 1 המרות סטטיות 68580 91806 0 2 המרות המבטלות קביעות 0851 5%ח60 1 3 המרה חוזרת 685% 6%זכזס%חוז 7 3 מרחבי שמות פַסספפַחח 0 1 שימוש בהגדרות מקוננות ל 1 המונת פַסַַ8ס65חַַ8ח ב 2 שלימוש במילת המפתת פחופט 0 2 כינון של מרחבי שמות 3 3 הרתבת מרחב שמות 0 4 מללת המפתח 80!8זוח 0 5 מללת מפתח זוסו!סא6 (מפורש) 0 6 סיכוס - 0 7 שאלות כ 2 ++6 ו-007 למתכנת המקצועי פרק 10 | ספריית תבניות סטנדרטיות ‏ 511 1 עקרונות הספרייה 511 0 2 מכולות ב-511 - | 3 איטרטוריס 0 1 שילימוש באלגוריתמיסם ואיטרטוריס ב 2 תווית של איטרטור ,ככ ל 6 ה לשכנ הבתכ ;2-1 4 אלגוריתמיס 7 002 0 5 5 מתאמיס (8ז0ס%ק08) ל 6 אובייקטי פונקציות (0[8608 חסטסחט=) 2 7 סיכוס 0 8 מקורות כ 1 ומר 20 + הכנכ הוור .27 פרק 11 | מבני נתונים סדרתיים ב- 511 1 וקטור || | |[ 1 מבנה הווקטור | 2 האיטרטור 7[ 3 פונקציות חשובות 0 050 םכש בבש 2 רשימה כפולה - 8%וו ב 1 מבנה הרשימה 0 2 האיטרטור 8 3 פונקציות שימושיות ל 2 3 תור כפול - 0 1 מבנה התור הכפול מש סש םש ל בש ב 2 האיטרטור ב 4 מבנה נתונים - דוגמה 0 1 מבנה היומן 75 ל 2 פונקציות עזר 0 3 התוכנית הראשית 0 הר כ 4 תכנות גנרי ו[ 5 סיכוס 7 6 שאלות 3 תוכן הענייניס 13 פרק 12 | מבנים שאינם סדרתיים ב- 511 1 הגדרת קבוצות 0 1 פעולות על קבוצות 7 2 מבני נתוניס אפשרייס לקבוצה || 1 טבלת ערבול 0 2 עצים בינאריים 2 3 ע ,6 מאוזן - 66זך 8|80% ₪60 0 2 הקבוצה )589 0 1 מבנה הקבוצה ל 2 פונקציות חשובות ב 43 האיטרטור ל 3 קבוצה עס כפילויות 0 1 פונקציות חשובות 0% 4 דוגמה - שימוש בקבוצה 0 1 כניסה ביומן ב וק ובס ב ות לכ 5 ב 5 8 בכ ב וימ ב שד 2 פונקציות עזר 0 5 מפות (ס8ח וטו , קהוח) 0 1 מפה (80ח) - 0 1 פונקציות חשובות 5 2 2 האיטרטור 2 2 מפה כפולה (קאחוז!וטוח) 0/7 1 פונקציות חשובות 0 2 האיטרטור ל 3 דוגמה - שימוש במפה ב 1 פונקציות עזר 2 2 פונקציות קלט 7 43 פונקציות עדכון למילון 7 4 קלט ופלט מקבציס 7 5 פמונקציות הניהול ל פרק 13 | שילוב סוגי תכנות 1 מתאמיס (8זס%ק08) שש וס סט שבי יט שישרטפצפ שש ינטיל לופיטש ם ציט 0 :שש 1 תיאוס בין ספריות שונות 0 2 המרת ממשק אובייקט לקבלת פונקציונליות אחרת 0 1 שימוש ברשימה 2 2 גמישות במימוש המחסנית 02 וב לש 0 שו ב בסו ו > 4 ++6 ו-009 למתכנת המקצועי 3 המחלקה 581806 ב- 511 2 דוגמה - ניהול משימות (8565!) 1 הרַררכיית הפעילויות 1 המחלקה 88%ד 2 המחלקה 1!8788%/ץ600 43 המחלקה 6188%/ 2 מנגנון יצירת האובייקטיס 1 המחלקה 6180188585 2 המחלקה ז6010/ 0!8588 3 לב המערכת - אוסף המשימות 4 פונקציות הניהול 3 סיכוס 4 שאלות 1 דיסקט התוכניות המצורף 2 התקנה 3 הרצה - כללי 4 הידור והרצה תחת חלונות 1 הגדרת פרויקט 2 הידור התוכנית 3 הרצת התוכנית 5 הידור והרצה בסביבת 05 1 חוקיס בסיסים של ₪868 2 הידור והרצה אינדקס תוכן הענייניס 15 | |על+6 כשכותביס ספר, נותניס את הדעת למי הוא מיועד, כי קהל היעד קובע את הרמה והסגנון של הספר. הספר שלפניכם מיועד למתכנתים בשפת ++6 שרוצים להגיע לרמת מיומנות גבוהה ולהתקדם להיות מתכנתים מקצועיים באמת. הוא גם מיועד למתכנתי 6 ושפת פסקל, שאינם מכירים את שפת התכנות ++6. לטובת מתכנתי 6 ניתן פרק הגירה המסכס את אפשרויות שפת 6, עס הצבעה על המקבילות להן בשפת ++6. במהלך הלימוד יש הסבריס והתייחסויות הקשוריס לשפת 6, מכיון ששפת ++6 התפתחה כהמשך לשפת זו. מתכנתיס בשפת פסקל יוכלו גם כן להשתמש בספר, אך ייתכן שקצב הלימוד שלהם יהיה איטי יותר בתחילה. לאלה האחרונים, ההמלצה היא לקרוא בעיון את הפרק העוסק בשפת 6. שפת התכנות ++6 והמושג 020202 - תכנות מוכוון אובייקטים - חד הם. אפשר לומר ששפת ++6 מבטאת את המימוש של עקרונות 002, ולכן לא ניתן להפריד בין השניים. התכונות והכלים של ++6 נגזרים מעקרונות 002 (עיצוב מוכוון אובייקטים) ו- 00 ולכן, אי אפשר ללמוד ++6 ללא 007, ואי אפשר ללמוד 002 ללא ++6. במהלך הלימוד והרחבת הידע נעסוק בשני תחומיס: תחום התכנות בשפת ++6 ותחום תפישת התכנות המתקדמת - 007, אשר מהווה כאמור, את התשתית לשפת התכנות. קיימים ספרים לא מעטים על ++6, רובס מתארים את השפה ברמה בסיסית ואחרים מתאריס אותה ברמה מתקדמת יותר. ספר וה מתחיל מרמה בסיסית של ++6, אך מניח שלקורא יש רקע בסיסי כלשהו בתכנות. על כן, הוא ממשיך מיד לנושאים מתקדמים, למושגיס חדשים ולחידושים בשפה שטרס מצאו ביטוייס ברביס מהספרים המתקדמים. מטרת הספר היא להפוך מתכנתי ++6 ''רגילים'' למתכנתים מקצועיים בשפה זו, השולטים בטכניקות תכנון ותכנות חדשות ומתקדמות. 17 אובמ‎ ++6 היא שפה מתפתחת. התקן שלה אינו גמור עדיין (לפחות בעת כתיבת שורות אלו), אך קרוב לסיומו. שיטות וטכניקות חדשות עדיין מתוספות ולכן, ספרים חדשים המלמדים טכניקות ומונחים חדשיס הם כורח המציאות. שפות התכנות 6 ופסקל הן שפות פשוטות ובעלות יכולות מוגבלות. מתכנת ממוצע יכול להשתלט ולהתמחות בשפות אלו בזמן קצר יחסית, במספר חודשיס מועט. עס ++6, לעומת ואת, המצב שונה. גס מתכנתיס המשתמשיס בשפה זו מספר שנים, אינס מכיריס את כל אפשרויותיה. הזמן המשוער למתכנת ממוצע להשתלט על יכולות השפה מוערך בשניס. מתכנת שמכיר את 6 יכול לכתוב תוכניות ב-++6 כמעט באופן מיידי, אך כדי לכתוב תוכניות יעילות ובאיכות גבוהה, דרוש וזמן לימוד רב. ספר זה מלמד את השיטות והטכניקות הדרושות למתכנת כדי שיוכל לנצל את השפה ביעילות. לימוד עקבי יכול לקצר את ומן הלימוד באופן משמעותי. ++6 היא שפה הייברידית, כלומר, שפה שממזגת מספר גישות. היא יורשת מ-6 את כל המבניס והתכונות שלה, אך בנוסף לאלה היא מציגה יכולות חדשות, כגון תכנות מוכוון אובייקטים (8םות8זקסץ? 211620606) 020[606)) ותכנות גנרי (0110מם10) תות 8טַסזי). למרות ששני המונחים האחרונים נשמעים זהים, הס שוניס. הסבר על כך תמצא בפרקיס המתאימים. שפת ++6 היא שפה מוכלאת (הייבריד) ולכן היא מאפשרת לכתוב תוכניות דמויות 6 בשפה ++6. רביס חושבים שאפשרות זו היא חיסרון. קיימות שפות מוכוונות אובייקטיס אחרות, שאינו מאפשרות כתיבה אחרת, פרט לכתיבה בשיטה זו. חסידי שפות אלו טועניס ששפת ++6 מאפשרת חופשיות רבה מידי למתכנת, ואף מאפשרת להשתמש במבנים שאינס טובים מבחינת הנדסת תוכנה. מבניס אלה הן פונקציות שאינן קשורות לאובייקטיס. בשפת אובייקטים טהורה קיימים רק אובייקטים, כל הפונקציות נקראות שיטות (116)1008), וא*נן עומדות בפני עצמן, אלא שייכות לאובייקט כלשהו. אובייקט מייצג מבנה נתוניס כלשהו ופעולות המבוצעות עליו, ואלה קשוריס בקשר בלתי ניתן להפרדה. תכונה זו היא יתרון במקריס רבים, אבל ייתכנו גס מקרים בהס נרצה לכתוב פונקציות שאינן קשורות לאובייקט. הדבר יעיל במיוחד כשרוצים לכתוב פונקציות גנריות (כלליות), הפועלות על מגוון רחב של אובייקטיס, ללא תלות בסוג. היכולות לבצע דברים כאלה אינה נתונה בשפות אחרות. יכולת זו הולידה את המונח תכנות גנרי, שנתמך ב-++6, אבל לא בשפות אובייקטים אחרות. תכנות גנר? (8הוותות08?8ז? 6110מ020)) מאפשר אם כן לכתוב פונקציות, שהפרמטריס שלהן וסוג האובייקטים שהן מקבלות משתנה ומותאם לפי סוג השימוש שנעשה בהם. תכונה גו מאפשרת לכתוב פונקציות גנריות הפועלות על סוגיס רביס של אובייקטיםס שאינס קשורים וה לזה, כמו למשל, פונקציה שמעתיקה תחוס אחד למשנהו. הייתחוסיי יכול להיות מערך, רשימה, עצ חיפוש וכדומה. פעולת ההעתקה אינה תלויה בסוגיסם אלה, כל עוד הס מספקיםס ממשק קבוע של פעולות. הדבר חוסך מהמתכנת שכפול של פונקציות מספר רב של פעמים, אחת לכל סוג של מבנה נתוניס, או לכל סוג אובייקט. 8 ++6 ו-009 למתכנת המקצועי בשפות אובייקטים טהורות אחרות כמו א411131ו5, כל סוגי הנתוניס הס מחלקות היורשות מאובייקט גנרי כלשהו. לא כך הדבר ב-++6, שבה יש את כל סוגי הנתוניס שקיימיס ב-6, וגם סוגי נתוניס חדשים, או הרחבות של השפה. סוגי נתוניס אלה הן מחלקות (6185805) אשר נקראות גס: סוגי נתונים המוגדרים על ידי המשתמש 60 5 666 מתכנני ++6 הקדישו מחשבה רבה ליעילות השפה. ++6 אינה נופלת משפת התכנות 6, שנחשבת לשפה היעילה ביותר בין שפות התכנות המקובלות, ויש מקריס שאפשר להגיע בה לרמת יעילות גבוהה יותר. עובדה זו נראית מפתיעה, ומרבית הקוראים יתקשו לקבל עובדה זו. ספר זה מדגים את המקרים ואת השיטות שמאפשרים להגיע ליעילות כזו, המושגת הודות ליכולת לכתוב פונקציות גנריות. כדי להגיע ליעילות המתקרבת לשפת התכנות 6 חייבים להכיר את ++6 היטב ולשלוט ברזי השפה (רבים לא מנצלים אותה בצורה יעילה). בין שפות האובייקטים, ++6 היא היעילה ביותר. היא מאפשרת גישה לסיביות בודדות במילה, לפעול על מצביעים, וגם מאפשרת גישה לאוגריס של המחשב. העיקרון העומד מאחורי ++6 הוא שאי-שימוש ביכולות מסוימות של השפה לא יפגע במתכנת, או בתוכנית שהוא מפתח. מתכנתים יכולים להשתמש רק בחלקי השפה שהם מכירים, ללא כל צורך להכיר את כולה על בוריה. | על הספר ומה שיש בו הנושאיס הנלמדים בספר גה רבים, ומכסים את כל היבטי השפה. הפרקים מחולקים ועוליס ברמת הקושי, ככל שמתקדמים בקריאת הספר. ההנחה הבסיסית היא שקורא שמתקדס מפרק לפרק רוכש יותר ידע, ומאפשר לעלות ברמת הנושאים שהוא לומד. הפרק הראשון מלמד על המבנים ומשפטי הבקרה ש- ++6 יורשת מ-6. פרק זה מביא את הקורא לרמה הידע הדרושה בשפת 6 כדי שיוכל ללמוד את הנושאיס האחריס שבספר. הפרק השני מציג את המושג תכנות מוכוון אובייקטים - ?00. הפרק מתחיל בהצגת המונח מודול, שקדם לתכנות מוכוון אובייקטיס. הפרק מציג את הסיבות והמוטיבציה שהולידו את הטכניקות של תכנות מוכוון אובייקטים. הפרק השלישלי מציג את המונח מחלקה. מונח זה התפתח מהמונח מודול. מחלקה ב-++6 היא סוג נוסף שמגדיר המתכנת ובכך מרחיב את השפה. כלומר, ++6 מאפשרת להגדיר אופרטוריס למחלקות, או סוגים חדשים המוגדרים על ידי המתכנת, כך שסוגים אלה ייראו כמו סוגיס בסיסיים של השפה. והו מונח מרכוּי בשפה זו ומהחשובים בשפות אובייקטים. הפרק הוביעי מציג את ספריית הקלט/פלט של ++6. שפת התכנות עצמה אינה כוללת מבניס המאפשרים טיפול בקבצים. במקוס ואת, מסופקת ספרייה תקנית 19 אובמ‎ המאפשרת את הטיפול בקלט/פלט. שימוש בספרייה גו מאפשר לכתוב תוכניות ניידות שיכולות לרוצ על סוגיס שוניס של מחשביס ומהדרים, ללא צורך בשינוי. הפרק החמישי מלמד את המושג ירושה (118800זס1ם1). הפרק מציג את המונחים ירושה, ירושה מרובה וירושה וירטואלית. הפרק מציג נושאיס רבים הקשורים לירושה, כגון סדר בנייה של אובייקטים, סדר פירוק של אובייקטים, מתי להשתמש בירושה וכיצד להשתמש בירושה בצורה טובה. הפרקס השישי מלמד את הנושא פונקציות ווירטואליות. פונקציות וירטואליות קשורות למונח פולימורפיום, כלומר ריבוי-צורתיות. מונח וה, יחד עם מחלקות וירושה, מהווה בעיני רביס את הבסיס למונח תכנות מוכוון אובייקטים. פרק זה מציג גם את מודל האובייקטים וכיצד מושגת קשירה מאוחרת של פונקציות לאובייקטים. הפרק השביעי מתאר את המונח תבניות (14)6ק1ת16) ב-++6. מונת זה הינו מהחשוביס בשפה, אשר מאפשר תכנות גנרי, אחת מטכניקות התכנות החדשות שהופיעה לאחרונה ב-++6. פרק וה מסביר את עקרונות התכנות הגנרי. הפרק השמיני מדגיס את המונח מצבים חריגים (10605/ בסגזק66א3). מצביס חריגיס הס תוספת חדשה יחסית ל- ++6. מתכנתים מעטים יודעיס לטפל במצביסם חריגים, בדרך נאותה. נושא זה אינו מוסבר בדרך כלל בספרי לימוד אחריס של השפה. בדרך כלל, מוסברות רק המכניקה ומילות המפתח של השפה. בספר זה, לעומת זאת, בנוסף למכניקה ומילות המפתח, מוסברות טכניקות תכנות וטיפול במצביס חריגים. גס מוצגות מספר מחלקות העוזרות בטיפול במצבים חריגיס. הפרק התשיעי מציג נושאים חדשים שהתוספו לשפה ושאינם נתמכים על ידי רוב המהדרים. בין הנושאיס כלוליס מרחבי שמות, המרות של מצביעים, זיהוי סוגי אובייקטים בזמן ריצה ועוד. הפרק העשירי מהווה מבוא לספריית התבניות הסטנדרטית של ++6, .81'1. ספרייה זו הביאה לעולס את המונח תכנות גנרי ויצרה מהפכה באופן החשיבה והשימוש ב-++6. .1 היא ספרייה יעילה במיוחד, יחסית לספריות האחרות הקיימות ב-++6 וכדי להשתמש בה ביעילות דרוש ידע נרחב בתבניות. הספרייה יעילה בפעולותיה פי שתייס או שלוש מספריות אחרות. הספרייה תומכת במכולות, שהם אובייקטים המכילים אובייקטיס רביס אחרים (כגון, רשימות). הספרייה תומכת באיטרטוריס שמאפשריס לפעול על מכולות בצורות שונות, ומספקת מגוון רחב של אלגוריתמים גנריס. אלגוריתמים כמו +80, שממיין תחום נתוניס, או אלגוריתם כגון 6טףופט, שמבטל מופעיס כפולים של אובייקטיס בתחוס נתון. אלגוריתמיס אלה פועלים על כל סוג נתוניס כל עוד סוג הנתוניס מקייס ממשק מסוים. כלומר, האלגוריתמיס המסופקים בספרייה יכוליס לתמוך במכולות של ספריות אחרות! הפרק האחד עשר מציג את הנושא מבנים סדרתיים שמספקת .511. מבניסם אלה כולליס וקטור (מערך חד-ממדי), רשימה ותור כפול. כמו כן, מציג הפרק את האיטרטוריס של מחלקות אלו. הפרק נותן הסבר על המבנה הפנימי של המחלקות וכללים מתי ואיך להשתמש בהן ביעילות. 0 ++6 ו-009 למתכנת המקצועי הפרק השניים עשר דן במבנים שאינם סידרתיים ושמספקים חיפוש יעיל ומהיר של אובייקטים בתוכס. מבניס אלה מבוססים על עצי חיפוש בינאריס מאוזניס. המחלקות שמתוארות בפרק וה הן: 566, +₪₪1656, ק₪3 ו-כהּ010!טגת. כמו כן, מתואריס האיטרטוריס שלהס ומוצגות דוגמאות לשימוש במחלקות אלו. בשני הפרקיס האחרונים מודגמת, ומוצגת, שיטת התכנות הגנרית שהביאה ,511 לעולם. השיטה מוצגת לעומק ועקרונותיה מוסברים בפירוט. בפרק השלושה עשר מתואריס מתאמים (4680101%) ושילוב בין תכנות גנרי לבין תכנות מוכוון אובייקטים. פרק וה מציג דוגמה המשלבת בין עקרונות התכנות מוכוון האובייקטיס והתכנות הגנרי, ניחול מטלות ועוד. רוב המתכנתיס הלומדיס את ++6, הופכים לחסידים נלהבים שלה. צריך להזכיר לקורא, שהשפה היא כלי להשגת המטרה ולא המטרה עצמה. המטרה היא לכתוב תוכניות שמקיימות דרישות מסוימות בצורה יעילה ובאיכות גבוהה, תוכניות עמידות בשינוייס, שקל לשנותן בעת הצורך. ++6 אינה המטרה, אלא הכלי להשגתה. כך למשל, אין להשתמש בפונקציות וירטואליות, אלא אס הן תומכות בפתרון בעיית התכנות. התחלתי לעבוד בשפת ++6 בינואר 1989 בסידני שבאוסטרליה, ומאז ועד כתיבת שורות אלו אני משתמש בה. למרות מספר השניס הרב בהם אני עוסק בתכנות מוכוון אובייקטיס אני עדייו ממשיך ללמוד דבריס חדשים לגבי ++6. באוסטרליה עבדנו על פרויקט שנחשב, בשעתו, מהפכני בסוגו. כאשר הציגו לנו את השפה חשבתי שזו טעות להשתמש בשפה חדשה בפרויקט חדש שבו יש טכנולוגיות חדשות ורמת הסיכון בו כה גבוהה. מאוחר יותר התברר ש- ++6 עזרה לנו לפתח תוכנה באיכות גבוהה יותר ובומן קצר יותר. כיוסם אני עובד בחברת אורבוטק, ובה אנו מנצליס את השפה, ואת הטכניקות החדשות האלו, לפיתוח של פרויקטיס מתקדמים. אני יכול להבטיח לקורא ש- ++6 מספקת כלים יעילים מאוד למי שיודע להשתמש בהסם! למי שאינו יודע להשתמש בכלי השפה, אייעצ שלא להשתמש בהם. כדאי לו, למשתמש, לנצל את אפשרויות השפה שהוא מכיר ובהן הוא שולט היטב. קוראים המוצאיסם צורך בייעוץ, או מעונייניס לשאול שאלות, מוזמניס לפנות אלי. ניתן לעשות זאת בשתי דרכיס: דרך הוצאת הוד-עמי לספרי מחשבים המוציאה לאור של ספר זה, או להשתמש בכתובת הדואר האלקטרוני שלי: 1. מ6000660 תסו 91 21 אובמ‎ | | הדיסקט המצורף בדיסקט המצורף לספר נמצאות דוגמאות תכנות רבות. כדי להדר את הדוגמאות, עליך להשתמש בפקודה ₪₪8%6 המסופקת עס סביבת הפיתוח של בורלנד. הדוגמאות אינן תלויות במהדר מסוים, אלא מתאימות למהדרים רבים. רבות מהדוגמאות הורצו גס על מהדר ++% שהוא חופשי לציבור. דוגמאות אחדות הורצו גם על המהדרים של חברת תט5. אס אתה משתמש במהדר אחר, עליך להחליף את פקודת ההידור על פי המהדר שברשותך. אס המהדר שברשותך תומך בפקודות 4%86, עליך להחליף את הפקודות המתאימות בקוב וה. הוראות מפורטות להרצה ראה בנספח, וכמובן שעליך לעיין בהוראות ההפעלה של המהדר שברשותך. קובץ 886116 הוא קובצ המורה למהדר כיצד יש להכין תוכניות לריצה. הישוס 6, מסופק עם המהדר, עובר על הקוב 486816 ומבצע את הפקודות שבו. בין הפקודות יכולות להיות פקודות אחרות מאשר להידור של קובצי תוכנית. בדרך כלל משתמשים ביישוס זה כדי להכין תוכניות לריצה. בתת הספרייה .511 שבדיסקט המצורף לספר זה, תמצא את ספריית התבניות הסטנדרטיות של ++6. זוהי הספרייה המקורית שסופקה על ידי חברת 12, והיא חופשית לקהל הרחב. בהודמנות זו, אני רוצה להודות לכל האנשים אשר עמדו לצידי בעת כתיבת ספר וה. להורי רבקה וישראל כהן, לאשתי יפה ולאחרונות החביבות והחשובות מאוד, בנותי: ליאורה, נירית ואורנית. תודתי נתונה לכל האנשיס שעזרו לי בעריכת ספר זה, במיוחד לצור לוין וליצחק עמיהוד. שמעון כהן, 1997 2 ++6 ו-009 למתכנת המקצועי פרק 1 סקירה של שפת 6 בפרק וּה נלמד את המבניס החשובים של שפת התכנות 6. שפה זו היא הבסיס של ++6, ולכן חשוב להבינה. פרק זה נועד לסטודנטים, או מתכנתיס שאינס מכירים את 6 ומשמש כמבוא לשפה, אשר מי שמכיר אותה יכול לפסוח עליו. הפרקיס הבאים נכתבו בהנחת יסוד שהקורא מכיר את שפת 6 לפחות ברמה הבסיסית המוצגת בהמשך. תיאור נוסף של שפת 6 יכול הקורא למצוא באחד מהמקורות שבסוף הפרק: המדריך השלם לשפת 6 מאת משה ליכטמן ועמית רש, ו- ללמוד 6 מאת יואב נתיב, שניהס בהוצאת הוד-עמי. כל מה שנלמד בפרק זה על שפת התכנות 6 נכון גס לגבי ++6, שבנויה על יסודותיה של 6 ויורשת את תכונותיה. פרק וה משמש, אס כך, הקדמה לשאר הפרקים המלמדים ++60 ותכנות מוכוון אובייקטים. בעת הצורך נסקור יכולות המתאפשרות בעבודה עם ++6, אבל לא בעבודה עס 6, כשיכולות אלה מתאימות למקרה ולדוגמה. |1.1 | הקדמה והיסטוריה 6 היא שפה רב תכלית אשר משופעת בביטויים, משפטי בקרה, מבני נתוניס ופונקציות. זו שפה פונקציונלית שהתוכנית בה מורכבת מאוסף של פונקציות אשר קוראות זו לאו על מנת למלא משימה מסוימת. 6 אינה נחשבת לשפה גבוהה במיוחד. להיפך, ‏ 6 מאפשרת פעולות קרובות מאוד לחומרה של המחשב, ולכן היא גס שפה יעילה מאוד. אחד הדברים המייחדיסם את שפת 6 הוא הפעולות על מצביעיס ועל סיביות בודדות. המצביעים ב-6 הס אולי הדבר שגורס ל-6 להיות אחת השפות היעילות ביותר. אבל, מצד שני, המצביעיס ב-6 הס אולי הדבר המושמצ ביותר על ידי המתכנתיס בשפות אחרות. המצביעיסם והיכולת לממש ביטויים מורכביס במשפט אחד, הס מן הדבריס הקשיס למתחילים ב-6. בהמשך נראה דוגמאות רבות לכך בספר זה. פרק 1: סקירה של שפת 6 23 במקור נועדה שפת 6 להיות שפת פיתוח למערכות הפעלה, עקב הקירבה שלה לחומרה מצד אחד ויעילותה מצד שני. יש מספר מערכות הפעלה שנכתבו ב-6, אשר המפורסמת מביניהן היא אז]אז. ברבות הזמן הפכה 6 לשפה המובילה בין השפות הפונקציונליות, וכיוס אפשר להבתחין כי רוב התוכנות המצויות בשוק התוכנה נכתבו בשפה זו. ?) פותחה על ידי דניס ריצ'י ובריאן קרינגהן מחברת 4787 ומומשה בתחילה עבור מערכת ההפעלה אא ומחשביס מסוג 50 ו-תכע-11. המהדר (מהדר), מערכת ההפעלה ומספר יישומי עזר נכתבו ב-6. שפה זו אינה קשורה כעת לחומרה מסוימת ואפשר להריצ תוכניות ?6 על רביס מסוגי המחשביסם שקיימים בעולם. לשפת 6 יש יכולת גבוהה מאוד לבטא הרבה במספר מצומצס של משפטים. על כן, מתכנתיס שאינס מכירים אותה לא ירגישו נוח עם יכולת זה. כדי לפתח תוכניות יעילות ב-6 יש להכיר היטב את המשמעות של האופרטוריס השוניס ב-6. ב-6 יש תהליך בקרה יחיד, הקרוי 11696)+, אשר מורכב מפונקציות, לולאות ומשתניס בסיסיים, כלומר 6 אינה תומכת באופן מובנה בפעולות מקבילות, כפי שעושה ואת שפת ‏ 23 , למשל. כדי להשוות, לדוגמה, בין שתי מחרוזות, צריך להפעיל פונקציה. לפיכך, ‏ 6 היא שפה קטנה ומצומצמת. ה נראה כחיסרון, אבל היתרון למתכנת הוא בכך שאפשר ללמוד 6 מהר מאוד ולהגיע לרמת שליטה גבוהה (דבר אשר אינו מדויק לגבי שפות אחרות, כמו ++6). למי שמכיר את התחביר (אסותץ5) של 6 אין קושי להבין מה עושה התוכנית. ++6 אינה מכריחה מתכנתיס להשתמש בדבריס מורכביס אשר אינס קיימיס ב-6. [1.2 | תוכנית ראשונה התוכנית הראשונה והבסיסית ביותר אשר ניתן לכתוב ב-6 היא תוכנית המדפיסה הודעה לפלט. תוכנית כזו תדגיס לנו כיצד משתמשיס במהדר וכיצד מגדירים תוכנית אשר מקבלת פרמטריס בהפעלתה. כל תוכנית בשפת 63 מתחילה בפונקציה מיוחדת ששמה (0)מוגּממ. פונקציה זו היא הפונקציה הראשית של התוכנית וממנה מתבצעות התפצלויות וקריאות לפונקציות אחרות. שיס לב שכותביס את שם הפונקציה ואחריה זוג סוגריים רגילים ריקים, או 'ימלאיםיי בארגומנטיס (או פרמטריס). בכל תוכנית יכולה להיות, לכל היותר, פונקציה מופות אחת יחידה. כדי להדגים את הפונקציה הראשית נכתוב תוכנית קטנה אשר מדפיסה את הביטוי סל 116116'י לפלט הסטנדרטי. בדרך כלל, הפלט הסטנדרטי הוא החלון, או המעטפת (50611), שממנו הופעלה התוכנית. <ת.56₪10> 61006ת1+ ()מגנאת 6ם1 | ; ("מ16עסח 8110ם")11ת1צס 2 תעט0ט66ץ 4 | ++6 ו-009 למתכנת המקצועי המשפט הראשון בתוכנית שלנו (<5)010.2> 066(([ס11א) מכליל את הקוב 5)610.2 לתוכנית. דבר וה נעשה כדי שהמהדר יכיר את הפונקציה ())פוזק, שהיא חלק מהספרייה הסטנדרטית של 6. מייד לאחר מכן מוגדרת הפונקציה הראשית, ()מוגוז. הפונקציה הראשית היא, כאמור, פונקציה המייצגת את כל התוכנית והגדרתה נעשית בדומה להגדרת כל פונקציה ב-6. הגדרת פונקציה נפתחת בערך המוחזר על ידי הפונקציה (במקרה זה ₪6מ6, לאתחר מכן שם הפונקציה ובסוגריים - רשימת הארגומנטיס אשר הפונקציה מקבלת. הארגומנטים אשר מועברים לפונקציה מועבריס כהעתק של המשתנים המקוריים. המשתניסם המקוריים מועתקים על המחסנית של הפונקציה, והפונקציה משתמשת בהעתק וה. שיטת העברת הארגומנטים נקראת העברה לפי ערך (סט]גצ עְס). כדי לשנות את המשתניס המקוריים יש צורך להשתמש במצביעים (נראה כיצד לעשות זאת בסעיף העוסק במצביעים). גוף הפונקציה נמצא בתוך סוגרייס מסולסלים ([)) ומהווה אוסף של משפטיס אשר הפונקציה מבצעת. אוסף משפטים זה יכול לכלול הגדרת משתנים, או משפטי בקרה. פונקציה אף יכולה לכלול קריאה לפונקציות אחרות. כאשר הפונקציה מסתיימת היא מחזירה ערך בעזרת משפט מעט66ע. המבנה הכללי של פונקציה הוא: (820-118%)סתג5 6ט810ט-מעגו26% | צְססס ] הפונקציה הראשית בדוגמה זו מחזירה ערך שלס (0089ו10) בעזרת המשפט ג00סז. הפונקציה הראשית אינה מקבלת ארגומנטים, בהמשך נראה שקיימיס מצביס בהס מעבירים ארגומנטיס לפונקציה הראשית. במקרה הנדון מחוזירה הפונקציה את הערך אפס. הפונקציה מדפיסה לפלט את המחרוות המבוקשת בעזרת קריאה לפונקציה אחרת, 1)חוזק. הפונקציה +)מוזץן מדפיסה את המחרוזת הנתונה לפלט הסטנדרטי (0ו5/0). הפונקציה יכולה גס להדפיס נתונים מעוצביס וזאת נראה בהמשך. התו המיוחד ת (המיוצג בקוד על ידי שני תוויס) מסמן למהדר להחליף אותו בקוד 450611 המתאים לקוד דילוג לשורה חדשה. כדי להדר את התוכנית הזו צריך להפעיל את המהדר על הקוב המתאים. פעולה זו נעשית כך: 0 00 המהדר, התוכנית המבצעת את ההידור, יכולה להיות אחרת מאשר 6ס. עבור מהדרי 4, למשל, שס התוכנית הוא 66פ. ברירת המחדל של המהדר היא ליצור קוב בשס 3.00%, שהוא למעשה התוכנית לאחר הידור, ואותו אפשר להריצ. כדי לשנות שס זה אפשר, בדרך כלל, להוסיף את הדגל (188ת) 0 (האות ס), ולאחריו את שס הקוב של התוכנית המבוקשת. למשל: 0 ס611תם 0ס- 00 פרק 1: סקירה של שפת 6 25 פקודה זו תיצור קובץ בשס ₪616 אשר יכיל את התוכנית לביצוע. כדי להפעיל את התוכנית צריך להקליד את שמה. העברת ארגומנטים לתוכנית הראשית שיפור אפשרי לתוכנית זו היא לאפשר הדפסת שם נתון. כלומר, לאפשר להדפיס ,16110 <6ותִאת> כאשר <6ַַתאת> הוא ארגומנט שניתן על ידי המשתמש. כדי להזיו את השס לתוכנית, יש להוסיף ארגומנטיס לפונקציה הגגות. דבר וה יכול להיעשות בצורה הבאה: ([]טףע8* ע8םת0 ,8260 סםת1)תנ1את 6ם1 ןָ ; ([1]עש826 ,"םת%5 ,6110ם")11ת1צק 2 תעט0ט66ץ ו הפונקציה הראשית של התוכנית נקראת תמיד עס שני ארגומנטיס (הפרמטרים). הארגומנט הראשון הוא מסוג שלם, אשר מוגדר על ידי מילת המפתח ומו. ארגומנט וה מציין את מספר המחרוזות אשר הארגומנט השני מצביע עליהסם. הארגומנט השני של הפונקציה מציין את הארגומנטיס שאיתס הפעיל המשתמש את התוכנית. הארגומנט השני הוא מערך של מצביעיס לתווים. ראשית, הסוג של המערך הוא של תוויס (ז8ת6), כלומר, מערך של מצביעים לתווים. המערך (עגזזג) מסומן למהדר בעורת הסוגריים המרובעים [], ואילו מצביע (וטומוסע) מסומן למהדר בעזרת התו כוכבית *. משתנה מסוג תו הוא המשתנה הקטן ביותר וגודלו תלוי בסוג המחשב. ברוב המחשבים גודלו של משתנה ה הוא בית (טוץט) אחד, או שמונה סיביות. הפונקציה ))חוזן יכולה לקבל מספר משתנה של ארגומנטים. הארגומנט הראשון הוא מחרוזת אשר מתארת את תסדיר (פורמט) הארגומנטיס האחרים של הפונקציה. התסדיר של הארגומנטיס נעשה בעזרת תווי הבקרה א%, כאשר א הוא התו שמתאר את סוג המספר הנדרש להדפסה. האות 5 מציינת שלפנינו מחרוזת (8פ501), כלומר מצביע לתוויס. הנה מספר תווי זיהולי: * %8 - הדפסה של מחרוצות. * %6 - הדפסה של שלמים. * %1 - הדפסה של מספריס ממשים בשיטת הנקודה הצפה (ומוסק 6ת109801). 1 - הדפסה של שלמים כפולים באורכם (8חס). הפונקציה אפוק מדפיסה את הפרמטרים שלה בתוך המחרוות הנתונה לה לפלט הסטנדרטי של התוכנית. לכן התוכנית הקודמת תדפיס למשל: 8 ,110סת 6 | ++6 ו-009 למתכנת המקצועי הערות כדי לאפשר תיעוד לתוכנה, מקובל להכניס הערות (ותסנתננס6) בגוף התוכניות. המהדר מתעלס מהערות אלה ואינו יוצר קוד כתוצאה מכך. הערות ב-6 נכתבות בין שני זוגות של תווי קוד: /*... הערה ...*/. הערה מתחילה משמאל בתווים */ ומסתיימת מימין בתוויס /*. כאשר ההערה יכולה להיפרש על פני מספר רב של שורות. למשל: */ פתעספעסס תסנססתט+1 6ת1אס011+ 6מך *%/ או כך: /* הערה */ ב-++6 יש צורה נוספת להערה: הערה בשורה אחת בלבד. ההערה מתחילה עם צמד התוויס // בשמאל, ומסתיימת בסוף השורה. למשל: 8 מס051םט1 6ם1ח0ס5011 6מע // מניסיון, עדיף לשמור על סגנון הערות אחיד באותה תוכנית. למשל: 8 שת סאם 0% 8082806 56 68ס6טקתסס פטא8 // (2ט %ת1 ,1ט 6ם1)שט8 6ם1 תטפ 6ם6 מסגח עסע6% צץ1מ058815ק ,8067806 6םם 5מלט66ץ, // 8 18 // 72 / (2ט+1ט) תעט66? כדי לבטל קטע של פונקציה או את כולה, ניתן להכניסה להערה רבת שורות: /* ..*/. [1.3 | משתנים ופעולות אריתמטיות ב-6 יש סוגים שוניס של משתניס (9118016) שעליהם ניתן לבצע פעולות אריתמטיות כמו חיבור, חיסור, כפל וחילוק. כדי להגדיר משתנה, משתמשים במילת המפתח של סוג המשתנה ולאחריה מופיע שס המשתנה. למשל, השורה הבאה מגדירה משתנה מסוג שלס : ?7 106 בשורה אחת ניתן להגדיר מספר משתנים. מפרידים ביניהם בפסיקים. למשל: 2 ,11 סם1 סוגי המשתנים השכיחים הם: = זגַתס - מייצג תוויס בשיטת 458011. גודלו בית אחד. *‏ 8101 - מייצג שלס קצר (ם1ג). הוא גדול או שווה ל-0191. = פַמס1- מייצג ערכים שלמים. כפול בגודלו מ-+זס81. * 11006 - מייצג מספר ממשי עס שבר, למשל: 1.23. > 600016 - מספר ממשי בעל דיוק גבוה יותר מ-8108%. פרק 1: סקירה של שפת 6 27 את שלושת הסוגיס הראשוניס אפשר להגדיר חסרי סימן (1866פתט), והמשמעות היא שהס יהיו חיובייס. לשס כך, צריך להוסיף להס את מילת המפתח 18860פתט. למשל: ;ך %ם1 ;% 16260פםגו ;0 0 18260פתגו ;12 6ת0ס1 16260פתג בשורה הראשונה מוגדר משתנה מסוג שלס עם סימן. השורה השנייה מגדירה משתנה שלס חסר סימן. כאשר לא מסופק סוג המשתנה ברירת המחדל היא ''שלם'י. בשורה השלישית מוגדר משתנה מסוג תו ללא סימן. בשורה הרביעית מוגדר משתנה שלס בגודל כפול ללא סימן. במשתנה עס סימן יש סיבית אחת, אשר מציינת את הסימן (חיובי, או שלילי). לכן, הערכיס שיכוליסם להחזיק מספרים חסרי סימן גדוליס פי שתיים מאלה של משתניס עס סימן. למשל, משתנה מסוג 041 יכול לקבל ערכיס בתחוס [127, 128-], ואילו משתנה מסוג 0181 18866פמט יכול לקבל ערכים בתחוס [255, 0]. באופן דומה ניתן להגדיר מספריס ממשיסם. השורה הבאה מגדירה שני משתניס מסוג מספר ממשי עם דיוק כפול: 72 ,601 000016 על משתנים ניתן לבצע פעולות אריתמטיות. פעולות אריתמטיות נקראות אופרטורים. האופרטוריס מתחלקים לשני סוגים : = אופרטוריס בינאריים, אשר פועלים על שני משתנים. = אופרטוריס אונריים, שפועלים על משתנה אחד. רשימת הפעולות האריתמטיות : + כדי לחבר שני מספרים, או כאופרטור אונרי לסמן את הסימן (כחיובי) של משתנה. - | כדי לחסר משתנה ממשתנה אחר, או כאופרטור אונרי לסמן את הסימן (כשלילי) של משתנה. * אופרטור בינארי המשמש ככפל בין שני משתניס. / אופרטור בינארי המשמש לחלוקה של שני מספרים זה בזה. % אופרטור בינארי אשר מספק את השארית (מודולו) בפעולת חלוקה בין שני מספרים. ++ אופרטור אונרי המגדיל באחד את המשתנה שעליו הוא פועל. -- | אופרטור אונרי המקטין באחד את המשתנה שעליו הוא פועל. למשל: 2 ,2 = 12 ,1= 11 סם1 8 ++-6 ו-009 למתכנת המקצועי שורת ההגדרה מגדירה שלושה משתניס שלמיס כאשר שני הראשוניס מאותחליס ל-1 ו-2 בהתאמה ואילו השלישי אינו מאותחל. השורה הבאה היא שורת השמה, היא משימה את הערך של הכפל של המשתניסם למשתנה 13. כאשר משתמשיס בפעולת החילוק, יש לדעת שעבור משתנים שלמיס התוצאה מתעגלת ולכן: = רד משפט זה קובע למשתנה 13 את הערך אפס. לו המשתנים היו מסוג 108% או 16פטס4 היה הערך המוכנס ל-13 שונה: 0.3333. בפעולת החיסור יש להיזהר מחלוקה באפס. מצב של חלוקה באפס אינו מוגדר ובמקרה הטוב, התוכנית תופסק באופן מיידי על ידי מערכת ההפעלה עס הודעה מתאימה. במקרה הפחות טוב, התוכנית לא תופסק ותתנהג באופן בלתי צפוי. מערכים ב-6 וגם ב-++6 יש אפשרות להגדיר מערכים. מערכים (8119/8) הס אובייקטים אשר מכילים מספר קבוע מראש של אובייקטיס אחריס. למשל מערך של תוויס יכול להכיל עשריס תוויס. מערך של שלמים יכול להעריך מספר שלמים. האובייקטים שמוגדריס במערך מאחסנים בקטע זיכרון רציף, מהאובייקט הראשון והלאה. כך אנו מגדיריס מערך: ; [5126] סתהםת 6סץ6 6 מציין את סוג האובייקטיס אשר נמצאיס במערך. 6וַגח הוא השס של המערך, ואילו הערך 8126 בתוך סוגרייס מרובעים, מצייו את מספר האובייקטים שקיימים בו. למשל: ;[828]20ם0 05 צץ08ע8 מַַם0 ;[68]5ת1 01 צץ28ע 8‏ 6ת1 המערך הראשון הוא מערך של 20 תוויס ואילו המערך השני הוא מערך של עשריס שלמים. הגודל של המערך הראשון הוא עשרים תוויס. הגודל של המערך השני הוא חמישה שלמים. הפנייה לאובייקטיס במערך נעשית בעזרת פעולת המערך באופן הבא: ;'8' = [828]0ם0 01 82287 2 = [6]1ת1 0% עבעצב מערכיס מתחיליס מאינדקס אפס ולכן, בשורה הראשונה מכניסיס את הערך תו 8 לתו הראשון במערך, בשורה השנייה מכניסיס את הערך 1 לכניסה השנייה במערך, אשר מצוינת על ידי האינדקס 1. פרק 1: סקירה של שפת 6 29 מערכים כפולים מערכים כפולים הס מערכים של מערכים, ולעיתים מכוניס מטריצות (18011008/). מערכים כפולים מוגדרים בצורה דומה למערכים רגילים כאשר מוסיפים מימד נוסף למערך. הצורה הכללית של הגדרת מערך כפול חיא : ; [51262] [851261] סתהם 6סץ6 6 מציין את סוג האובייקטיס אשר יהיו במערך. 6נאת הוא שס המערך, 81261 הוא גודל המימד הראשון של המערך, ואילו 51262 הוא גודל המימד השני. למשל, אנו יכולים להגדיר מערך כפול של שלמים באופן הבא : ;[10[]5]ץ8ע2ע82 %6ם1 ההגדרה הזו מתייחסת למערך של 5א10 שלמים. המשמעות של ההגדרה היא: מעוך של מערכים. כלומר, ההגדרה של המערך הכפול היא הגדרה של עשרה מערכים. כל אובייקט במערך הוא מערך של חמישה שלמיס בפני עצמו. כלומר, בזיכרון יופיעו חמשת האובייקטיס של המערך הראשון, אחריהס חמשת האובייקטיס של המערך השני וכן הלאה. האובייקטיס של המערך שבדוגמה הס שלמיס. פנייה לאובייקטיס יחידים במערך נעשית כך: 2 = [1[]2] צץ3228 בדוגמה זו מוכנס הערך 3 לשורה השנייה של המערך במקוס השלישי. במילים אחרות, הערך מוכנס לאיבר השלישי של המערך השני של מערכים. מערכיס מסדריס גבוהיס יותר ניתניסם להגדרה באופן דומה. לדוגמה, מערך תלת-מימדי של שלמיס נראה כך: ;[2[]3[]4]ץ8228 6ם1 הגדרה זו מגדירה מערך בגודל 2 של מערך כפול מגודל 3 של מערך שלמים מגודל 4. נוכל לומר ואת גס כך : לפנינו 3 מערכיס של 4 איברים, או מערך דו-מימדי, אשר מוצג פעמיים ולכן יוצר מערך תלת-מימדי. במערך זה יש לנו 24 איבריס שלמים (סחייכ 4*32). כלומר, ההגדרה הינה רקורסיבית. דוגמה כדי להמחיש משתנים ואופרטורים נכתוב תוכנית קטנה שמחשבת ממוצע של מספרים. נגדיר פונקציה שמקבלת מערך של שלמיס ומספר האלמנטיס במערך, ומחשבת את הממוצע שלהס. הפונקציה מחזירה את הממוצע שלהם לפונקציה הקוראת לה. (סמטסס %ת1 ,[]?82 6ם1)עטה8 %6ם1 / 2 = תטפ ,0 = 1 %6ם1 ] (פתטסס > 1) 16נתט ;[1]ץע8 + תט5 = תגפ ; 1++ ] ; (6>תטסס / מטפ) םמעו6%ת2 0 | ++6 ו-009 למתכנת המקצועי בפונקציה +צג יש מספר דבריס חדשיס אשר לא ראינו עד כה. ראשית, היא מחזירה ערך מסוג שלם (ו). הארגומנט הראשון שהפונקציה מקבלת הוא מערך של שלמים. הואיל והפונקציה אינה יודעת את גודל המערך (הניתן בארגומנט השני שלה) אין סימון של גודל המערך בתוך הסוגריים המרובעים שנלוויס לשס המערך. המימד הראשון של המערך בקריאה לפונקציה הוא המימד היחיד אשר מותר לא לפרטו. המערך אינו מועבר בקריאה לפונקציה, אלא רק הכתובת לתחילתו. המהדר מחשב את האובייקט המתאים של המערך. הפונקציה מגדירה שני משתנים 1 ו-ממטפ אשר משמשים כאינדקס למערך וכסכוס האיברים. שני המשתניס מאותחליס לאפס. הפונקציה מחשבת את הסכוס של איברי המערך בלולאת 6!ואו. לולאה (קסס!) כזו מאפשרת לבצע רצף של מספר משפטים כתלות בתנאי. המבנה של לולאת 16ומאי הוא : ] (עקא6) 16נ1נתט צְססס ] לאחר מילת המפתח 16וגאי מופיע ביטוי בין סוגרייס. בכל שלב של הלולאה נבדק הביטוי. אם ערך הביטוי שונה מאפס, אזי מתבצע הגוף של משפט 6!וםאי. הגוף של משפט 16ו1]ש נמצא בין סוגרייס מסולסלים לאחר התנאי. גוף הלולאה יכול להכיל משפט אחד, או מספר משפטים. אם הגוף של משפט הלולאה מכיל משפט יחיד, אין צורך להכניסו בין סוגרייס מסולסליס. אם כך, המשמעות של משפט 6!ו1]ש היא, שכל עוד התנאי (הביטוי) בסוגריים הוא בעל ערך אמת (ערך השונה מאפס) מתבצע גוף ה-6ו)ש. בכל פעס מתבצע גוף המשפט, והבקרה של התוכנית בודקת את התנאי במשפט האס לבצע את המשפט שוב. גם לפני הביצוע הראשון של משפט זה נבדק התנאי. משפט 6ופ בפונקציה ץג מתבצע כל עוד המשתנה 1 קטן מהמשתנה ותטף. האופרטורים > או < מקביליס למשמעות שלהסם במתמטיקה, כלומר, קטן או גדול בהתאמה. האופרטורים =< ו-=> אף הס בעלי משמעות והה למשמעות המתמטית שלהם, כלומר גדול-שווה או קטן-שווה. לפיכך, אופרטוריס אלה מקבלים ערך אמת (ערך השונה מאפס, בדרך כלל אחד) כאשר המשתנים עליהס הם פועלים ממלאים את היחס המתמטי גדול או קטן בהתאמה. אחרת, האופרטוריס מחזיריס ערך שקרי (אפס). הסימן == ערך אמת, כל עוד המשתנים עליו הוא פועל בעלי ערכים זהים, אחרת אפס. הגוף של הלולאה מתבצע )מטסס פעמיס כאשר בכל פעס מתוסף הערך של האלמנט במקוס ה-1 במערך לסכוס המערך. בסוף הלולאה המשתנה נתטפ מכיל את הסכוס של כל איברי המערך. לכן, אס מחלקים ערך זה במספר האלמנטים במערך מקבלים את הממוצע שלהם, וזה מה שהפונקציה מחזירה לפונקציה שקוראת לה. המשפט [911]1 + מטף = מזטפ יכול להיכתב בצורה מקוצרת כך: ; [22]1ע8 =+ מטפ פרק 1: סקירה של שפת 6 31 המשמעות של המשפט המקוצר היא: הוסף למשתנה ננטפ את הערך של האלמנט במקוס ה-: של המערך. כאשר האופרטור צמוד לסימן =, אזי הפירוש שהאובייקט השמאלי עליו פועל האופרטור הוא האובייקט לפני =. למשל, עבור אופרטור בינארי (₪ כלשהו מתקיימת הזהות הבאה: % ;ץ 6 א = א >==<‏ ;ץ =6 לכן על פי חוק ה מתקיימות הזהויות הבאות : מצביעים ב-6 יש משתניס אשר מצביעיס (6ומוסק) על משתנים אחרים. כלומר, משתניס שמכילים כתובת של משתנה אחר. לפיכך, הערך של משתנה כזה הוא כתובת בציכרון. האופרטור * משמש להגדיר מצביעיס לסוג נתון (פרט לכך שהוא אופרטור הכפל). כאשר מוסיפים לו את סוג המשתנה, הרי שההגדרה היא של מצביע לסוג מסוים. למשל: ;קב* %ם1 המשפט לעיל מגדיר מצביע למשתניס מסוג שלמים. כאשר המהדר מטפל במשתנה כזה הוא מניח שהוא מצביע לשלס ובהתאם לכך הוא מבצע עליו פעולות אריתמטיות. אס למשל משתנה מסוג שלס הוא בגודל ארבעה בתיס אז המשפט - ;ק1++ יקדסם את הכתובת אליו מצביע המשתנה בארבע ולא באחד. לעומת ואת הפעלת אותו אופרטור על משתנה מסוג מצביע לתו תשנה את הכתובת (ערכו) בבית אחד. כאשר מפעילים את האופרטור * על מצביע, מקבליס את הערך של האלמנט אשר מוצבע על ידי המצביע, כלומר, את הערך של האלמנט (המשתנה) שנמצא בכתובת שמכיל המצביע. לפעולה זו קוראיס 06761070006. כדי להכניס ערך למשתנה מסוג מצביע יש לתת לו את הכתובת של משתנה המתאיס בסוגו לסוג המצביע. למשל, עבור מצביע לשלמיסם יש לתת את הכתובת של מצביע שלם. לקיחת הכתובת של משתנה נעשית על ידי האופרטור 8. למשל, 12 = ס1 כאשר 1 הוא משתנה מסוג שלס 150). אפשר להשתמש במצביע כדי לשנות ערכיס של משתניס אשר מוצבעים על ידי המצביע. למשל, אפשר לעדכן את הערך של המשתנה 1 בעזרת האופרטור כוכבית ( *). דבר זה ניתן לעשות בצורה הבאה: כ ב המשפט הזה מכניס את הערך 3 למשתנה 1. באופן דומה אפשר לקבל את הערך של המשתנה :. לפיכך, מצביעים מאפשרים לנו לבצע פעולות על משתניס בצורה עקיפה. ;ק1* = ך 6ם1 במקרה זה אנו מגדיריס משתנה שלם | אשר מאותחל בערך התכולה של המצביע כ שהיא הערך של המשתנה 1. 2 ++6 ו-009 למתכנת המקצועי מצביעים ומערכים בשפת 0, מצביעים ומערכים קשוריס זה לזה והמשמעות שלהם היא כמעט והה. כאשר נתון מערך, השס של המערך הוא מצביע לתחילת המערך. מצביעיס ומערכיס זהיס ואפשר להשתמש ולהחליף ביניהס. ההבדל העקרוני הגדול בין מערך לבין מצביע הוא, ששס המערך מצביע למקוס קבוע בזיכרון ואי אפשר לשנותו כך שיצביע למקוס אחר. לעומת זאת, מצביע אפשר לשנות ולגרוס לו להצביע למקוס אחר ביכרון. האריתמטיקה אשר פועלת על מערכים פועלת על מצביעים כדי לחשב ערכים של אובייקטיס בתוך מערך. למשל: 2* ,[7]10ץ28ע82 6ם1 ;צְעעה = ס8 72 = [287]2ע82 2 = [2]סה בקטע הקוד הזה מוגדריס מערך בגודל של עשרה שלמיס ומצביע לשלמים. ההגדרה של מערך גורמת להקצאה של עשרה שלמים כאשר השם (משתנה) צ889 מצביע לתחילת המערך. לעומת זאת, ההגדרה של המשתנה 82 גורמת להגדרת מצביע בלבד. משפט ההשמה אשר מופיע לאחר מכן נותן למצביע 82 להצביע לתחילת המערך. שני המשפטים שמופיעים לאחר מכן מכניסיס את הערך 3 לאלמנט השלישי של המערך. האינדקס אשר מופיע בפעולת המערך הוא 2, אבל מערכיס ב-6 מתחילים מאפס ולכן זהו האלמנט השלישי. כאשר המהדר מחשב כניסה במערך הוא עורך את החישוב יחסית למצביעים. כלומר, הכתובת של תחילת המערך נלקחת כבסיס לחישוב. לכתובת זו מוסיפיס את האינדקס מוכפל בגודל בבתיס של אלמנט במערך, וזו הכתובת של האלמנט שיש להתייחס אליו. לאחר חישוב הכתובת מתבצעת פעולת 06מ46161070, כלומר הוצאת התכולה מהכתובת, ועל הערך המתקבל מתבצעת הפעולה המבוקשת. למשל: 7 = ((6ם812601)1 * 2 + צץ8228)* >==<‏ ;3 = [7]2ץ8228 לסיכום, יש שני הבדלים עיקריים בין מערך למצביע: > בהגדרת מערך, שס המערך הוא מצביע קבוע לתחילת המערך ואין אפשרות לשנות אותו. מצביעים יכוליס להצביע למקומות שונים, כי הס יכוליס לקבל ערכים שוניס במהלך התוכנית. + כאשר מגדיריס מערך, המהדר מקצה עבורו זיכרון לפי מספר האלמנטים שנמצאים בו. כאשר מגדיריס מצביע, המהדר מקצה מקוס אך ורק עבור המצביע. לכן, הפונקציה זצג יכולה לחיכתב בצורה הבאה : (פסתטסס 6ת1 ,עע8* 6ם1)עטה8 1108% | 2 = תטפ8 ,0 = 1 %6ם1 ] (פתטסס > 1) 16נתט ;[85?]1 =+ תגפ פרק 1: סקירה של שפת 0 - 33 ; ב++ 1 ; (9ם000ס(108%6+) / תטפ(108%+)) מעג66ץ ו השינוי שהוספנו כאן הוא שהערך המוחזר מהפונקציה הוא )1094, ואילו הפונקציה מקבלת מצביע לתחילת מערך השלמים. הסיבה להמרה של שלסם למספר ממשי היא, שכאשר מחלקים מספרים שלמים מקבלים מספרים ממשיים (לא תמיד שלמים). בגירסה הקודמת היינו מאבדים דיוק. כדי למנוע אבדן דיוק, אנו מוריס למהדר לבצע את פעולות החישוב במספרים ממשיים על ידי המרות (6ם68511) של המשתניסם במשפט מ:60ע. המרה של משתנה נראית כך: ;ץ(פסץ5) = א כאן, סטש הוא הסוג של המשתנה א. בדרך זו אנו ממיריס את הערך של ץ לסוג המתאים ל-א. שינוי הארגומנטים של פונקציה כוכור, כשקוראים לפונקציה עס ארגומנטיס ב-6 (וגם ב-++6), מועבר העתק של המשתנה אל המחסנית של התוכנית. הפונקציה מכירה רק את ההעתק, וכל פעולה על ההעתק אינה משפיעה על המשתנה המקורי. לעיתים צריך לשנות את המשתנים המקוריים. נניח למשל, שישנה פונקציה שמחליפה בין הערכיס של שני משתניס שלמיס באופן הבא : (2ט %ם1 ,1ט שת1) ק8ח5 ב1בסט ןָ ;1ץ = קתס %ם1 2 = 1 ;סתף = 2ץ ] פונקציה כזו יכולה לשמש אלגוריתס של מיון למשל. הבעיה היא שקריאה לפונקציה כוו אינה משפיעה על המשתניס המקוריים, כלומר: 2 = 2א סת1 ,1 = 1א 6ם1 ; (%2 ,1א) 58 גס לאחר הקריאה לפונקציה, המשתניס 1א ו-2א יחזיקו את הערכיס ההתחלתייס שלהם, כלומר 1 ו-2 בהתאמה. אנו יכולים לשנות מצב וה אס נגדיר את הארגומנטיס של הפונקציה כמצביעים. במקרה כזה, יועברו הכתובות של המשתניס המקוריים ואז הפונקציה תוכל להשפיע על תוכן המצביעים: (2ט* %ת1 ,1ט* שת1) ק8ח5 בנ1בסט זָ + > ב ו % > כ % > כא] | + 3 ס' 4 | ++6 ו-009 למתכנת המקצועי ;2 = 2א ,1 = 1א 6ם1 6%2( ;‏ ,1א6) ₪8 לאחר הקריאה לפונקציה 840 במקרה זה, יוחלפו הערכיס של המשתנים המקורים 1א ו-2א. השימוש במצביעים כדי להשיג מטרה זו נראה מגושם ואכן, ++6 תומכת באפשרות אחרת שנקראת *יחוס (00ם010-0ו) כדי להשיג את אותה תוצאה. נדון בכך בפרקיס הבאים. מצביעים לפונקציות ב-6 וב-++6 אפשר להגדיר מצביעיס לפונקציות. בניגוד לשס הפונקציה שקשור לכתובת אחת ויחידה של פונקציה, מצביע לפונקציה אינו קשור לכתובת אחת. לפיכך, אפשר לשנות את המצביע, כך שיצביע לפונקציה אחרת. מכיון שאפשר להפעיל את הפונקציה הקשורה באותה עת למצביע, הרי שאפשר לשנות את הפונקציה המופעלת בומן ריצה. ב-6 דבר זה מעניק גמישות רבה לתוכניות, אך ב-++6 יש כלים הרבה יותר חזקים, ובדרך כלל אין צורך להשתמש באפשרות זו. הגדרת מצביע לפונקציה כלשהי נראית בצורתה הכללית כך: ; (8206-118%) (ע6ק*) 6גו81ט-26%6 כשקוראיס את ההגדרה משמאל לימין, מוגדר תחילה הערך שהפונקציות מחזירות, שהמצביע אמור להצביע עליהם. לאחר מכן, בתוך סוגריים, מוגדר שס המצביע לאחר התו *. לאחר שם המצביע מוגדריס סוגי הפרמטרים שמועברים לפונקציה. כדי להפעיל פונקציה דרך מצביע, יש לספק את הארגומנטיס ולבצע את פעולת ייהתוכןיי על המצביע באופן הבא: ;(ם8 ,... ,82 ,81) (62ס*) כדי להבהיר נושא זה נציג דוגמה פשוטה. נגדיר שתי פונקציות, אחת מחשבת סכוס של זוג מספרים, והשנייה - מחשבת את המכפלה שלהם: (2א סת1 ,1א 6םת1)תטפ5 %6ם1 ;(2א + 1א) םמעגמ66ע (2<< %ם1 ,1א %ם1%)1טת %ם1 ; (2א * 1א) םמעג6%0ת 2 ,1א סם1 מסנמח ת0ס61סםגט? 8 60 ע6סם1סק 8 // ;(6ם1 ,6ם1) (סםמט2*) 6ם1 6מס 5םעט6%0ע בשת8 פפ6מתטת סטף 68%68 // פרק 1: סקירה של שפת 6 - 35 ;תטפ = סםתט1 3 --> 1א // ;(2 ,1)(סםט+*) = 1א ;+1טת = סםט1 2 --> 2א // ;(2 ,1)(סםמט+1*) = 2א דוגמה זו מראה מצד אחד את הגמישות אשר מושגת בעזרת מצביעיס לפונקציות, ומצד שני קטע הקוד אינו ברור. לא תמיד ברור לאן מצביע המצביע לפונקציה, כלומר, לא ברור תמיד איזו פונקציה תתבצע כאשר מפעיליס פונקציות באמצעות מצביעים. בדוגמה וו ההשמה למצביע נעשית בסמוך להפעלת הפונקציה. לכן, מצב זה עדיין קל יחסית. ייתכן מצב בו ערך המצביע נקבע במקוס אחר בקוד מאשר המקוס שבו מופעלת הפונקציה! אופרטורים להוספה והפחתה ראינו שיש אופרטוריס המאפשריםס להגדיל, או להקטין משתנה ביחידה אחת. האופרטור ++ מאפשר להגדיל משתנה ביחידה אחת, בשעה שהאופרטור -- מאפשר להקטין משתנה ביחידה אחת. אופרטוריס אלה ניתניס להפעלה בשתי דרכים : שני האופרטוריס הראשוניס מגדיליס את המשתנה 1 באחד, ואילו שני האחרוניס מקטיניס את המשתנה 1 באחד. אמנס, האופרטוריס מבצעים פעולות והות - אבל יש משמעות והבדל בסדר הפעולות. כאשר כותביס את האופרטור ++ מימין לשס המשתנה, כמו למשל ++1, משתמשיס תחילה בערך של המשתנה 1 ולאחר מכן מגדילים את ערכו באחד. פעולה כזאת היא פעולה מאוחרת: א11)פס, כלומר שינוי ערך המשתנה מתרחש לאחר השימוש בו. לעומת זאת, כאשר כותביס את האופרטור ++ משמאל, כמו למשל 1++, מגדיליס תחילה את ערך המשתנה 1 ורק לאחר מכן משתמשים בו (בערך החדש). ווהי פעולה מוקדמת : צו)6יזק. חשוב להבחין בדרך שבה משתמשיס בערך של המשתנה, לפני או אחרי שינויו, כמו למשל כאשר מעבירים אותו למשתנה אחר. למשל: ;> ,ך 6ם1 :ב = כ 2 --> % 2+ = % 2 --> % ;++ך = א% בקטע התוכנית הנייל המשתנה ( מקבל את הערך 1. לאחר מכן המשתנה % מקבל את הערך של המשתנה [ לאחר הגדלתו, כלומר % מקבל את הערך 2. בשורה הבאה מקבל % את הערך של [ ולאחר מכן מוגדל המשתנה [. לכן, בסוף קטע זה, הערך של א% הוא 2 ואילו הערך של [ הוא 3. 6 ++6 ו-009 למתכנת המקצועי ביטויים לוגיים במשפטי בקרה (שנלמד בהמשך) יש בדרך כלל תנאי לוגי (מ0ו610ם60 [108108), אשר נבדק וכתוצאה מכך מתבצע חלק זה או אחר של משפט הבקרה. התנאי הלוגי הוא ביטוי של השפה, אשר מתפתח לערך השונה מאפס, אמת - ערך 1 (₪6*ש6), או שקר - ערך 0 (18189). למשל, ביטוי מהצורה: 9 0-2 מציג ערך לוגי 1 אם המשתנה א מכיל ערך הגדול מ- 5, אחרת הוא מציג ערך 0. כל פעולת השוואה מציגה בסיומה ערך לוגי, כפי שנראה להלן: צ<א הביטוי מקבל ערך אמת אס הערך של המשתנה א גדול מהערך של ץ, אחרת ערך 0. ץ>א הביטוי מקבל ערך אמת אס הערך של א קטן מהערך של ץ, אחרת ערך 0. ץצ=<א הביטוי מקבל ערך אמת אס הערך של א גדול או שווה לערך של צץ, אחרת 0. ץ=>א הביטוי מקבל ערך אמת אס הערך של א קטן או שווה מהערך של ץ, אחרת 0. 5 הביטוי מקבל ערך אמת אס הערך של א שווה לערך של צץ, אחרת 0. ץ=!א הביטוי מקבל ערך אמת אס הערכיס של המשתנים א ו-ץ שונים, אחרת 0. השוואות אלו פועלות על כל משתני השפה. כאשר המשתניס הס מצביעים, ההשוואות פועלות על הכתובת, ולא על תוכן המצביע. אפשר לצרף מספר ביטוייס כאלה ולקבל ביטוי מורכב יותר. צירוף הביטויים יכול להיעשות בעזרת האופרטוריס הבאים: *‏ 88 - שקול ל-6פה לוגי (ייגם'', ''יוגם'י), ומקבל ערך השונה מאפס, אס שני הביטוייס עליהס הוא פועל שוניס מ- 0. > | - שקול ל-זס לוגי (ייאויי), ומקבל ערך השונה מאפס, אס אחד מהביטויים עליו הוא פועל שונה מ- 0. למשל, כאשר ברצוננו לבדוק אס הערך של משתנה נמצא בין חמש לשבע, אנו יכוליס לרשוס את הביטוי הבא : 7 => א 68 5 =< א הביטוי הזה מציג ערך אמת (1) רק אס המשתנה א נמצא בתחוס המבוקש, אחרת הוא מציג ערך 88856. לעומת זאת, אס אנו רוציס לבדוק אס המשתנה הזה אינו נמצא בתחוס, נכתוב את הביטוי הבא: שר ו|ן- ‏ %% פרק 1: סקירה של שפת 6 - 37 מספיק שאחד מתת-הביטוייס מקבל את הערך 1, אז הביטוי הכולל מקבל את הערך 1. בצורה וו אפשר להרכיב ממספר ביטוייס ביטוי מורכב יותר. אין הגבלה של השפה על מספר תת-הביטוייס הנכתבים בביטוי. האופרטור ''!יי (סם, יילאיי) הופך את הערך של הביטוי מ- 0 ל- 1 ולהיפך. כלומר, האופרטור הופך את הביטוי מערך אמת לערך שקר. לכן שני הביטוייס הבאיס שקולים: (7 => א 86 5 =< א) <==> (7 < א || 5 > א)! אופרטורים הפועלים על סיביות 60 היא שפה יעילה המאפשרת לפעול על סיביות בודדות של מילת מחשב. בדרך כלל, פעולות אלו לא נתמכות בשפות עיליות אחרות וכדי לממשן כותביס את הביטוייס האלה באסמבלר (שפת מכונה). יש שני סוגיס של פעולות כאלה: פעולות לוגיות (07811005ק0 [108108) על סיביות ופעולות הזזה (80105ז6קס 1ם5) של סיביות. פעולות לוגיות על סיביות ביטוייס לוגייס על סיביות מאפשריס לקבל ערך של סיבית, או לשנות ערך של סיבית. יש שני אופרטוריס המבצעיס פעולת 6חתו או זס על משתנה: 8 - מבצע פעולת 86 (י'וגם", או 'יגם'י) ברמת הסיביות בין שני ביטוייס. | - מבצע פעולת עס (י'אויי) ברמת הסיביות בין שני ביטויים. למשל: 12 ,3א ,2א ,1א סם1 2 = 1א ;2 = %2 2 6 1א = 3א 2 | 1א = 4א במשתנה 1א יש את הערך0...1 ואילו במשתנה 2א יש את הערך 00...10, ולכן לאחר פעולת 01 מקבל המשתנה 4א את הערך 0...011 ואילו 3א את הערך 0...0. אופרטור נוסף הוא האופרטור * אשר מבצע פעולת זסא מס 6טופט]6א6, "זה או וה בלבדיי) על שני משתנים או ביטוייס. התוצאה של פעולה זו היא ברמה של סיביות. אס הסיביות של שני הביטוייס הנתוניס לאופרטור דולקות או כבויות, תהיה הסיבית המתאימה בתוצאה כבויה. אס רק סיבית אחת (ורק אחת) דלוקה בשני הביטוייס הנתוניס לאופרטור דלוק, תהיה הסיבית המתאימה בתוצאה דולקת. למשל: 16 1 = 3, 2 7 2 " 1א = 3א 6ם1 8 ++6 ו-009 למתכנת המקצועי המשתנה 1א מכיל את הערך 00...11 ואילו המשתנה 2א מכיל את הערך הבינארי 0, ולכן התוצאה של הפעלת האופרטור האחרון תהיה 00...01. במיליס אחרות, הערך של 3א יהיה אחד. פעולות הזזה על סיביות אפשר להזיו את הסיביות במשתנים שלמיס מסוג: שתס), +זסת8, זגת6, +מוּ. דבר וה נכון גס למשתניס מהסוגיס הקודמיס ללא סימן, כלומר, למשתנים מסוג 66ח18פתט. ההזזות של ערכיס אלו מתבצעות על ידי שני אופרטוריס : >= << - הזזה ימינה של הביטוי הנתון. > >> - הזוה שמאלה של הביטוי הנתון. למשל: ל 7 2 1 5ב 2 = 1א 2 >> 1א = 2א ;82 = 3א ;2 << 3א% = 2א המשתנה 2א מקבל את הערך של המשתנה 1א (שהוא במקור 0001 בינארי) לאחר שערך זה הוזו פעס אחת שמאלה. לכן, בשורת ההשמה הראשונה של 2א יקבל משתנה זה את הערך 2 (כלומר - 0010 בינארי). בשורת ההשמה השנייה של המשתנה 2א מוכנס אליו הערך של 3א (שהוא 8, או 1000) לאחר הזזה ימינה פעמיס (שתוצאתה 0010). לפיכך, בסוף קטע הקוד הזה, המשתנה 2א מכיל את הערך 2. מחרוזות מערכים מיוחדים ב-6 הס מחרוזות. מחרוזות הס מערכים של תווים (זגּם6). למשל מערך של מערך של תוויס יכול להיראות כך: ; "8000" = ע860* עַהםס המחרוזת "6ַסטג" היא כתובת בזיכרון של מערך של תוויס. כאשר כותבים ביטוי כזה, המהדר דואג לסייס את המחרוזת תמיד בערך מיוחד, אשר מסמן את סוף המחרוזת. ערך וה הוא אפס. לפיכך, מערך של תוויס דומה למערך של שלמים, פרט לעובדה שיש לו אלמנט נוסף שמסמן את סופו והוא הערך אפס. אפשר היה להגדיר את המערך הזה בצורה הבאת: ;"8000" = []502 עַַַםס עתה 8% הוא שס של מערך בגודל חמישה תווים, כאשר התו הנוסף הוא התו ""אפסיי בסוף המערך. המהדר מקצה את הצזיכרון בגודל המתאים למערך זה באופן אוטומטי. פרק 1: סקירה של שפת 6 - 39 משפטי בקרה משפטי בקרה מאפשרים לנו כתיבת לולאה. בשפת 6 יש משפטי בקרה מסוגים שונים, כפי שנראה להלן. משפט הלולאה שווחש משפט הלולאה 116גש ('יכל עוד...") מאפשר להגדיר לולאה (00ס1) פשוטה. היא פועלת, כלומר המשפט או המשפטים הכלולים בה מתבצעים, כל עוד מתמלא התנאי הכתוב בפקודה. נבחן את הפקודה באמצעות דוגמה של העתקת מחרוות. נכתוב פונקציה אשר מעתיקה מערך של תוויס אחד למשנהו. (20ע5* ע8םת0 ,08%* ע8ם7)0ץ56200 הנ1בסט ;ך %ם1 72 = כ + ([0ר]6ע52) 118תט 2 = [456]17 ;ר++ הפונקציה עק5₪06 מקבלת שני מצביעיס לתחילת המערכים ומחזירה ערך 016צ. מילת המפתח 6וסץ אינה מציינת ערך מסויס ואין משתניס מסוג גה. במקרה זה מילת המפתח שנס מציינת שהפונקציה אינה מחצירה כל ערך. המצביע הראשון (680) מתייחס למערך שאליו יש להעתיק את המערך שהמצביע השני (0ז8) מתייחס אליו. הפונקציה עושה שימוש בכך שהמערך של המקור חייב להסתייס באפס. בלולאה 6!ותאי היא מעתיקה את תוכן המערך אל המערך המבוקש, עד לתו אפס (זהו תנאי משתמע מהגדרת המחרוזת, שבסופה כתוב הערך 'יסיי). לאחר הלולאה הפונקציה כותבת אפס בתו האחרון שבמערך המטרה. הפונקציה 500 בגירסה הנוכחית מכילה משפט שמגדיל את המשתנה [. משפט וה יכול להיכנס למשפט ההשמה ואז הפונקציה תיראה כך: (520* ע8ת0 ,08%* ע8ם7)0ץ56200 הנ1בסט ָ 7[ שת 72 = ךכ ([ר]060ע52) 16נ1תט ;[++ר]58520 = [ר]456 72 = [0כ]0385%6 0 | ++6 ו-009 למתכנת המקצועי אנו מגדיליס את [ לאחר השימוש בערכו. לפיכך, המהדר מחשב תחילה את הכתובת של האלמנט [ במערך 6זג, והוא משתמש בערך זה כדי להשים את הנתון למערך +68 במקוס ה-[. הבעיה בגירסה זו של הפונקציה היא שתחילה (במקרים מסוימים) מבוצע הצד הימני של משפט ההשמה, ולאחר מכן הצד השמאלי. לכן, ההשמה תתבצע לאלמנט הבא של 65%%. ב-6 אין הגדרה קבועה לסדר של משפט ההשמה. דרך אחרת לכתוב את הפונקציה הזו היא להשתמש באריתמטיקה של מצביעים. נכתוב את הפונקציה בצורה הבאת: (520* ע8ת0 ,08%* ע8ם7)0ץ56200 הנ1בסט ו ] (0ע82*) 16נ1תט 7+ = 45₪* ;5+ 7+ ] *0456₪ = 0; ] בגרסת המצביעים אנו מקדמיס את המצביעיס במקום להגדיר משתנה אינדקס למערך ולקדסם אותו. למרות שבגירסה זו יש יותר משפטים, היא הרבה יותר מהירה מהגירסה הקודמת, מכיון שכאשר משתמשים באינדקסים למערך יש לבצע פעולת חיבור בכל פנייה עס אופרטור המערך []. לכן, משפט כמו [[]526]![=680 מחייב חיבור של הערך 1 לכתובות של תחילת שני המערכים. בנוסף, היה עלינו להגדיל את המשתנה [ בגירסה הקודמת. בגירסה זו יש לנו רק שתי פעולות אריתמטיות, ואילו בגירסה הקודמת היו לנו שלוש. ניתן לקצר את הפונקציה הזו בצורה יותר קומפקטית באופן הבא: (20ע5* ע8ת0 ,08%* ע8ם7)0ץ56200 הנ1בסט ָ ;ק (++0ע80* = ++08%*) 16נתט ו הפונקציה צומצמה לשורה אחת בלבד. בתנאי של משפט 6!וי מתרחשת ההשמה של התו הנוכחי ששני המצביעים מצביעים עליו, ולאחר מכן מקודמיס המצביעים. הערך של משפט ההשמה הוא התו האחרון אשר הושס. אס הערך הוא אפס, כלומר, סוף המחרוזת - אזי הסתיימה ההעתקה. למרות שהגירסה הנוכחית של הפונקציה קצרה מהגירסה הקודמת, היא פחות יעילה. הגירסה הנוכחית משתמשת באופרטור ++ בצורה שבה נלקח הערך של המשתנה ורק אז מוגדל המשתנה. לכן, על המהדר לזכור את הערך של המשתנה במשתנה זמני, לקדס את המצביע ואז להשיס את הערך הזמני למקוס המתאים לפי מצביע המטרה 680). ההשמה למשתנה הזמני דורשת זמן, ולכן הגירסה הנוכחית איטית יותר בביצוע מהגירסה הקודמת. פרק 1: סקירה של שפת 6 41 משפט התניה ]ו משפט התניה ב-6 מורכב לפחות ממילת המפתת 11 (ייאם'י) ולעיתיס עס מילת המפתח 6 (''אם לא'י). הצורה הכללית של משפט הבקרה נראה כך: ]1 (861ם00) 15 ; 5%68%1 ] ) (082ם00) 15 6156 ; 568%2 ]1 0186 ;ת568% ו אפשר להסתכל על משפט הבקרה 11 כמורכב משני חלקיס עיקריים: חלק של 32 וחלק אופציונלי של 61856. החלקיס האופציונלייס יכוליס להיות מורכביס ממספר חלקיס של 6. כאשר התלקים הפנימיים של 6156 חייבים להיות מסוג 11-686. רק המשפט האחרון יכול להכיל 6156 בלבד. משפט בקרה זה מבוצע מהתחלה שלו (ַאק-11) והלאה. אס נמצא תנאי שמתפתח לערך אמת, ההסתעפות המתאימה של המשפט מבוצעת. אס אין שום הסתעפות שהתנאי שלה שונה מאפס ויש חלק 686 - מבוצע חלק זה. אס אין חלק כזה, לא מתבצע שוס חלק של המשפט. להלן מספר דוגמאות : 1? 6 (0 < א) +15 ; ("6ט051610סק 18 א")65>תנ1עס בדוגמה זו נבדק ערכו של א. זה התנאי של משפט הבקרה, הואיל והתנאי מקבל ערך אמת (כי א גדול מאפס) יופעל הגוף של משפט הבקרה (4מוזק). במקרה שיש משפט יחיד, אין צורך להכניס את הגוף בסוגרייסם מסולסלים. אפשר להרתיב את הדוגמה באופו הבא : (0 < א) +1 ; ("6ט05161סק 18 א")65>תנ1עמס 1-6 ; ("6ט1%1פסק ססם 18 א")65>תנ1עס בצורה זו של משפט הבקרה יש לנו חלק אחד של 6156, שמתבצע רק אס החלק של 11 אינו מתבצע; כלומר, אס התנאי של 11 מקבל ערך שקרי (אפס). במקרה שלנו, אס הביטוי 0<א הוא לא נכון יתבצע החלק שאחרי 6186. אפשר להוסיף למשפט הזה 68566 נוסף בצורה הבאה: (0 < א) +1 ; ("0516106סק 18 א")65>תנעס 2 ++6 ו-009 למתכנת המקצועי (0 == א) 15 6156 ; ("20620 18 א")65תנ1עס 1-6 ; ("608%106ת 18 א")65>תנ1עס החלק האחרון (61860) מתבצע, בתנאי שהמשתנה א אינו חיובי ואינו שווה לאפס. כלומר, החלק האחרון מתבצע אס המשתנה א הוא בעל ערך שלילי. צורה אחרת למשפט ההתניה היא בעזרת האופרטור ? (ייהאם'י). הצורה הכללית של אופרטור זה היא: ;(5%8%2 : 56₪8%1 ? מִתסס) משפט זה מקבל את הערך של 5911 אס הערך של 6056 שונה מאפס, ואחרת את הערך של 818)2. למשל: לבא 2 12 תי ;(2א : 1א ? 2א > 1א) = 3א בדוגמה זו המשתנה 3א מקבל את הערך המינימלי של המשתנים [א ו-2א. אס 1א קטן מ-2א תוצאת האופרטור 1 היא 1א, אחרת 2א. משפט זסז גס משפט הוא משפט לולאה (ק100). משפט זה מאפשר לבצע משפט אחד, או יותר, מספר רב של פעמים. הצורה הכללית של המשפט חיא: )+ (0םת1 ;תסנ61%תסס ;1%ם1) 10 ; ץ00ס ] לאחר מילת המפתח 107 מופיעים בתוך סוגריים רגיליס שלושה משפטים. המשפט הראשון הוא אתחול שמבוצע פעס אחת ויחידה במהלך הלולאה. בדרך כלל מאתחליס במשפט וה משתנה שהוא אינדקס, או מצביע לערך התחלתי. המשפט השני מייצג את התנאי לביצוע הגוף של משפט הלולאה. אס התנאי מקבל ערך השונה מאפס (ערך אמת הוא בדרך כלל אחד), מתבצע הגוף של המשפט אשר מופיע בסוגריים מסולסלים. החלק השלישי הוא משפט אשר מקדס אינדקס בדרך כלל, או מצביע, ועקב כך יכול לשנות את התנאי של המשפט. החלק השלישי מתבצע כל פעס לאחר ביצוע גוף משפט הלולאה. הגוף של משפט הלולאה מופיע בסוגרייס מסולסלים ומורכב ממשפט ביצוע אחד, או יותר. אס קייסם רק משפט ביצוע אחד, אין צורך בסוגרייס המסולסלים. משפטי ביצוע אלה יכוליסם להיות גס משפטי בקרה אחרים, ואין הגבלה איזה משפטים נכתוב, או בכמה רמות קינון נשתמש. פרק 1: סקירה של שפת 0 - 43 משפט הלולאה 101 שקול למשפט הלולאה 6!ו1ש הזה : הת 3 ] (תס1נ1%הםתס60ס) 16נ1תשט ; ץ00ס ; סמ ] נדגיסם את משפט הלולאה 10 על ידי חישוב הממוצע, כמו שעשינו באחד הסעיפיס הקודמים. (פסתטסס 6ם1 ,עע8* 6ם1)עטה8 1108% / 2 = תטפ ,1 %ם1 (ב4+ ;%תטסס > 1 ;0 = 1)ע0ס+ ;[2]1ע82 =+ תטפ ; (%ם108%6(00+) / תטפ(108%+)) מעג66ת ו בדוגמה זו מאותחל האינדקס של הלולאה 1 לאפס בחלק האתחול של משפט הלולאה. התנאי של הלולאה בודק אס האינדקס קטן ממספר האלמנטים במערך. משפט ההגדלה של האינדקס מגדיל את המשתנה 1 בכל פעס שהלולאה מבוצעת, והוא עושה זאת לאחר ביצוע גוף הלולאה. לכן, לאחר הפעס הראשונה שמתבצע גוף הלולאה ([11]1 =+ בתטפ) יקבל המשתנה 1 את הערך אחד (1). משפט 6ווח/ש-₪60 משפט 8116או-60 ('יבצע כל עוד...'י) הוא משפט לולאה שדומה למשפט 116תאי אך סדר הפעולות וההתניה שוניס בו. המבנה הכללי של המשפט: ] 60 ; %8ת56086606 ; (ע02קא6) 16נ1םח [] תחילה מוצגת מילת המפתח 60, ולאחר מכן מופיעים משפטים לביצוע בין סוגריים מסולסלים. אם יש משפט ביצוע יחיד, אין צורך בסוגרייס המסולסלים. לאחר הסוגריים מופיעה מילת המפתח 16ואו ולאחריו בין סוגריים ביטוי אשר מקבל ערך אמת או שקר. גוף המשפט (המשפטים בין הסוגריים המסולסלים) מתבצעים לפחות פעם אחת וממשיכיס להתבצע כל עוד התנאי של הביטוי שלאחר ה-6|ואי הוא ערך אמת (₪₪6)). לכן משפט זה וזּהה למשפט 6!ואו, פרט לכך שהלולאה מתבצעת לפחות פעסם אחת. בגוף המשפט יכולים להופיע משפטים אחרים, כולל משפטי בקרה, ואין מגבלה לסוג המשפטים שנכתבים או למספר המשפטים המקוננים. 4 | ++6 ו-009 למתכנת המקצועי משפט ח6)0ו/5 משפט בקרה ח6גאו8 ('ימַתָּג'י, או 'ימיתוגיי) מאפשר לבחור בין מספר אפשרויות של ערכים שלמיס ולבצע משפטיסם של 6 בהתאס לבחירה. המבנה הכללי של משפט הוא : ]1 (81ט-%ת1) 60 באפ :1 08856 ;568%1 ;268% :1 0886 ;52 ;268% :ו 7ת5680 268%; ו משפט טוש הוא משפט בקרה הסתעפותי רב שלבי. לאחר מילת המפתת 51066 נכתב בין סוגרייסם משתנה שמכיל ערך שלם. משתנה שלס (ו) הוא משתנה מסוג: שַת0], זהתס, +ת1 או כל אחד מאלה בצירוף מילת המפתח 66ח18פתט. הגוף של המשפט שנמצא בין סוגרייס מסולסלים מכיל מספר משפטי 0886 ואפשרות למשפט )66/01 אחד. המשפט 661401 הוא משפט ברירת המחדל שמתבצע אם כל שאר האופציות אינן בעלות ערך אמת. אין חשיבות לסדר ההופעה של המקרים (60886) וברירת המחדל (0 1 ). לאחר כל מילת מפתח 6886 (י'אירוע'' או 'ימקרהיי) מופיע ערך שלם, אשר מציין מתי לבצע את המשפטים שאחריו. כלומר, אם הערך שעליו מבצעיס את משפט 5100 זהה לערך של משפט 64986 (הערך שכתוב לאחר מילת המפתת 6486) מתבצע משפט זה. בסוף כל משפט 0886 נהוג לכתוב 968%. מילת המפתח האחרונה מסמנת למהדר שאין צורך לבצע את המקרה (6850) הבא. אס מילת מפתח זו חסרה, יבוצע משפט 6886 הבא אחריו. לפיכך, מתבצע משפט 6986 אשר הערך שלו והה לערך של המשתנה הנוכתי שעליו מבצעיס את ג8110. משפט זה שקול למשפטיס הבאים: ] (811ט == 81ט-%6ם1) +1 ; 568%1 ] ] (812ט == [8ט-6ת1) 1% 6156 ; 56862 ] ] 60186 ;ת568% פרק 1: סקירה של שפת 6 45 למשל אנו יכוליס לכתוב את קטע הקוד הבא : ;א סם1 ] (0 < א) ב166ח5 :1 0886 ; ("ת581%106סק 18 א")%1מנועק ;68%ע2ס 1 08856 ; ("ת6ט1610פסק ססת 18 א")61ת1צק ;68%תס :1 ; ("תתפסקאת ססם 61)"60016ת1צס ;268% ו התנאי 0<א יכול להתפתח לשני ערכים 1 או 0. אם הביטוי 0<א מתפתח ל-1, אז מתבצע המקרה הראשון 1 64986. לעומת זאת, אס הביטוי מתפתח לאפס, מתבצע המקרה השני 0 688%6. המקרה האחרון שהוא ברירת המחדל (66/901) אינו מתבצע בדוגמה זו. כאשר האפשרויות לבחירה הן שלמים, אזי משפט 5816 הוא האפשרות המתאימה ועדיפה על פני משפט הבקרה 1-6886. |1.5 | רשומות רשומות הן מבנים (50000000) הן הכלי ששפת 6 מספקת כדי לאגד מספר סוגי משתניס במבנה אחד. כאשר יש אובייקטים, או ישויות, במרחב הבעיה אשר מייצגיס נושא אחד, אפשר לאגדס ברשומה אחת. המבנה הכללי של רשומה הוא: ) שתהא 06וע5% 5 טס ססות ו הרשומה מתחילה במילת המפתח 5698666 (יימבנה'י), ולאחר מכן מופיע שס הרשומה. שס הרשומה הוא אופציונלי ואינו חייב להופיע. אס אין שס לרשומה, אי אפשר להגדיר לה מופעים נוספים (מאוחר יותר נראה כיצד אפשר לעשות ואת). לאחר שס הרשומה מופיעים המבניס אשר שייכים לה. בין מבניס אלה יכוליס להופיע רשומות אחרות. תכונה זו מאפשרת לבנות רשומות מסובכות וגדולות. אין מגבלה על מספר תת-הרשומות, או למידת הקינון שלהן. דוגמה לרשומה המייצגת נקודה המכילה קואורדינטות א ו-ץ: ]) ףתנסע 562606 ;ץ ,א %ם1 ל 6 ++6 ו-009 למתכנת המקצועי הרשומה שהוגדרה כאן היא בעלת השס )מוסק. שני המבניס ברשומה הס מסוג שלמיס. הצהרה זו אינה מקצה זיכרון או משתנים, אלא רק מוסיפה סמל לטבלת הסמלים של המהדר. אפשר להגדיר משתנה מסוג הרשומה בדרך זו: ;>מס סת1סע 06גע56 5 = א.סתס 2 = ץ.סמס בדוגמה הגדרנו משתנה ומק מסוג 1מוס, בצורה זו יש להוסיף את מילת המפתח )100ו8. בשתי השורות שלאחר מכן מוכנסים ערכים 5 ו-6 לשדות א ו-ץ בהתאמה. הפנייה לשדות הרשומה נעשית על ידי האופרטור ''.", המפריד בין שס הרשומה לשס השדה שפונים אליו. אם יש קינון של מספר רשומות, הפנייה לשדה ברשומה תיעשה כך: ;א א 06גע50 72 = 2.3ת.1ת.א כלומר, מפעילים את האופרטור "." מספר פעמים לפי עומק השדה שאליו רוציס להגיע. ב-++?6 אין צורך להוסיף את מילת המפתח )51006 וניתן לעשות זאת בצורה הבאה: ;%מס סתנ1סק כדי להגדיר מצביע לרשומה ניתן לעשות זאת בצורה הבאה: ;צפס6תק* %ם1סקע ססגוע56 או ב-++6 אפשר להגדיר ואת ללא מילת המפתת )81-00 בצורה הבאה: ;צפספתק* %םנ1סק ;מק = עסקפתק 2 = א<-עס6ס הכנסת הערכים או פנייה לשדות במקרה שיש מצביע לרשומה נעשית על ידי האופרטור <- שמבצע פעולה זהה לאופרטור יי.יי על רשומות. בדוגמה השדה א מקבל את הערך 1. שימוש ב-06061ע! בעזרת משפט ]10606 ('יהגדר סוג'י) ניתן להגדיר שס חדש לסוג מסוים. בצורה זו אפשר לקצר ולחסוך כתיבה של שמות. הצורה הכללית של משפט זה היא כדלהלן: ; סזהת-טחטסת סתהַת-6סץץ6₪ 6061סץ6 המשפט מתחיל במילת המפתח 060661), לאחר מכן מופיע שס הסוג של המשתנה שעבורו מגדיריס שס חדש. לבסוף מופיע השס החדש של אותו סוג. למשל: ;%מנט סת1 606ם18פםתט 6661סעץ6 ;הסט ע8ת0 606ת16פתט 6661סעץ6 פרק 1: סקירה של שפת 6 | 47 בשתי השורות האלו הגדרנו שני שמות חדשים לסוגיס בסיסיים אשר קיימים בשפה, + ו-זהתסט. הראשון מביניהס מתאיס לסוג שלס ללא סימן, ואילו השני מתאיס לסוג תו ללא סימן. לאחר הגדרות אלו אנו יכוליס להגדיר את המשתניס הבאים: 2 סתנט 7 סת1 60ם16פמגו 7 08 60מ2ם16פ8םגו 7 מהת6סגט המשתניס 11 ו-12 הס מאותו הסוג, שלס ללא סימן (18060פ5חט). המשתנים 61 ו-02 הס מאותו סוג, תו ללא סימן. בדומה אפשר להגדיר שס חדש לרשומה שמייצרת נקודה, כך: ] %סטע56 061ס6סץ6 ;ץ ,א 6ם1 2 ן ק1מס* ,1 סמנסע ;01 = 1סס במשפטיס אלה הגדרנו משתנה מסוג זמוסע בשס 1. בנוסף, הגדרנו משתנה המצביע ל-+ם01? בשס 1סס. כדוגמה לרשומה יותר מורכבת, אנו יכוליס להגדיר רשומה המייצגת קו ישר. כידוע, קו ישר מוגדר על ידי שתי נקודות, ולכן אנו יכוליס להשתמש בהגדרות הקודמות של נקודה כדי להגדיר קו ישר באופן הבא : + פת1 562606 %תוסק 1128% // 2 סת1סק 1% 865006 // 2 סם1סק ;ן 2 תג 2 = א.11.01 ?= ץע 11.01 ;5 = א.11.02 11.02. = 2 בדוגמה זו הגדרנו ישר אשר עובר דרך ראשית הציריסם ודרך הנקודה (5,6). כדי להכניס ערכים אלה לשדות המתאימים, יש להשתמש בשס השדה המתאים לאחר הנקודה. כך למשל, שורת ההשמה הראשונה כותבת את ערך אפס (0) לשדה א של הנקודה הראשונה בקו. 8 | ++6 ו-009 למתכנת המקצועי פונקציות רקורסיביות פונקציות רקורסיביות (5ת10ז0ם10 6טופעטס6ע) הן פונקציות אשר קוראות לעצמן באופן ישיר, או בלתי ישיר. פונקציות רקורסיביות יעילות במספר הגדרות מתמטיות, או באלגוריתמיס של מיון. למשל, ההגדרה המתמטית של עצרת (6 היא : !(1- ם) * ם = !ם ו 1 = 01 בצורה זו אפשר לכתוב פונקציה רקורסיבית שמחשבת עצרת של מספר כלשהו. (ת %ם1+80%02181)1 %ם1 ן 2 תעג6%עת ;(1 - ם)80%02181+ * ם םמ%ג6%0ת הפונקציה שמחשבת את ערך העצרת במקרה זה אינה יעילה, מכיון שהיא מבצעת 1-ת קריאות לפונקציות. אפשר לתקן את הפונקציה בצורה הבאה: (ת %םת80%02181)1+ 6ם1 ;% ,1 = 26585 6ם1 (%++ ;ם => % ;2 = א) ע0ס+ ;8 * 268 = 268 82 תלגע ו בגירסה השנייה, הפונקציה אינה קוראת לפונקציות אחרות (או לעצמה, במקרה הרקורסיבי), אלא מבצעת את החישוב בעזרת לולאה. לא תמיד אפשר לפתור בקלות כה רבה בעיה כזו, ואז יש לכתוב פונקציה רקורסיבית. כאשר נקראת פונקציה, המשתנים בפונקציה נכתביסם במחסנית של התוכנית, וגם הפרמטריס הנמסרים לפונקציה מועתקים אל המחסנית. אין כל קשר בין המשתנים של הפונקציה הקוראת לאלה של הפונקציה הנקראת. תכונה זו מאפשרת לבצע קריאות רקורסיביות לפונקציות. דוגמאות לקלט/פלט בסיסי קלט/פלט בסיסי כולל את האפשרות לקלוט תו אחד, או לפלוט תו אחד. בסעיף זה נראה קלט/פלט בסיסי כזה ומספר תוכניות שימושיות שמאפשרות תהליכים פשוטיס ושימושיים. שתי הפונקציות הבסיסיות שישמשו אותנו כאן הן: ; () 6660582 6ם1 ; (8₪ת0) ע8םספטק 18סע פרק 1: סקירה של שפת 6 | 49 הפונקציה :860009 קוראת את התו המגיע מהקלט ומחזירה את ערכו. אס הפונקציה מגיעה לסוף הקובץ, מוחזר 501 שהוא סמל קבוע המוגדר על ידי משפט 4606. משפט 6מ:/661 מוכר על ידי קדס המהדר אשר מופעל לפני המהדר, מבטל את ההערות ומבצע מספר מבני בקרה. נחזור לנושא וה בהמשך פרק זה. בכל הדוגמאות שלהלן נשתמש ביכולת של מערכות הפעלה כמו א1א11ז לנתב (10011000) את הפלט, או את הקלט של התוכנית, בעזרת האופרטוריס < או > של מעטפת (81611) מערכת ההפעלה. כלומר, אס מפעיליס תוכנית נש כלשהי בצורה הבאה: סטס < ם1 > ס הקלט הסטנדרטי של התוכנית ינותב לקוב> םו, הפלט ינותב לקובצ זס. ספירת תווים בקובץ נתון הדוגמה הראשונה תהיה של תוכנית הסופרת את מספר התוויס בקובצ נתון, ומדפיסה את מספר התוויס. ()מ1נהת %ם1 / 2 ,0 = פפ8תסת 6ם1 (0% =! (()46₪0282 = 0)) 16נ1נתט ; 875תסת++ ; (858תסם ,"מת828ת0 %6 858ם 11)"1116ת1צק 02 תעמגו6%ת ו התוכנית קוראת את התווים מהקלט הסטנדרטי, תו אחר תו, עד שנקרא ערך המסמן את סוף הקוב>. הפונקציה 8610041 מחזירה שלם, מכיון שיש ערך נוסף, פרט לערכים הרגילים של תוויס, המסמן את סוף הקובצ. כלומר, מכיון שרוצים לקרוא את כל סוגי התווים, הפונקציה צריכה להחזיר ערך השונה משאר התווים שמסמן את סוף הקוב>. העתקת קבצים אפשר לשכלל את הדוגמה הקודמת, בכך שנעתיק קוב כלשהו לתוך קוב אחר ונחזיר את מספר הבתיס בקובצ המקור. גם בתוכנית זו אנו קוראים תו אחר תו מהפלט הסטנדרטי, וכותביס תו אחר תו לפלט הסטנדרטי. כאמור, אנו משתמשים ביכולת של מערכות הפעלה כמו א1%את1ז, 205 או פשסמנ/ו, לנתב את הפלט, או את הקלט של התוכנית אל קבצים. לכן, הפעלה של התוכנית הבאה בצורה )טטוטס<)טקם1>ץק0ס מנתבת את הפלט של התוכנית לקוב זטקפו ואת הפלט לקוב )וטטוטס. ()ת1נהת %ם1 2 ,0 = פעאתסת 6ם1 ] (20%9 =! (()06₪0282 = 0)) 16נ1נתט 0 | ++6 ו-002 למתכנת המקצועי ;828ם0ת++ ; (0) 82תס6טוס ] ;פַפַהתסת תע0ו66ת ו תוכנית זו, שלא כמו התוכנית הקודמת, אינה מדפיסה את מספר התווים לפלט הסטנדרטי. אס התוכנית היתה מדפיסה את מספר התווים, אזי דבר זה היה מודפס לקובצ המטרה. תוכנית זו כמו התוכנית הקודמת אינה יעילה, משוס שהקריאה לפונקציה עבור כל תו (6082). אנו מדגימיס את השימוש במבני השפה, ולכן איננו שמיס דגש על יעילות. בפרקיס הבאיס נראה דוגמאות רבות לשימוש יעיל בכליס המסופקים על ידי ++6. ספירת בתים ושורות הדוגמה הבאה היא של תוכנית הסופרת את מספר התוויס ואת מספר השורות בקוב>. כדי לספור את מספר השורות, יש להשוות את התו הנקרא לתו המייצג שורה חדשה. אם תו זה אכן זהה לתו המייצג שורה חדשה יש להגדיל מונה. ()מנאת 6ם1 2 ,0 = 6889ם11ם ,0 = פַּכַםסת %ם1 ] (09 =! (()86₪0282 = 0)) 16נ1גתט ;828ת0ם++ ('מ' == 60) +15 ;8ת11ת++ ] ,7 ,"תפע8םת0ס %8 6םת8 68ת11 %8 פהם 61)"1116ת1צס ; (8עַאתסת ;0 ת00ו6%ת2 1 כדי לקבל תווים מיוחדים, כמו התו המייצג שורה חדשה, יש להקדימו בתו (לוכסן הפוך) כאשר שני התווים נמצאיס בין גרשיים בודדים מסוג '. יש מספר תווי בקרה שימושייס שמפורטיס כדלהלן: * 'ע' - שורה חדשה (6מו1 ש6ם). * ש' - טבלר (99ו) סדרה של מספר תוויס רקיס, בדרך כלל שמונה. * %6 - לכל תו 6, הביטוי האגה מחזיר את הערך 45611 שלו שהוא בין 0 ל-256. פרק 1: סקירה של שפת 6 | 51 קדם-מהדר ב-6 וגם ב-++6 יש שלב הקודס להידור. בשלב גה מופעל קדם מהדר (0005850זכ-6זק, שהוא רכיב של המהדר עצמו), אשר סורק את קוב הקלט ומבצע משפטים המתחילים בתו 8 כל משפט כזה מסתיים בסוף השורה. אס יש צורך להמשיך משפט בקרה כזה מעבר לשורה אחת, יש להשתמש בתו לפני סוף השורה. המעבד מבטל את ההערות אשר נמצאות בגוף התוכנית ומאחד את הקבצים שנכללו בקבצים אחרים. רק לאחר מכן, מועבר הקוד המעובד למהדר. הכללת קבצים הכללת קבצים נעשית על ידי מילת הבקרה 1861₪886, אשר נכתבת לאחר התו המיוחד המציין את פקודות הקדס המהדר: <6ת8ת1116> 610066ת1+ "סתה8ת116+" 610866ת1+ באפשרות הראשונה שס הקוב להכללה נמצא בין <>. במקרה זה הקובצ מחפש לפי הדגליס 1-(3 מציין דגל כלשהו), אשר הועברו למהדר. למשל: 6:16- 06 פקודה וו (עם הדגל ,1-) מוסיפה את הספרייה 6םו:ס למסלול החיפוש של קבצים. במקרה זה, קדס המעבד מחפש את קוב נדרש בספרייה הנוכחית, ורק אס לא מצא אותו הוא עובר לחפש בספריות שמוגדרות בנוסף. הגדרות של קבועים משפט אחר של הקדס מעבד הוא 66486 (ייהגדר'י) שמאפשר להגדיר קבועים, או טקסט להחלפה. הצורה הכללית של משפט זה היא : 1 ש6תהת 6ת461+1+ לאחר הגדרה זו, המעבד עובר על קובצי המקור ובכל מקוס בו הוא מוצא את המילה 6אח הוא מחליף במילה [א. למשל, נהוג להגדיר את הקבועיס הבאיס באופן הבא : 1 מסתץ 6ת61+1+ 0 מפמתת 6ם046+1+ הקדס מעבד תומך במשפט בקרה אחר המאפשר לבדוק הגדרה (על ידי 1/661), כלומר, אס שס כלשהו כבר הוגדר: ₪1 [סת? +1606 1+ 6+ + 1מ6+ 2 ++6 ו-009 למתכנת המקצועי מבנה הפקודה דומה למבנה של כל פקודת +1 או 11-6186. לרוב משתמשים פקודה 11661 כדי למנוע הכללה של קבצים פעמיים. למשל, ₪ מתדע +06ם15+ ₪8 ₪ת1ע 6ם46+1+ ;(ץ %ם1 ,א 6םת1)תט5 18בסט + נמ6+ המשפט 18166 כולל בתוכו את ההמשך, אס השם המופיע לאחריו אינו מוגדר. במקרה וה תוכן הקובץ יועבר למהדר. אס השס הוגדר כבר, תוכן הקוב אינו מועבר למהדר. הגדרת תבנית פונקציה קדס המהדר מאפשר להגדיר תבנית פונקציה. אין זו פונקציה ממש אלא תבנית שנראית כמו פונקציה. כלומר, אס מופיע שס ולאחריו רשימת ארגומנטים בין סוגרייס ומופרדיס בפסיקים, המהדר מתייחס למשפט זה כאל פונקציה. קדם המהדר במקרה זה מחליף את השס של הפונקציה בגוף שלה בכל מקוס בקוד, לאחר התחלפת הארגומנטיס של תבנית הפונקציה. למשל: ((ץ) : (א) ? (ץ) > (א)) (ץ ,א)תגת 6מם8611+ 2= 8 ,1 = 7 6ם1 ;(% ,ך)םנת = 2 6ם1 המשפט אשר משתמש במילת המפתח מגגם מתורגם על ידי קדס המהדר בצורה הבאה: ;((א) : (ך) ? (א) > (7)) = 2 ס6ם1 משתמשיס באמצעי וה כדי להימנע מקריאה לפונקציות קצרות ולחסוך בזמן. מומלצ לא להשתמש ביכולת וו של 6, משוס שב-++6 יש אמצעיס אחריס וטובים יותר שנראה בהמשך. סיכום בפרק זה למדנו את המבנים הבסיסיים של 6. כאשר היה שוני בין מבנה כלשהו של 6 לבין המבנה ב-++6 הדגשנו את השוני. על כן, בפרק ה למדנו גסם את המבנים של ++6 המאפשריס תכנות פונקציונלי. תכנות פונקציונלי (פתנותנתהזפסזק [8מ0010םט)) מבוסס על פונקציות, שאחת מהן היא פונקצית ניהול ראשית שמחלקת את העבודה בין פונקציות שונות. כל פונקציה אחרת יכולה לחלק את העבודה לפונקציות אחרות שהיא קוראת להן לצורך כך. פרק 1: סקירה של שפת 0 - 53 ב-6 (וגם ב-++6) יש משתניס בסיסיים של השפה. משתניםס אלה מתאימיס לסוגים שוניס כמו תוויס (028), שלמיס קצריס (-סםף), רגילים (םו) וארוכיס (08ס). 6 כוללת משתנים ממשיים מדיוק רגיל (1091), או דיוק כפול (000516). 0 מאפשרת להגדיר מבני רשומות (30:060) אשר מאגדות מספר משתנים בסיסיים של השפה, או רשומות אחרות. אפשר להשתמש ברשומות כדי לייצג ישויות ממרחב הבעיה שאנו מנסיס לפתור. פונקציות ב-6 יכולות לקבל מספר פרמטרים ולהחזיר תשובה אחת. הפרמטריס שמועברים ב-6 הס על ידי ערך. כלומר, הפרמטר מועתק למחסנית של הפונקציה הנקראת. לכן, אס הפונקציה משנה את הפרמטר הנמסר לה, אין וה משפיע על המשתנה המקורי. תכונה זו מאפשרת לקרוא לפונקציות באופן רקורסיבי. כלומר, פונקציה יכולה לקרוא לעצמה באופן ישיר, או עקיף. כדי לשנות את הערך המועבר לה על הפונקציה לקבל מצביע. בפרקיס הבאים נתרכז במבנים של ++6 המאפשריס תכנות מונחה אובייקטים, כמו מחלקות ירושה וקשירה דינמית של פונקציות לאובייקטים. כל מה שלמדנו בפרק וה תקף עבור ++6 והינו הבסיס של שפה זו. = | 1.10 | שאלות כתוב פונקציה המחשבת ממוצע של מערך מספריס בעזרת משפט ז10. 2 כתוב את הפונקציה (8* 5₪162)00491 אשר מחזירה את אורך המערך של התוויס שהיא מקבלת. 3 כתוב פונקציה רקורסיבית הממיינת מערך של שלמים באופן הבא : היא ממיינת את שני חצאי המערך על ידי קריאה רקורסיבית לעצמה, ולאחר מכן היא ממזגת את שני החצאים הממוינים. 4. כתוב תוכנית אשר מדפיסה לפלט את מספר השורות בקובצ נתון, מספר המיליס ומספר התוויס (תוכנית או מתנהגת כמו 6אי ב-א1צת)). 5 כתוב פונקציה שמחשבת את האיבר ם-י של הסדרה הבאה: 2 - םג + 1-םג = םא כאשר 40 = 0 ואילו 41 = 1. | מקור 1 7001106 ,110016 .1 18תמ20] , 8ם18מס א. \ ם718 1800886 פתונמות4זפסזק ?6 6 4 ++-6 ו-009 למתכנת המקצועי פרק 2 תכנות מוכוון אובייקטים בפרק זה נלמד מהו תכנות מוכוון אובייקטים (שמווות8זק0ז1 100מ00119) 00[60%), או 0 נלמד על חסרונות התכנות הפונקציונלי, שהיה ועדיין מקובל כשיטת תכנות ליישומיס רביס. נתאר את ההתפתחות מהשיטות הפרוצדורליות לתכנות מוכוון אובייקטיס ונראה כיצד תכנות מוכוון אובייקטיס עונה לחסרונות אלו. כאן המקוס להדגיש שתכנות מוכוון אובייקטים ויישומו בשפת ++6 אינם הפתרון האוטומטי לכל התחלואים אותם נלמד. יש להשתמש בתבונה ב-++6, וגם בתכנות מוכוון אובייקטים, כדי להגיע לתוצאות הרצויות. |2.1 | משבר התוכנה בשנות השבעיס החלו לפתח תוכנות גדולות יותר. מחשבים מהיריס יותר, ושפות תכנות פרוצדוראליות, הס שהקנו למתכנתים עוצמה רבה. עם ואת, מרבית הפרויקטיס לא עמדו בלוח הזמניס שלהם, ואלה שעמדו בלוח הזמנים, הפיקו מוצרי תוכנה באיכות נמוכה מהצפוי. האיכות הנמוכה נבעה מהעובדה שכאשר המתכנתים נדרשו לערוך שינויים בתוכנה, הס נאלצו להשקיע מאמצים רבים כדי להשיג את מטרתם. יתר על כן, ברבות הזמן וכתוצאה מהשינויים האלה, הפכה התוכנה למסובכת והיה קשה מאוד לשנותה. כאשר הצליחו לשנות את התוכנה, גרמו השינוייס לכשלים (או באגים) במקומות לא צפויים בתוכנה. מחקריס שנעשו באותה תקופה, גילו שמירב ההשקעה בתוכנה לא היה בזמן הפיתוח, אלא בזמן התחזוקה. מתכנתים יימבליסיי ומן רב בניסיון לשיפור התוכנה והוספת אפשרויות חדשות בה. כתוצאה מפעילות זו מתגליס כשליס חדשים לתוכנה הקיימת. במיליס אחרות, התוכנה נהפכת למסובכת כתוצאה מאפשרויות שמוסיפים לה לאחר התכנון הראשוני. פרק 2: תכנות מוכוון אובייקטיס | 55 מהנדסי תוכנה שניסו לשפר את המצב, הגיעו למסקנה שחלקי התוכנה השונים תלויים זה בזה, ולכן שינוי בחלק אחד של התוכנה גורס לשינוי בחלקיםס אחרים. הבנה זו הביאה לעולס את המודולים. |2.2 | מה הם מודולים מודולים (060103גם) הס קטע תכנות, לרוב אוסף של פונקציות, שמטפלות בנושא מסויס מוגדר, כמו לדוגמה מודול המטפל ברשימה. רק הפונקציות המסוימות של המודול יכולות להכניס קישורים (8/ם11) חדשים, או לבטל קישוריס קיימים, ורק הן מכירות את מבנה הרשימה. כתוצאה מכך, כאשר משתנה מבנה הרשימה - לא מושפעת המערכת כולה מן השינוי. דוגמה: ספר טלפונים - ניסיון ראשון כדי להמחיש את הנושא נראה דוגמה. נלמד תחילה איך נכתב הקוד הדרוש בשפת 6, ומאוחר יותר נלמד כיצד ניתן לממשה ב-++6. נניח שיש לנו תוכנית אשר מתַחוקת רשימה של אנשיס ומספרי הטלפון שלהסם. אפשר להוסיף שס ומספר טלפון ואפשר להציג את רשימת הטלפונים, או את רשימת האנשים. לצורך כך נגדיר מבנה (511000016) אשר יכיל שס ומספר טלפון: % פססם 8562006 6065סץ6 ;עסמחטת 6מסםסק 6ת1 ; [32 ] סתהם מַהַםתס ו ; ססת תחילה נבנה את הרשימה כמערך (183ג) של המבנה, ונגדיר מספר מקסימלי של אלמנטיס למערך. נגדיר את הערך המקסימלי כ-5תא0סץ אגא ואת מספר האלמנטיס הנוכחיס במערך כמשתנה הגלובלי 866 )מסיטס. 0 פפמאסטק אתא 6ם%0611 2 סממםשפעטס ס6ת1 ; [5שאַסמפ אתא] פפתסםס 6סת כעת נגדיר פונקציה שמציגה את רשימת האנשיס : ()60016ק סת1עס 16סע / 2 סםת1 (++1 ;95860 %םמ6ע1>0022 ;1=0) 505 ; (סתהת. [1] פסתסםמס ,"ת%5 = סתהםת")11ת1צס 6 ++6 ו-009 למתכנת המקצועי הפונקציה עוברת על המערך עד למשתנה 6 5מסעטס האחרון ומדפיסה את השס השמור בכל רשומה. באופן דומה, אפשר להגדיר פונקציה שמדפיסה את מספרי הטלפון בלבד: () 68מסתק סת1עס ב1סע תד (++1 ;95860 %מ6ע1>0022 ;1=0) 5050 ; (ע6מתטםת 6מסמס. [1] פ6מסםמס ,"מ%6 = 6ת8ם")+65ת1שס ו לצורך הוספת אנשים ומספרי טלפון, צריכה לחיות לנו פונקציה נוספת שנקרא לה סמסונן 866. פונקציה זו מקבלת שס ומספר טלפון ומכניסה אותו למערך הרשומות. (תגטם %ם1 ,סתםת* כַַםת0) סתסתק 800 בנ1סעט ו ;מתטת = ע6סתגות 6תסםס. [₪566 6תס6פעגוס] פ6מסמס ; (6תהת ,סתהם. [++560ט 6ם6ע2טס] פסתסםס) 56200 1 במהלך הזמן יקרה לתוכנית הקטנה שלנו מה שקורה לפרויקטיס גדוליס: הרחבות כתוצאה מדרישות נוספות, או דרישות שלא הובנו היטב מלכתחילה. למשל, ברבות הומן ניצור פונקציות נוספות אשר יציגו בפנינו את מספרי הטלפון של כל האנשיס בחתך מסוים, טלפונים באזור חיוג מסוים וכדומה. כל אותן הפונקציות פועלות על המערך המקורי של מספרי הטלפונים, אבל אז יכול לקרות מה שקורה בדרך כלל בפרויקטיס גדולים, נרצה לשנות את מבנה הנתוניס. קיימיס מספרי טלפון רביס, למעשה ללא גבול נראה לעין. לכן, נרבצה לעבור למבנה של רשימה מקושרת 1158 666הו1) אשר אין לה גודל קבוע (בניגוד למבנה שיצרנו המוגבל ל-100 מספרים). רשימה מקושרת היא רשימה המורכבת מתאים שכל אחד מהם מצביע לבא אחריו בתור, ולכל תא יש את הנתון שלו. אפשר לעבור על רשימה מקושרת בעזרת מעקב על המצביעיס של התאיס אשר מקשריס בין תאים שכניס ברשימה. בהמשך נראה דוגמה לרשימה כזו. אך מעבר וה דורש מאיתנו לעבור על הפונקציות שכתבנו ולשנותן. בעצס, דורש מעבר שכזה לכתוב את התוכנה מחדש! כיצד, אם כן, יכולנו למנוע את בשיטת המודולים! בניית ספר טלפונים בעזרת מודולים כדי למנוע מכל הפונקציות שלנו את הכרת מבנה הנתוניס המשמש להחזקת מספרי טלפון, נגדיר פונקציות שירות (60005מ10 507/106), אשר יתנו לה שירותים בסיסייס על מבנה הנתונים. מבנה הנתוניס עצמו יהיה מוסתר מכל שאר חלקי התוכנה. כלומר, פונקציות אחרות שלא שייכות למודול יגשו למבנה הנתוניס דרך פונקציות השירות של המודול בלבד. פרק 2: תכנות מוכוון אובייקטים | 57 למשל, נגדיר פונקציות שירות המאפשרות לעבור על השמות ומספרי הטלפון שלנו זה אחר זה, באופן הבא : 2 = סתס6עעטס 6ם1 ()66סת 11286* 66סת ו 02 = סמתספעגטס ; (סמ6עעגוס + 68תסםק) םעו266 () 6סם 6א6ם* 6בסת ו ; ++%ת226גוס ; (0תסעעטס + פס6תסםתק) מעטס6ץ ו כדי לעבור על רשימת הטלפוניס ולהציג את מספרי הטלפונים, עלינו לכתוב פונקציה שמשתמשת בפונקציה 2066 8286 ובפונקציה ₪066 1א6ם באופן הבא : ()60016ק ס6ת1עס 16סע ו = עססת ;עס6סת ;()006סם 21286 = עססת* 006סם) 1058 (()66סם סא6ת ; (6ת8ת<-?+פקת ,"ת%5 = סתהאם %1)"6ת1צס ו כעת, אס נרצה לעבור למבנה נתוניס אחר, למשל רשימה (18, נשנה את שלוש הפונקציות המטפלות במבנה הנתוניס של הטלפונים בלבד, ולא נאלצ לכתוב את כל התוכנית מחדש. כלומר, הפונקציה שמדפיסה את ספר הטלפונים אינה משתנה! בדרך זו, הפונקציות שמשתמשות במודול ואינן שייכות למודול, אינן משתנות כתוצאה משינוי במבנה הנתוניס של המודול. בדרך זו, של מידור התוכנה והפיכתה למודולים, אנו מגיניס על חלקי התוכנה מפני שינוייס מסיביים. בדרך שתוארה עד כה יש חיסרון בולט: אפשר להגדיר רשימה אחת ויחידה בכל התוכנית. בשלב הבא, נרצה לתמוך במספר רשימות כאלה להתייחס לרשימה כמודל אוטונומי המטפל באוסף של רשומות. טיפול במספר מודולים כפי שראינו, טיפול במודול אחד בו-ומנית מספיק לתוכניות פשוטות ביותר. במציאות, צריך לפעול בו-ומנית במספר מודולים. אפשר, אס כן, להגדיר מודול המטפל ברשימות כלשהן. מודול ה יתן לנו שירותים, כגון הוספת אלמנטיס לרשימה או ביטולס. כמו כן, המודול יספק את האפשרות לעבור על הרשימה, כלומר, לטייל על הרשימה מהאלמנט הראשון לשני וכוי. פעולת המעבר, 8 ++6 ו-009 למתכנת המקצועי או הסריקה, על הרשימה נקראת איטרציה (מ1069000), ומכאן נגזר המונח איטרטור (10679101), שאודותיו נלמד בהמשך. כאשר נזדקק לרשימה של אלמנטיס נבקש עבורה ידית (ס0מַ14) שתשמש, לאחר מכן, בכל הקריאות לפונקציות של מודול זה. נגדיר את הממשק למשתמש בקובץ הנקרא קובצ ממשק (116 1611106מ1), בו נתאר את הפעולות שמספק המודול. קוב הממשק נקרא, בדרך כלל, קוב כותר (16866) של מודול. הקוב מפרט את הפעולות אשר בהן תומך המודול. 2 סמססגע56 ;()026866 118%6* 118% ס6סגו562 ; (08%8* 10סט,1* 1186 800)56200 11586 בנסעט ;(*118% 00%6ע112586)86% 1186* 16סע ; (*118% 5%2006)%א6ם 1186* 16סע השורה הראשונה מצהירה על מבנה (רשומה) בשס +188. שורה וו אינה מפרטת את מבנה המבנה (או הרשומה. לעיתים מבנה נקרא גס רשומה והכוונה וזהה). לאחר הצהרה על רשומה בדרך זו, אפשר להשתמש במצביע (6חוסק) לרשומה בלבד. אי אפשר להגדיר משתנה מסוג רשומה משוס שהמהדר אינו מכיר את השדות שלה. הגדרה וו מספקת ידית לרשומה, ומסתירה את הפרטיס מהמשתמש ברשומה. ההצהרה על פונקציות הטיפול ברשומה משתמשת בידית של הרשומה כדי לפעול על הרשומה המבוקשת. חשובה במיוחד הפונקציה 01086 118%, שיוצרת רשומה חדשה ומחזירה מצביע לרשומה זו. המצביע לרשומה הוא הידית שעל המשתמש למסור לשאר הפונקציות של חבילה זו. הפונקציות עצמן והקוד שלהן תוגדרנה בקובץ אחר שמכונה בדרך כלל קובץ המקור (1110 50₪106). קוב וה מוסתר מהמשתמש, ולכן למתכנת המשתמש בחבילת התוכנה יש ממשק קשיח שרק בו הוא יכול להשתמש. נגדיר צומת ברשימה אשר לו מצביע לצומת הבא (0א6ם) ומצביע לנתון (688) שנמצא בצומת הנוכתי. ) 6 66סם 00%ע585%2 6065סץ6 ;%אסת* שססם 06סגוע56 8%82* 10סט 7 ן הרשימה עצמה היא רשומה שמכילה מצביע לצומת (66סם, התא) הראשון, ומצביע לצומת הנוכחי. המצביע האחרון (ומסזזטס) משמש למעבר על הרשימה. מצביע זה מצביע על הצומת הנוכחי בכל שלב של האיטרציה. /* 118% 66 01 6ע60ס0ט5852 6ם */ ] 6 118% ס6סגו562 ;0אסת* פסת ;%ת6עתטס* ססם ;תססות 6ם1 2 7+ פרק 2: תכנות מוכוון אובייקטים | 59 הפונקציה 6 ליוצרת רשימה חדשה ומאתחלת אותה. מספר האלמנטים ברשימה והמצביעיס מאותחליס לאפס. הפונקציה מחזירה מצביע לאזור זיכרון אשר הוקצה בעזורת פונקציית הספרייה 1341106. /* 16 0ם ע6סםת01סק 8 פמעטססץ 6₪ם8 118% חסת 8 0268668 */ 1186 *1186 0208066)( ן ;((81106)8512605)1186ת(*118%) = 1186 שסם* 1186 2 = סת00226<-118% שסםת = 680ם<-115%6 חאסת 2 = 16608ם<-118% חסםת 2 שסם םשג660ת ו הפונקציה 804 +18 יוצרת צומת חדש ומחברת אותה לרשימה. המצביע לנתוניס בצומת החדש מאותחל למצביע (688) הנתון לפונקציה כארגומנט. כלומר, המצביע 8 בצומת החדש יצביע לנתון החדש, ואילו המצביע 1א6ח יצביע לראש הרשימה הקודס. לאחר מכן, המצביע לראש הרשימה מעודכן לתא החדש. לבסוף, הפונקציה מגדילה את מספר האלמנטיס ברשימה. (08%8* 16סט ,1186262* 800)1186 11586 בנסעט ו ; ( (06סת) 812605) 81100ת(*6סת) =6ססתת* פסת 7 <-ע11560% %אסת<-6סמת 82 = 0868<-6ססתת 62 = 680ם<-%2ק1156 ;++166008ם<-%2ק1156 ו הפונקציה 11% +18 מאתחלת את האיטרציה (מעבר) על הרשימה ומחזירה מצביע לאלמנט הראשון ברשימה. אס הרשימה ריקה, מוחזר מצביע מאופס המסמן תנאי זה. (ע%ס1* 52128%)118% 118%6* בנסט ו ;680ם<-10%2 = 6ם226ג0ס<-62ס1 ;(0 : 08%68<-%ת6ע2ט0ס<-52ק1 ? סתסעעטס<-1052) םמעג6%ע2 1 הפונקציה +א6ת 1186 מקדמת את המצביע לצומת הנוכחי ומחזירה מצביע אל הנתוניס שאליהס מתייחס צומת זה. אס אין יותר רשומות ברשימה מוחזר מצביע מאופס. (%2סק1* 118%6)%א6ם 1186* בשנסע זָ (2עסא =! סתסמפטס<-62ס1) +1 ;6אסם<-00226%<-%2ק1 = 6ם226טס<-62ק1 ;(0 : 08%68<-%ת6ע2טס<-52ק1 ? סתסעעטס<-52ס1) םמעג6%ץ2 0 ++6 ו-009 למתכנת המקצועי כאמור, כל הפונקציות המטפלות ברשימה מופיעות בקובצ שהמשתמש במודול אינו חשוף לו. קובצ זה מהדריס בנפרד והמתכנת משתמש בתוצאת ההידור. לכן, כל שינוי בפונקציה כזו, לא יגרוס לשינוייס בתוכנת המשתמש. יתרה מכך, יש לנו עכשיו מודול שמספק לנו שירותיס בסיסיים של רשימה, ואנו יכוליס להשתמש בו לרשימות רבות. למודול עדייו חסרה פונקציה שתשחרר את הזיכרון שהוקצה במהלך הוספת אלמנטיס לרשימה. כתרגיל, אני משאיר לך ליצור פונקציה זו. החסרונות של המודולים המודוליס אכן פתרו בעיה חשובה. כעת הוסרה התלות בין מספר גדול של פונקציות ומבנה נתוניס ומשתניס רבים. כעת יש אפשרות לשנות מבנה נתוניס ביתר קלות מבלי ששאר חלקי התוכנה ישתנו. במיליס אחרות: כך הושגה הסתרת המידע (מסגואמחס)ת1 שמושו). כלומר, פונקציות שאינן שייכות למודול, אינן מכירות את מבנה הנתוניס של המודול. תוכנית הנוקטת בגישה זו המורכבת מאוסף של מודולים, כאשר כל אחד מהס מספק כממשק רשימה של פעולות, או פונקציות שירות אשר בהן הוא תומך - נקראת תוכנית מודולרית (ת8זפסזק ז18גו00הז). למרות היתרון שהושג בעזרת המודולים, עדיין קיימיס מספר חסרונות. כדי להבין אותס, נראה כיצד להשתמש במודול כזה: ()מ1נהת %ם1 2* ,11* 118% 06וע5% ; ()026806 118% = 11 ; ()026806 118% = 12 /* 118% 6ם6 0ם 68ת6180 8506 0ת 806061‏ */ ; (₪1ת61 ,86₪0)11 1186 ; (6102 ,86₪0)12 1186 6 ם1 6100668 7ץ0ע669% שח 00 חסם ? 6שע6ם 00 0ם סאמח */ /*118% ; (7)11ץ068%20 118% ] עצס ההכרזה על המשתנים 11 ו-12 אינה הגדרה של הרשימות, ואינה יוצרת רשימות, או מקצה להם זיכרון במחשב. לכן, אס המשתמש אינו קורא לפונקציות שיוצרות את הרשימה וקורא במקומן לפונקציה, כגון 806 +18 (שנועדה להוספת נתון לרשימה), תופסק התוכנית בנקודה זו, במקרה הטוב. במקרה הגרוע, תמשיך התוכנית לרוץ, אך תוצאותיה אינן צפויות ובוודאי שלא כפי שייהתכוון המשורריי. במקרה זה יתרחשו בעיות שונות, שלכאורה נראות ללא שוס קשר לבעיית האתחול. לכן, על המתכנת לזכור שעליו ליצור רשימה חדשה על ידי קריאה לפונקציה שיוצרת ידית לרשימה זו. המתכנת הגדיר ידית כזו, אך היא אינה מספיקה. פרק 2: תכנות מוכוון אובייקטיס | 61 המשתמש במודול הרשימות צריך לעבור על הרשימה ולשחרר את הזיכרון שהקצה. בנוסף, עליו לקרוא לפונקציה שהורסת את הרשימה. והו תהליך שטומן בחובו אפשרות לשגיאות רבות. למשל, מתכנת המשתמש ברשימה עלול לשכוח לשחרר אותה. חיסרון אחר של המודול הזה הוא הסרבול בשימוש בו. כאשר קוראיס לפונקציה, יש להעביר את המצביע לרשימה הנוכחית, כלומר, את הידית שיצרנו בשלב מוקדס יותר בעזרת הפונקציה )118 010866. לאור החסרונות האלה, הגיעו מפתחיס ומהנדסים רביס למושג מחלקה - 01888. 2.3 | המחלקה מחלקה (018589) היא מבנה נתוניס ואוסף של פעולות שמוגדרות על מבנה הנתוניס. אפשר להגדיר משתניס מסוג מחלקה. משתניס אלה הס מופעיס של המחלקה, או אובייקטיס. הציון אובייקט (05(60ס) חשוב במיוחד, ויש להבדיל בין מחלקה לאובייקט. מחלקה היא תבנית, כמו רשומה, המאפשרת להגדיר אובייקטים, כלומר, משתנים השייכים למחלקה. הפעולות (פונקציות) קשורות למבנה הנתוניס של המחלקה ואינן עומדות בזכות עצמן. פעולות אלו נקראות שיטות - 642005ג, או פונקציות חברות - 5מ6010ת61-10 ומ סו. כשמגדירים אובייקט של מחלקה מסוימת, באופן אוטומטי מתבצע האתחול שלו. כשיוצאיס מהבלוק שבו הוגדר האובייקט, האובייקט מפורק באופן אוטומטי. ואת בניגוד לדוגמה הקודמת של המודול, בו המתכנת היה צריך לזכור ליצור ולפרק משתנים (אובייקטים) של המודול. לפיכך, המחלקה פותרת את החסרונות שראינו במודול. השימוש במחלקה פשוט וקל יותר. עובדה זו חשובה מאוד. אס נחזור לרשימה שלנו, הרי שהזמן אותו נשקיע בפיתוח הרשימה קצר יחסית. לעומת ואת, נשתמש ברשימה בהרבה מקומות, ולכן נוחיות השימוש בה חשובה מאוד. כיצד, אם כן, נראית הצהרה על מחלקה ב-++6! הצהרה של מחלקה מתחילה במילת המפתח 61358. בהמשך ההצהרה מופיעיס החברים (פז6טנתסות) במחלקה. חבריס אלו יכוליסם להיות שדות נתונים (116165), או פונקציות (611005מגח) למשל: 01858 118% ] + סססת ;+תסעעטס* פבסםת ;85ת166ת 6ם1 :טס 1156)(; >118%6 )( ; ; (* 0186ע)86₪84 %הנ1בסט 7016 *+125%6)( ; ; () >א6ת* ה1סטע 2 ++6 ו-009 למתכנת המקצועי החלק הראשון של המחלקה, עד למילת המפתח 6ו!פטוק (ציבורי) והה להגדרת המבנה 4% ב-60. השינוי היחיד הוא, שבמקרה ה אנו משתמשיס במילת המפתח 61888. מילת המפתח סו!פטק מציינת את האזור של המחלקה שפתוח לשימוש על ידי מחלקות, או פונקציות אחרות. כלומר, רמת הגישה לאזור ה של המחלקה היא ציבורית. + היא שפת כלאיים, אפשר להגדיר בה פונקציות גלובליות (פתסנזסתט1 [81008), שאינו שייכות למחלקה, או מחלקות ואובייקטים. שפות תכנות מונחות אובייקטיס טהורות אינו מאפשרות הגדרה של פונקציות גלובליות. יש הרואיס דבר זה כחיסרון ויש הרואיס את כיתרון. המצדדיס בשפות תכנות מוכוונות אובייקטים טהורות, טועניס שהאפשרות להגדיר פונקציות גלובליות מאפשרת למתכנת יילקלקליי את מבנה התוכנה. המצדדים בשפות כלאיים טוענים שיש בשפה כמו ++6 יכולת גדולה יותר, והשפה מאפשרת ליהנות משני העולמות בעת ובעונה אחת. אני נוטה להסכים עס הקבוצה השנייה. בדוגמה שלעיל מוגדרות חמש פונקציות. הראשונה מביניהן היא בעלת שם והה לה של המחלקה. ווהי פונקציה מיוחדת שמשמשת לאתחול, או ליצירת אובייקטים חדשיס של המחלקה. לפונקציה שם מיוחד +600500600 או בנאי. פונקציה זו נקראת באופן אוטומטי על ידי המהדר, ואין באפשרות המתכנת לקרוא לה באופן אחר. הפונקציה נקראת כאשר מוגדר אובייקט של המחלקה. הפונקציה השנייה היא המפרק, או *60%19₪000. פונקציה זו נקראת באופן אוטומטי על ידי המהדר כשהמשתנה של המחלקה (אובייקט) יוצא מתחוס ההגדרה. כלומר, המהדר מבצע את פעולות ההריסה של אובייקטיס באופן אוטומטי. שאר הפונקציות : 806, 1%, +אסם הן פונקציות רגילות של המחלקה, אשר מבצעות את הפעולה של הוספת צומת לרשימה ומעבר על הרשימה. השימוש באובייקטיס של המחלקה נראה באופן הבא : ()מ1נהת %ם1 ?2-ה ;ע6ק* הנ1בסע ; ("08%68 6ת11.860)"50 ; ("ת1%606 עסת%סת12.806)"8 (()%א6ם.11 = עפס ;עס ;()11.1129896 = עסס) ע02ס+ ; (עפףס ,"ם1)"%5>מו1עס 7 תעגו66ע ו התוכנית הקטנה הזו מגדירה שתי רשימות (אובייקטים) 11 ו-12. התוכנית קוראת לפונקציה 804 פעמיים, עבור כל אחד מהאובייקטים 11 ו-12. הקריאה לפונקציה של אובייקט נעשית על ידי כתיבת שס האובייקט, לאחריו נקודה ולאחריו שס הפונקציה. דבר וה דומה לגישה לשדה בשפת 6. מעבר על הרשימה והדפסת המחרוזות הנמצאות ברשימה נעשה באופן דומה. פרק 2: תכנות מוכוון אובייקטים | 63 דוגמה וו שונה מהדוגמה הקודמת, שבה השתמשנו במודולים. כזכור, היינו צריכיס לקרוא לפונקציה שיצרה ידית לרשימה. בנוסף, היינו צריכיס להרוס את הרשימה במפורש. ב-++6 כל הפעולות האלו מתבצעות באופן אוטומטי על ידי המהדר. הדבר חוסך את הטירחה בכתיבת פעולות אתחול והריסה של מודולים, וגס מונע מאיתנו שגיאות טיפשיות, כמו לנסות להשתמש בידית (אובייקט) שלא יצרנו כלל. דבר נוסף שאפשר לראות מקטע התוכנה הקודם הוא האלגנטיות הרבה. אין צורך להעביר מצביע לאובייקט בכל קריאה לפונקציית שירות של המחלקה. האובייקט הנוכחי הוא הידית של פונקציית השירות. פונקציות חברות (5ת6010ת10 זסטותסגת) במחלקה א כלשהי, הן פונקציות שנכתבות בצורה הבאה: (60)8206-118%תג20::א 1סט ו 56086668 . .. ו שס המחלקה מופיע לפני שס הפונקציה. לאחר שס המחלקה מופיעות פעמייס נקודתיים. סימון זה מציין שהפונקציה שייכת למחלקה מסוימת, ואינה פונקציה גלובלית (שאינה שייכת לאף מחלקה). לאחר שס הפונקציה מופיעה רשימת הארגומנטיס המועברים לפונקציה, כמו ב-0. רשימת הארגומנטים נמצאיס בין סוגריים. גוף הפונקציה נמצא בין סוגרייס מסולסלים בדומה ל-6. כדי להדגיס זאת, נראה את הפונקציה 8664 של הרשימה, שמוסיפה אלמנט לרשימה. פונקציה וו מקבלת מצביע לאלמנט שיש להוסיפו לרשימה. הפונקציה משתמשת בפונקציית המערכת ש6ת של ++6. א6ם מקצה זיכרון, לפי גודל האובייקט שנמסר לה, ומחזירה מצביע לזיכרון זּה. אין צורך להמיר מצביע זה לסוג של המצביע הנוכתי כמו במקרה של 1381100 ב-6. שינוי נוסף לעומת ?) הוא שאין צורך להעביר את המצביע לרשימה הנוכחית, ואין צורך להשתמש במצביע גה כדי לגשת לשדות של הרשימה. (08%8* 010ע)115%::800 ב1סע ו ;6ססם חשסם = 6בסת 87 = 08608<-06סת 2 = סא6ת<-6סת ;ס6ססםת = ַ68םת ;++16608ם ו ב-++6 יש ארגומט נוסף אשר מסופק על ידי המהדר לכל פונקציה של מחלקה. ארגומנט זה הוא 4818 המתכנת אינו צריך לספק ארגומנט בקריאה לפונקציה, אך לעומתו יכול כותב הפונקציה להשתמש בארגומט זה כמצביע לאובייקט הנוכתי. בהמשך נראה את השימוש של המצביע. 4 | ++6 ו-009 למתכנת המקצועי כל פעולה על שדה של המחלקה מתבצע יחסית למצביע לאובייקט הנוכחי 1118. כלומר, השורה: ;6סםת = בִ6םת שקולה לשורה הבאה: 22 = 680ם<-15ם6 פונקציה מיוחדת של המחלקה היא הבנאל (סזסט5מסס). כאמור, הפונקציה נקראת כאשר מגדיריס אובייקטיסם מהמחלקה הנתונה. הבנאי למחלקה % כלשהי מוגדר בצורה הבאה: (826-1186)%::א [ ו שס הפונקציה במקרה זה, הוא כשמה של המחלקה. רשימת הארגומנטיס יכולה גס להישאר ריקה. למשל, במקרה של רשימה, אפשר לכתוב בנאי עס רשימת ארגומנטיס ריקה: (69) 5%: 3.1 11 ו ; = ַ6ת 2 = סתספעעגטס 2 = 166098ת ו הבנאי מאתחל את שדות הפרטיס של הרשימה כדי לאפשר פעולה תקינה שלה. מומלצ לכתוב בנאי קצר שמעביר את האובייקט למצב תקין ומוכן לפעולה. עדיף להימנע מבנאיס ארוכיס שמבצעים אלגוריתמים שלמים בבנאי עצמו. פונקציה מיוחדת אחרת היא פונקציית מחיקה וניקוי, המפרק (40500000) של המחלקה. פונקציה זו נכתבת על ידי מתכנן המחלקה ותפקידה למחוק ולנקות תוצאות של פעולות ביניים שנעשו על אובייקט של המחלקה. למשל, לשחרר הקצאות ויכרון שנעשו על ידו. הצורה הכללית של פונקציה כזו עבור מחלקה כלשהי א היא כזו: ()א-::א .. . 508600668 ] התחביר של המפרק דומה לתחביר של הבנאי, אך נמצא כאן שני שינויים. השינוי הראשון הוא: שס הפונקציה הוא כשס המחלקה, אך בתוספת הסימן '-'' לפני שם הפונקציה. השינוי השני הוא, שהמפרק אינו מקבל ארגומנטים. פרק 2: תכנות מוכוון אובייקטים | 65 לשתי פונקציות אלו (הבנאי והמפרק) אין אפשרות להחזיר ערך כלשהו. אין אפשרות לראות אס הבנאי נכשל בפעולתו ולכן יש לדאוג לכך שהוא לא ייכשל. דוגמאות לכך נראה בהמשך. במקרה של הרשימה צריך המפרק לשחרר את כל הצמתיםס של הרשימה; המפרק יעבור על כל צומת וישחרר אותו. ()118%6-:115% ןָ ;%אסת* ,680ם = עטס* סבסם + (עתטסא =! פטס) 16נתט ;%אסם<-ע00 = סאסת ;עטס 061666 2 = שגס ו במפרק אנו מגליס מילת מפתח חדשה: 661666 (מחיקה, ביטול). למעשה, ווהי קריאה לפונקציה של המערכת שמשחררת זיכרון, שהוקצה קודם לכן בעזרת הפונקציה אוסם. חוק : אין להפעיל את 66166 על זיכרון שלא נרכש בעזרת שש6ם. הפעלה של 6616066 על זיכרון שלא נרכש בעזרת 6 יגרוס לבעיות ולתופעות בלתי צפויות. סיכום בפרק וה ראינו את הגורמיס ליצירת מודוליס. ליישוס (מ8001108)10) שמפתחיס יש מחזור חייסם ארוך, שבמהלכו נוספים לו דרישות שגוררות שינוייס מרחיקי לכת בתוכנה, עד כדי שיכתובה מחדש. כדי להתגבר על בעיות אלו הומצא המודול. מודול מספק שירותיס ומסתיר את אופן המימוש משאר חלקי התוכנה. לכן, כאשר משתנה אופן המימוש, ישתנה רק המודול ולא כל התוכנה המשתמשת בו. לפיכך, משיג המודול מידור של רכיבי התוכנה. יש מספר חסרונות במודולים. למשל, יש צורך שהמתכנת המשתמש בהס יאתחל ויהרוס אותם. אס המשתמש שוכתח ליצור אובייקט מתאים של המודול, אין דבר המונע ממנו למסור ידית כזו לפונקציות השירות של המודול ולגרוס לתוצאות בלתי צפויות. כדי לפתור חסרונות אלה מגדיריס את המחלקה. משתנים, או מופעים, של מחלקה נקראים אובייקטים. כאשר מגדיריס אובייקט כזה, נקראת פונקציית האתחול שלו, הבנאי, באופן אוטומטי. כאשר יוצאיס מהבלוק אשר בו הוגדר האובייקט, פונקציית הניקוי, המפרק, נקראת באופן אוטומטי גס כן כדי לבטל הקצאות והקצאות שונות. בהמשך נראה איך לכתוב פונקציות אלו. 6 ++6 ו-009 למתכנת המקצועי = תרגילים הגדר את הפונקציה של המודול 66560 18%. לאיוו פונקציה של המחלקה 118% שקולה פונקציה זו? 2 הגדר מודול למערך דינמי, המגדיל את המערך כאשר אין בו מספיק מקוס. הגדר פונקציות בנייה ופירוק למערך זה. 3 כתוב תוכנית המנהלת רשימת טלפוניס בעזרת המערך שבנית. 4 האם המפרק של הרשימה צריך לשחרר את הזיכרון אליו מצביעיס הצמתים בעזרת 16848 נמק! כתוב את הפונקציות המאפשרות מעבר על הרשימה 1118 ו-+א6ם. 6. כתוב פונקציה המבטלת צומת ברשימה. מה הפונקציה צריכה להחזיר למשתמש: פרק 2: תכנות מוכוון אובייקטים | 67 פרק 3 המחלקה בפרק זה נמשיך ללמוד את המחלקה ב-++6, ונרחיב את ההקדמה מהפרק הקודס. המחלקה היא אבן הבניין הבסיסי בתכנות מוכוון אובייקטים, והיא מחליפה את המודול ומספקת שירותיס והסתרת מידע. מטרתנו בפרק זה היא ללמוד את הפונקציות השונות של מחלקה הכוללות אופרטורים שוניס, פונקציות בנייה ופונקציות פירוק (ובקצרה - בנאים ומפרקים). בסוף פרק ה נדע לכתוב מחלקות שימושיות למספר יישומים. בפרק וה נתייחס למחלקות ואובייקטים. מחלקות הן תבניות (18008קוחס!) המורות למהדר כיצד להגדיר אובייקטים. אובייקטים הס משתנים מסוג של מחלקה נתונה. אובייקט (000[טס) הוא מופע מסויס של מחלקה. בומן ריצה חיים האובייקטים, ואילו בומן הידור המחלקות משמשות כתבנית חוקים למהדר, כדי להגדיר את הפעילות שיכולה להתבצע על אובייקטים מסוג מסוים. בנוסף, מגדירה התבנית את השדות של האובייקטים ששייכים למחלקה מסוימת. | 3.1 | מבנה המחלקה - אזורי גישה למחלקה יש אזורי גישה שוניס. החלוקה לאזוריס נועדה לשמור את הסתרת המידע ממשתמשי המחלקה. מילת המפתח סו!פטונ מציינת שיש גישה לחלק זה של המחלקה, לפונקציות, או לאובייקטים אחריס שלא שייכים למחלקה הנוכחית. החלק של המחלקה שאינו נמצא בחלק הציבורי, נחשב חלק פרטי וזוהי ברירת המחדל. לחלק הפרטי של המחלקה יכולות לגשת רק פונקציות השייכות למחלקה. במחלקה כלשהי א אפשר להגדיר את אזורי הגישה למחלקה בצורה הבאה: 01858 8% ) ;1הטא סם1 :טס ;[הצץ 6ם1 פרק 3: המחלקה | 69 : עס 12 סם1 ו מילת המפתח 66)גטוזש (פרטי) מציינת את החלק הפרטי של המחלקה, אשר אליו יכולות לגשת רק פונקציות החברות במחלקה. מילות מפתת אלו יכולות להופיע מספר פעמיס בהגדרה של המחלקה, כאשר כל הופעה משנה את הגישה לשדות אשר מופיעיס אחריה. ההגדרה תקפה עד להגדרה הבאה. במחלקה שהגדרנו כאן, המשתנה 41וא נמצא בחלק הפרטי של המחלקה, ולכן הגישה אליו מוגבלת. לעומת ואת, השדה [גצץ נמצא בחלקה הציבורי של המחלקה ולכן הגישה אליו אפשרית לכל הפונקציות והאובייקטים. השדה [2%4 נמצא בחלק הפרטי ולכן הגישה אליו מוגבלת גם היא. נחזור למושגיס אלה בהמשך פרק זה. |3.2 | הבנאי - פונקציית האתחול של המחלקה בפרק הקודם ראינו שהמהדר משתמש בפונקציית בנייה (סזסטטפמסט), או בנאי, כדי לאתחל אובייקטים שונים. לכן, אחת הפונקציות החשובות ביותר של המחלקה היא הבנאי. למעשה, הבנאי הוא הוראות למהדר כיצד לאתחל אובייקט חדש של המחלקה. לכל מחלקה יכולים להיות מספר בנאים, שלהס תפקידים שונים. נסקור בסעיף זה את הבנאיס השונים. כדי להדגיס אותס נשתמש במחלקה מהפרק הקודם, ובעת הצורך נוסיף מחלקות נוספות. בנאי ברירת המחדל בנאי ברירת המחדל (06+09ע6050 )6613₪1) אינו מקבל פרמטריס כלשהם. כבר נתקלנו בבנאי אה בפרק הקודסם כשדיברנו על המחלקה 118. ()115%::1185%6 ו 2 = 86ס6ת 2 = 166098ת 2 = סתפעעטס ו בנאי וה מאפס את השדות של הרשימה, מביא אותה למצב כשיר לפעולה, ומאפשר להגדיר אובייקטיס בצורה הבאח: ;ךס10 1186 כלומר, אין צורך לספק פרמטריס לבנאי זה. הוא שימושי במיוחד כאשר רוציס להגדיר מערך של אובייקטיסם, או במקרה הזה מערך של רשימות: ;[5]ץ8עעת115% 115856 0 ++6 ו-009 למתכנת המקצועי השורה הקודמת מגדירה מערך של חמש רשימות. לאתחול כל רשימה משתמש המהדר בבנאי ברירת המחדל, לכן נקבל חמש רשימות ללא אף צומת, כאשר מספר האובייקטיס בכל רשימה הוא אפס. אין אפשרות להגדיר מערך של אובייקטים, אם למחלקה של האובייקטים אין בנאי ברירת המחדל, מבלי לצייו את הערך ההתחלתי של כל אובייקט; כלומר, את הארגומנטיס של אתחול עבור כל אובייקט. יש לנו, למשל, את המחלקה הבאה: ) % 01858 ₪ חי :טס ; (סא %םת1)א ;ן מכיון שאין בנאי ברירת מחדל למחלקה א, יש לאתחל כל אובייקט באופן נפרד כך: ;( (2)א ,(1)א ,(0)א + = []צעהא א בנאי עם פרמטרים בנאיס המקבלים פרמטריס משתמשיס בהם כדי לאתחל אובייקט חדש. נניח למשל, שיש לנו מחלקה המשמשת כמחרוזת של 6. ] 86ם1ע56 01858 7+ עבתס :טס ;(* 082 8%םת06)00ם1ע562 ; () 6ם5%621= ;ו הבנאי של המחלקה 5158 מקבל מצביע לתו. מילת המפתח +602%% (קבוע) מסמנת שהבנאי לא ישנה את תכולת המצביע שמועבר אליו. כאשר מילת מפתח זו מופיעה לפני משתנה, היא מודיעה למהדר שיש לשמור על המשתנה, כדי שהמתכנת לא ישנה את תכולתו בטעות. נחזור למילת מפתח זו מאוחר יותר. הבנאי מעתיק את המחרוות שניתנה לו למקוס חדש בזיכרון אותו מקצה הבנאי: (8* 0282 5%ת6)00ם8::5%21מם5621 ָ ;[1 + (5]ם82]8%218ם0 חטסם = ע56% 8( ;‏ ,ע7)56%ץ9%200 ] נשיס לב, שבמקרה זה השימוש באופרטור צופמ מלווה בסוגריים מרובעיס שמציינות הקצאת ויכרון של מערך. הקצאה של מערך מחייבת שימוש באופרטור 661666 של מערך. שימוש באופרטור אחר יגרוס לתוצאות בלתי צפויות. לכן, במפרק של מחלקה זו מופיע משפט 661606 באופן הבא : פרק 3: המחלקה ‏ 71 ()0ם1ע9%2-::6ם1ע562 ן 061666 ][ 557; ] בנאי עס פרמטר אחד יכול לשמש כאופרטור המרה מסוג הפרמטר לאובייקט של המחלקה. נחזור לוה בהמשך. בנאי מחלקה הוא פונקציה לכל דבר, פרט לעובדה שהוא נקרא באופן אוטומטי על ידי המהדר והמתכנת אינו יכול לקרוא לו. כמו כל פונקציה אחרת, הבנאי יכול לקבל מספר פרמטרים. למשל, הבנאי יכול לקבל מצביעיס לשתי מחרוזות ולשרשר ביניהם באופן הבא: (82* 0282 5%ת00 ,81* ע028% 5%6ת6)00ם1ע8::5%2מם1ע562 ;(82)ם8%216 = 22 ,(81)ם8%216 = 1 6ם1 2[ + 2ע + 1ע82]2ם0 טספם = ע6פ5 81( ;‏ ,ע562)ץ56200 ;(82 ,7)51+21ץ00ע562 ] הבנאי הזה מחשב את אורכי שתי המחרוזות, מקצה זיכרון באורך של שתי המחרוזות ותו נוסף. התו הנוסף נועד לתו המיוחד בעל ערך 0 (ערך דצימלי 0), שמסמן את סוף המחרוזת. הערך של התו המיוחד הוא 0 (שלס) וחשוב לא להתבלבל בינו לבין הערך '00' של 48011 שאינו ערך אפס (שלס). לאחר מכן, מעתיק הבנאי את שתי המחרוזות, זו לאחר זו, לתוך אזור הזיכרון החדש שאליו מתייחס המצביע ש8. אופן השימוש בבנאי וה הוא: ; ("%811 168 0ם8 " ,"פתס ע82)"856 8מם1ע56 האובייקט 82 הוא אובייקט מסוג 8פוש5 אשר יימכיליי מצביע למחרוזת המשורשרת משתי המחרוזות אשר הועברו לבנאי. בנקודת ההגדרה של אובייקט זה נקרא הבנאי בעל שני הפרמטרים באופן אוטומטי, כדי ליצור את האובייקט. בנאי עם קבועים ראינו שניתן להגדיר משתניס קבועים. כאשר ההגדרה של משתנה כוללת את מילת המפתח +60₪8%, המשמעות היא שאין לשנות את תכולת המשתנה. המהדר מגן על משתנה כזה ודוחה את האפשרות לשנות את תכולתו. למשל, המשתניס הבאיס הס קבועים: 2 = 0% %ם1 00586 כ ססף פַת0 ספםתסס 0086 11086 1 3 ;"0ם1ע8%2 6ףת868תסס ת" = ע865* ע8ם0 585%6ם00 2 ++6 ו-009 למתכנת המקצועי מכיון ששלושת המשתנים הראשונים הס קבועיס (כלומר, ‏ %םסט), הס אינס יכולים להופיע בצד השמאלי של משפט ההשמה. לעומת ואת, המשתנה השמאלי הוא מצביע לתוויס קבועיס. כלומר, אין אפשרות לשנות את התכולה של המצביע: 8110 ססם // ;'8' = ע86* ; "ף0ם1ע586 עס6םססתת" = מ565 המשפט הראשון בדוגמה זו אינו חוקי, כי הוא מנסה לשנות את תכולת המצביע. המשפט השני הוא חוקי משוס שאין משניס את התכולה של המצביע, אלא את המקוס שאליו המצביע מתייחס (זוהי המשמעות של מצביע). אם ברצוננו להגדיר מצביע קבוע, שמצביע למקוס אחד בלבד, עלינו לעשות ואת בצורה הבאה: ;"עפ" = עספס ספתסס* עִהתס פ185ם0 א0% // ל'78 = פס* ; "ףם1ע5% עסם6סםת" = ע056 ההשמה הראשונה חוקית, ולכן היא מאפשרת לשנות את אזור הזיכרון שאליו המצביע מתייחס. לעומת זאת, ההשמה השנייה אינה חוקית, משוס שאין לשנות מצביע קבוע כדי שיצביע למקוס אחר. לפיכך, משתנה קבוע יכול להיות מאותחל פעס אחת ויחידה בעת הגדרתו. בנאי העתקה ומושג הייחוס לכל מחלקה כלשהי % מוענק באופן אוטומטי בנאי העתקה. כלומר, גסם אס אתה, המתכנת, אינך מגדיר בנאי כזה, המהדר ייצר אותו עבורך. מהו אס כן בנאי ההעתקה? עבור מחלקה נתונה א, בנאי ההעתקה מוגדר כך: (8126%א6 % 56ם00)%::א ו בהגדרה זו אנו נתקליס במושג חדש שנקרא *יחוס (00מ1616760), או הפנייה לאובייקט. פעולות על הייחוס ישפיעו על האובייקט אשר אליו מתייחס הייחוס. כלומר, הפרמטר של הבנאי הוה הוא שס לאובייקט אחר, ובדומה למצביע, קריאה לבנאי זה אינה מעבירה את האובייקט כולו אל המחסנית, אלא את שמו בלבד. כלומר, נחסכת ההעתקה של האובייקט אל המחסנית. נחזור בהמשך למושג זה. כאשר המהדר מעניק בנאי העתקה למחלקה מסוימת, הבנאי מבצע העתקה של החבריס במחלקה מאובייקט אחד לאחר. הבנאי שהמהדר מעניק כברירת המחדל מבצע העתקה רדודה (עק60 שסן41ם5), של שס בלבד . למשל, הבנאי נקרא לבצע משפטים כמו אלה: ; ("סס00%א%")81 8ם1ע56 ;(852)81 6ם1ע56 2 = 83 8מם1ע56 פרק 3: המחלקה | 73 בשורה הראשונה מוגדר אובייקט 81, בשורה השנייה מועתק האובייקט על ידי בנאי העתקה לאובייקט החדש 82. בשורה השלישית מועתק 81 לאובייקט החדש 83 על ידי בנאי העתקה. נזכור שבנאי העתקה, המוענק על ידי המהדר, מעתיק את שמות השדות ולא את תוכנם. לכן, לאובייקטיס 82 ו-53 יש כעת מצביעיס (מסוג 6684 לאותו אזור בויכרון בו נמצא האובייקט 81. פונקציית הפירוק של האובייקטיס האלה תשחרר את אזור הזיכרון שלוש פעמיס. מצב וה יכול להוביל לתוצאות בלתי צפויות של התוכנית, שבמקרה הטוב נזהה אותן במקוס הפירוק של אובייקטים אלה. במקרה הרע, תחיינה התוצאות במקומות ללא קשר לכאורה לאובייקטיס שאנו עוסקיס בהן. חוק: כאשר יש מצביעים במחלקה, עלינו להגדיר בנאי העתקה. הדבר נכון במיוחד למחלקות שאסור שתהיה להן אפשרות של העתקה רדודה (של שמות) בלבד. ההעתקה אשר ה וה, וכד: בנאי ההעתקה אשר נכתוב למקרה זה, ייראח כ (88 06ם1ע562 585%ת6)00ם8::5%21מם1ע562 ;[1 + (ע6ס585.8)מם160ע82]562ם0 חאסם = מ565 ;(ע8.50 ,ע502) ץ56200 ו בנאי ההעתקה, במקרה וּה, מקצה אזור זיכרון חדש ומעתיק לתוכו את המחרוזות של האובייקט המועבר כפרמטר לבנאי. לפיכך, ישחררו המפרקים אזורי ויכרון שוניס והבעיה הקודמת נפתרת. בנאיס של אובייקטיס נקראיס בשני מקרים: * כאשר מגדיריס אובייקט במקוס כלשהו של התוכנית. * כאשר מקציס אובייקט בעזרת אופרטור א6ם. במקרה השני מוקצה לאופרטור א6ם ויכרון כגודלו של האובייקט הנתון, ואו נקרא הבנאי המתאים לאובייקט. הבנאי המתאיס הוא זה המקבל רשימת ארגומנטיס מתאימה לאלה שנמצאיס בנקודת היצירה של האובייקט. למשל: ; ("חם1ע5% קהסם")6םת1ע56 טחסם = ע82%ם1ע86* 8ם1ע56 במקרה זה, האובייקט מוקצה בויכרון החופשי של התוכנית, ולכן גם האובייקט והמצביע 86 מוקצים לאיכרון זה. | 3.3 | המפרק, פונקציית הניקוי של אובייקטים פונקציית פירוק ((465000)0), או מפרק, היא פונקציית הניקוי אשר מנקה הקצאות, הגדרות ומשאביס לאחר יימותיי האובייקט. אלגוריתס הניקוי שמופעל הוא באחריות המתכנת שכתב את המחלקה שלה שייך האובייקט. המהדר מצידו, קורא לפונקציית הפירוק באופן אוטומטי כשהאובייקט יוצא מתחוס הגדרתו, או כאשר מופעל על הכתובת שלו האופרטור 861666. בסעיף זה נראה דוגמאות והסבר מפורט לכך. 4 ++6 ו-002 למתכנת המקצועי סגנון כתיבה טוב הוא וה שמנקה ומשחרר את כל המשאביםס שנתפסו על ידי האובייקט במהלך חייו. משאביס אלה יכוליס להיות זיכרון של המחשב, או מתארי הקבצים (015ז6050110 116) שמתקבלים כתוצאה משימוש בפונקציית המערכת מססס. המפרק של מחלקה נתונה א, נראה כך: ()א-::א // ו כמו כל פונקציה של מחלקה, מוגדר המפרק כשלפניו מופיע שס המחלקה. שס המפרק הוא כשס המחלקה כאשר קודם לו התו "-יי. שני תווי לוכסן *י//יי המופיעים בגוף המפרק הס סימניס להערות. הערה (ומסותומסט) כזו מתחילה מצמד התווים "//יי וממשיכה עד לסוף אותה השורה. במחלקה שתוארה קודס לכן (8ת501) ייראה המפרק כך: ()0ם1ע9%2-::6ם1ע562 ןָ ;557 [] 061666 ] מפרקיס של אובייקטיס נקראיס אוטומטית על ידי המהדר כאשר אובייקט יוצא מהתחוס בו הוגדר. המפרק נקרא כדי להרוס את האובייקט כאשר הבקרה של התוכנית עוזבת את הבלוק בו הוא הוגדר. הדבר קורה מייד לאחר שבוצע המשפט האחרון בבלוק בו מוגדר האובייקט. למשל: (ע8%* ע8ם5)0 ב1סט ו ; (ע5)5%62 6ם1ע56 תסגססםט+ 0% 008 ... // 48 6608 ע88980 ת0ס061ם50 05 6ת6 6ב2ם 6ע6102ע 6פט7 626ם // ו הקריאה למפרק של אובייקט 5 מתבצעת ממש לפני היציאה מהפונקציה. עובדה זו נותנת לאובייקט אפשרות לנקות אחריו, ולהתחזיר למערכת משאביסם שהאובייקט נזקק להס במהלך חייו. במקרה וה הקצה האובייקט זיכרון דינמי ועליו מוטלת האחריות לשחרורו. משאבי מערכת אחרים :כולים להיות קבצים, או ויכרון משותף בין תהליכים. בכל מקרה כזה אחראי האובייקט לשחרור המשאביס בעת הפירוק. מועד הפירוק נקבע על ידי המהדר. ייתכן שהאובייקט הוגדר בבלוק בקרה כלשהו בתוך בלוק בקרה אחר. במקרה כזה ייהרס האובייקט כאשר הבקרה של התוכנית יוצאת מבלוק הבקרה הפנימי. למשל: (ע5%* ע8ת51)6 16סט ן + (תס1נ%ף1נסתסס 6ת80) 1% ;(ע81)85% 06םת1ע56 פרק 3: המחלקה | 75 / ו בדוגמה זו תיקרא פונקציית הפירוק (0ו0ט4080) על ידי המהדר כאשר מגיעים לסוף משפט 11, כלומר הרבה לפני סוף הפונקציה 11. פירוק האובייקט אינו נקרא באופן אוטומטי כאשר האובייקט מוקצה מתוך הציכרון החופשי של התוכנית. כאשר אובייקט מוקצה בעזרת האופרטור אשם, פונקציית הפירוק של האובייקט אינה נקראת באופן אוטומטי. במקריס כאלה, האחריות להחזרת הזיכרון ופירוק האובייקט מוטלת על המתכנת. למשל: (ע8%* 08% 856םת53)00 ב1בסט ; (ע06)5%םת1ע5% חטסם = 51* 6ם1ע56 0 ] כשפונקציה וו מסתיימת, לא מתבצעת קריאה למפרק של האובייקט 81. מצב זה גורס זליגת זיכרון (168% ץזסגמסות). במקרה כזה יש להפעיל את האופרטור 661666 על האובייקט 81. הפעלת האופרטור 86166 תגרוס קריאה אוטומטית למפרק (465000%0) של האובייקט 81, וכתוצאה מכך, לשחרור הזיכרון שלהוקצה לו. הזיכרוו שהוקצה עבור האובייקט (לא על ידי האובייקט) על ידי המתכנת בקריאה לאופרטור איסם, ישוחרר. מושג הייחוס נתקלנו כבר במושג הייחוס ובסעיף זה נבין מושג וה לעומקו. הייחוס (06ם161016) הוא מושג חדש יחסית ל-6, אבל אינו קשור דווקא למחלקה ב-++6. הייחוס הוא שס אחר לאובייקט. מתחילים רבים ב-++6 מתקשים להבין עובדה זו. נסביר ואת בעזרת דוגמאות. משתנה מסוג ייחוס הוא שס אחר לאובייקט, אך הוא אינו אובייקט בפני עצמו. ב-++6 אפשר להגדיר ייחוס לכל סוג של משתנה (לאובייקט, או למשתנה בסיסי של השפה). המשמעות של ייחוס לאובייקט, או למשתנה בסיסי היא זּהה, ודומה לסמנטיקה של מצביעים, למשל: 72 = 1 שם1 ; (1) 61265 %6ם1 2 = 1 ; (1565 ,1 ,"ת%6=+126 ,51)"1=%0ם1צק 6 ++6 ו-009 למתכנת המקצועי ההדפסה של שני המשתניס בשורה לעיל תיתן אפס כמובן. המשתנה 61זא אינו משתנה בזכות עצמו, הו שס אחר למשתנה 1. הגדרה של משתנה מסוג ייחוס נעשית על ידי הוספת 8 לפני שס המשתנה. משתנה מסוג ייחוס מאותחל פעס אחת ויחידה - בנקודת ההגדרה שלו. אי אפשר לשנות את הייחוס לאחר הגדרתו. כלומר, אי אפשר לקשור את הייחוס למשתנה אחר, לאחר הקשירה הראשונית בעת הגדרתו. אס הייחוס מופיע מצידו השמאלי של משפט השמה, משתנה תכולת האובייקט שאליו מתייחס הייחוס ולא הייחוס עצמו (כמו האופרטור יי * יי על מצביע), כלומר: 126% = 2; לאחר משפט ההשמה הזה יהיה גם ערכו של המשתנה 1 אחד. משתנה ייחוס דומה מבחינה זו למצביע רגיל של ++6. השוני בין מצביע לבין משתנה ייחוס הוא שאפשר לשנות מצביע, כלומר מצביע יכול להצביע לאובייקט אחר, אבל משתנה ייחוס מצביע מרגע הולדתו ועד מותו לאותו אובייקט. למשל: 2 ,31 5מ3 ; (11) 81265 %ם1 2 = ס1* 6ם1 2 = ס1* לאחר משפט השמה, הערך של 11 הוא 1. מצביע, לאחר אתחולו, יכול להצביע למשתנה אחר. למשל: 2 = ס1 7 י= יס% במקרה זה ערך המשתנה 12 ישתנה ל-2. אותה סדרה של פעולות, אך הפעס בעזרת ייחוס, תוביל לתוצאות שונות: 126% = 2 126% = 2 126% = 2 בשורה הראשונה יקבל המשתנה 11 את הערך 1. בשורה השנייה הוא יקבל את הערך של המשתנה 12, ואילו בשורה השלישית הוא יקבל את הערך 2. שימו לב, בכל המקריס משתנה ערכו של המשתנה 11. שימושי הייחוס מתי, אס כן, נשתמש באפשרות הייחוס! הייחוס (101670200) שימושי במיוחד כאשר רוצים להעביר אובייקטיס גדוליס לפונקציות. ב-++6 הקריאה לפונקציה היא 86 עט (לפי ערך). לפונקציה יש העתק של האובייקט שהוא הפרמטר, או הפרמטריס שלה. כאשר אובייקטיס אלה גדולים, תוביל יצירת ההעתקה שלהס לביצועים ירודיס של התוכנית. ראשית, התוכנית תצרוך יותר זיכרון, משוס שיהיו לה מספר אובייקטיס פרק 3: המחלקה | 77 במקוס אחד. שנית, התוכנית תצרוך יותר זמן, מפני שיש צורך ליצור העתק של האובייקט. אולס, בשיטה זו פעולות שמשנות את האובייקט-פרמטר של הפונקציה, אינן משפיעות על האובייקט המקורי שנמסר לפונקציה. לדוגמה, ] 8ם1ע56 018588 :טס ; (8* 028% 86ת8586%)00 ב1סע ע55 60ת0 שם1ע562 טספם 626 000168 866 // ;ן נניח שיש לנו פונקציה חדשה בשס 85% למחלקה 8ַתו8₪. תפקיד פונקציה זו לשנות את המצביע הנתון לה למצביע חדש. (8 06םת1ע5)56 1%סט [ ; ("6ו1אט שטסם")5.866 ; ("6מ1אט 010ס")5 8מם1ע56 ; (5)8 הקריאה לפונקציה + תגרוס למהדר ליצור אובייקט ומני שהוא העתק של האובייקט המקורי 5. הפונקציה תיקָרא עם האובייקט הזמני, והשינוייס שהיא תבצע על האובייקט הזמני לא ישפיעו על האובייקט המקורי. החיסרון במקרה זה הוא שנוצר אובייקט וזמני, שהוא העתק של האובייקט המקורי 8, ונדרש ומן ריצה להעתקה וגסם זיכרון נוסף. אם נגדיר את הפרמטר של הפונקציה 1 כייחוס, יעבור האובייקט בצורה הנקראת 6060206 עע. כך אין שפפול של האובייקטים והפונקציה פועלת על אובייקט המקור. (68 0ם1ע51)5%2 18סט ו ; ("6גו81ט שטסם")5.566 11)5( ; הפעלה של הפונקציה 11, במקרה וה, תגרוס לשינוי של אובייקט המקור. בקריאה לפונקציה זו אין המהדר מייצר אובייקט זמני, לכן נשמרת היעילות. החיסרון שבשיטה וו הוא בכך שהפונקציה משפיעה על האובייקטיס המקוריים. כדי לפתור בעיה גו אפשר להגדיר *יחוס קבוע (161076200 +5ת60), שאינו יכול להשתנות. ההגדרה של ייחוס קבוע נראית כך: (88 08ם1ע5%2 86ת53)00 ה1בסט ו ; ("6גו81ט שטסם")5.86% 8 ++6 ו-009 למתכנת המקצועי מילת המפתחת 6051 המופיעה לפני המשתנה, מציינת את העובדה שאין אפשרות לשנות את ערך המשתנה שמועבר לפונקציה; כלומר, הפונקציה אינה משנה את הייחוס. במקרה כוה אסור לפונקציה להפעיל פונקציה אשר עלולה לשנות את האובייקט. המהדר (ס11קננסס) לא ירשה פעולה כזאת, ובומן הידור נקבל הודעת שגיאה. |3.5 | פונקציות מחלקה ב-++6 יש אפשרות להגדיר פונקציות מחלקה (ב10ו6מט זסטנמסגע) כלומר, פונקציות אשר שייכות למחלקה מסוימת. פונקציה כזו מכירה את מבנה הנתונים של המחלקה ופועלת על אובייקטיס שלה. פונקציות כאלו דומות לפונקציות אחרות, אך שס המחלקה מתוסף לשס הפונקציה. לדוגמה, עבור מחלקה א ופונקציה כלשהי 1 של המחלקה, נרשוס: ()1::א ב1סטע [ מסנפסםתט+ 6ם₪ 0% 008 ... // ] לפני שםס הפונקציה מופיע שס המחלקה, לאחריו "::" ולבסוף שס הפונקציה. פונקציית מחלקה יכולה לקבל פרמטריס בדיוק כמו פונקציה רגילה. אפשר להגדיר פונקציה המשנה את הערך של המחרוות בצורה הבאתה: (8* ע8ת0 8%6ם6::86%)00ת1ע562 1בסט ;(8)ם8%216 = ת16 6ם1 2 [] 461666 ;[1 + ם0282]16 חסם = ע56 ;(5 ,562)צץ56200 ] הפרמטר של הפונקציה מוגדר כמצביע קבוע. כלומר, תוכן המצביע למחרוזת אינו יכול להשתנות על ידי הפונקציה 8%6. הפונקציה משחררת את אזור הזיכרון הישן, מקצה אזור ויכרון חדש ומעתיקה לתוכו את המחרוזת הנתונה. פונקציה זו משנה את האובייקט עליו היא פועלת. הגישה לשדות באובייקט שבתוך פונקציה היא ישירה, ואין צורך להשתמש במצביע לאובייקט הנוכחי (1118). פונקציות קבועות פונקציה קבועה (תסגוסתט] +ם59תס6) אינה משנה את האובייקט שעליו היא פועלת. הפונקציה הקודמת, 5%, אינה יכולה להיות פונקציה קבועה, מפני שהיא משנה את האובייקט שעליו היא פועלת. לעומתה, פונקציה שמחזירה את הערכיס של האובייקט, או עושה חישוב כלשהו, יכולה להיות פונקציה קבועה. פרק 3: המחלקה | 79 פונקציה קבועה מאופיינת על ידי מילת המפתח +600%. עבור מחלקה א ופונקציה כלשהי קבועה 1 של המחלקה, מגדירים : %פסס ()5)6::א ב1סע ָ // ו הפונקציה )86 של המחלקה 8מוש5 אינה יכולה להיות קבועה, כי היא משנה את האובייקט עליו היא פועלת. שתי הפונקציות הבאות הן קבועות : ] 8ם1ע56 018588 8 :טס 7 2 (()000* ע8ת0 56םסס %2 ()מם66ת16 6ם1 ;ו % ()0::860םת1ע5%2* 0282 0056 ָ 2 תעגטססע % () בם06ת16: :8ם1ע56 %6ם1 ו ;(8%2)ת5%216 תעגמ66ת ] הפונקציות 866 ו-ג81ם6! אינן משנות את האובייקט שעליהן הן פועלות, ולכן הן יכולות להיות קבועות. פונקציות מסוג וה יכולות להיקרא עבור אובייקטיס קבועים. למשל, ; ("ץעהט")51 06ם1ע56 ; ("60%רסס 8%ם52)"00 8ם1ע56 56ת0ס0 א%ס // ; ("6גו81ט")51.8566 %עסע62 ת118610קתס6 // ; ("52.56%)"78106 6% // ; ()ם05םת82.16 = ת16 6םת1 הקריאה לפונקציה 86 עבור האובייקט 82 תגרוס לשגיאת הידור. המהדר :ודע שהאובייקט האחרון הוא קבוע, ולכן אפשר להפעיל רק פונקציות קבועות עליו. מנגנון 6חזוחו מנגנון הסתרת המידע (קַמו6ום מסווהתתס1ם1) יוצר מספר רב של פונקציות וקריאות לפונקציות. לעיתיס, קריאה לפונקציה היא בזבוז זמן ריצה של המחשב. כל פנייה 0 ++6 ו-009 למתכנת המקצועי לאובייקט נעשית דרך פונקציית שירות, ולכן עלול ומן הריצה של התוכנית לעלות באופן ניכר. הפתרון לבעיה הזו הוא מנגנון 181186 (בתוך השורה), שבעזרתו נחסכת הקריאה לפונקציה, מכיון שקוד הפונקציה כלול בשורות הקוד של התוכנית. עבור מחלקה כלשהי א ופונקציה כלשהי+ של המחלקה, הגדרת פונקציית 6תו[חו נעשית כך : ) 8% 018858 // :טס // 0 הבס ;ן כאשר המהדר רואה קריאה לפונקציה כזו, הוא מטפל בפרמטריס שלה כמו שהוא נוהג בפונקציה רגילה, אבל במקוס לקרוא לפונקציה הוא משלב בקוד התוכנית את קוד הפונקציה. למשל: ] 06ם1ע56 01858 // :טס // [ ;802 מעטסשע + ספתסס ()066* עהם0ס ספתסס ו ; ("0ת1ע586 8)"8 8מם1ע56 // ;()5.0665 = ע6פ* תַםת0 ספםתסס בנקודת הקריאה לפונקציה ‏ %₪ המהדר מוודא שהפרמטרים והערך המותזר מהפונקציה תואמיסם, ואז הוא מחליף יחליף את שס הפונקציה בקוד עצמו. במקרה זה המהדר מוודא שהמצביע למחרוזת הוא קבוע, ואז הוא מחליף את המשפט הנתון במשפט הבא: = עס בכך תחסך הקריאה לפונקציה. פונקציה שהיא 1186תו יכולה להיות מוגדרת מחוצ לגוף המחלקה בתוספת מילת המפתח 6מ:ז1ח1, באופן הבא : ] 8ם1ע56 01858 ל 2 (()000* ע8ת0 56ם0סס ;ו פרק 3: המחלקה ‏ 81 0% ()0::86%ת1ע56* 8%9ם0 ספתסס 6ם11םת1 ָ 2 תעטגטססץ ו הגדרה זו שקולה להגדרה הקודמת ואין העדפות בין שתיהן. הגדרת פונקציה כ-6חו1ת1 אינה מבטיחה שהיא אכן תהיה כזו, כלומר אין חובה על המהדר להחליף את הקריאה לפונקציה בקוד שלה עצמו. הגדרה כזו היא בגדר המלצה למהדר. אם, למשל, יש משפט לולאה (מסוג 102 או 6|ותש), בפונקציה כזו רביס הסיכוייסם שהפונקציה לא תהיה 6מו1מ1. הגדרה של פונקציה כ-6ו!מו תגרוס לשורות קוד רבות יותר, בדומה לפריסת מאקרו, ולכן יש להשתמש באפשרות זו בתבונה. אישית, איני ממליצץ להגדיר פונקציות ארוכות, מעל שלוש שורות קוד, כפונקציות 86ו1ם1. במיוחד איני ממליץ להגדיר פונקציות 6מו[חו כפונקציות המכילות מבני בקרה. המושג מאקרו (סזסגנו) חדש לנו בהקשר לשפת 6 ולכן נסביר אותו בקצרה. מאקרו הוא קטע תוכנית דמוי-פונקציה, אשר מטופל ברמת קדס המהדר (0068850זק-6זכ). מאקרו מתחלל בתו *' ומילת המפתח (השמורה) '661806', כך למשל: 6תו061. והינה מאקרו לדוגמה: 5 א 6ם661א. מאקרו וה קובע שהתו א יוחלף בערך 5. על כן, בכל מקוס שקדס-המהדר יזהה את התו א, הוא יחליף אותו בסיפרה 5, וכתוצאה - המהדר לא י'ייראהיי תווי א, אלא ספרות 5 בלבד. יש אפשרות להגדיר מאקרו בצורות שונות, כמו למשל, (0.5+א) (%ם11) (א)בםמטסץ 6ם461+1+ במקרה זה, קדס המהדר יחליף את (א)6מטס? בביטוי המתימטי העוקב. כאן לא תהיה כל קריאה לפונקציה, אלא הרצת פקודות רגילות, שהן יותר יעילות. עס זאת, למאקרו יש גס מספר חסרונות, כפי שנראה בהמשך. פקודת מאקהו יש הסובריס שפונקציית 6םו!פו היא מאקרו, אך אין ה כך. הפרמטרים של מאקרו מטופליס באופן שונה מאלה של פונקציה. במיוחד יש לשים לב לעובדה שהמעבד העורך את המאקרו סורק את המקור והמהדר לא עושה זאת. כלומר, המהדר רואה כבר את תוצאת פעולת ההחלפה אשר מבצע המעבד של המאקרו. נגדיר לדוגמה, את המאקרו הבא : ((צ) : (א) ? (ץ) > (א)) (ץ ,א)תםגת 6ת4611+ מאקרו זה מחזיר את הערך הנמוך ביותר שבין שני ערכיס נתוניס. כפי שכבר הסברנו, השימוש במאקרו דומה לשימוש בפונקציה. הנה דוגמה: ;1- = א %6ם1 7 = ץ 60מ162פגו ;(ץ ,א)תנת = 2 6ת1 12 ++6 ו-009 למתכנת המקצועי התוצאה שהמשתמש מצפה לה היא ש-2 מקבל את הערך 1-. אבל במספר מהדרים יומר הערך השלילי של המשתנה א לערך משתנה שלס חסָר סימן, ולכן יקבל ערך הגבוה מ-60. הערך של המשתנה 2 הוא בלתי צפוי. במקרה אחר ייתכן המצב הבא : = ץ ,1=א 6ם1 ;(ץ ,++א)םתנת = 2 6ם1 במקרה זה, כוונת המשתמש היתה להגדיל את א לאחר מציאת המינימום בין א ל-ץ. השורה שנפרסת על ידי מעבד המאקרו היא כזו: ;(ץ : (++א) ? (ץ) > (++א)) = 2 6ם1 המשתנה א יגדל פעמיים, והתוצאה שיקבל 2 היא 2. למרות שהמאקרו נראה כפונקציה, הוא אינו פונקציה וגם ההתנהגות שלו שונה מזו של פונקציה. חיסרון אחר של מאקרו הוא שתוכניות ניפוי (60008062) אינן מכירות אותו. הסיבה לכך היא שהמהדר אינו יכול ליצור סמל עבורו בטבלת הסמלים, לכן אין כל אפשרות לדבג אותו. סמל ([0סגתץ5) הינו אלמנט אשר המהדר מחציק עבור כל משתנה או פונקציה בטבלה, אשר קרויה טבלת הסמלים בזמן הידור. פונקציות אשר אינן שייכות למחלקה יכולות אף הן להיות פונקציות 6תו]מו. אפשר להגדיר פונקציה שמוצאת את הערך הנמוך גס באופן הבא : (82< %ם1 ,1א %ת1)תנת 6םת1 6םת11ם1 ָ ;(2א : 1א ? 2א > 1א) םעגמ66עת ו פונקציה זו אהה מבחינת היעילות למאקרו הקודם שהגדרנו, אבל היתרון שלה בכך שהפעולות מתבצעות על הפרמטריס של הפונקציה פעס אחת בלבד. לכן השורה הבעייתית ;(ץ ,++א)תנת = 2 6ם1 היתה מכניסה את הערך 1 למשתנה 2 ומקדמת את א ב-1 בלבד. אופרטורים אופרטורים הס פונקציות מיוחדות של המחלקה, אשר שמם כשסם האופרטוריס הבסיסייס של השפה. למשל, האופרטור גדול או קטן (>,<). אופרטוריס יכוליס להיות אופרטורים בינארים (02ו8זסקס ץזהמנט), או אופרטורים אונלרים (6140029ק0 ץגמטט). אופרטוריס בינאריס הס אופרטוריס בעלי שני אופרנדיס ואופרטורים אונריסם הס בעלי אופרנד אחד. פרק 3: המחלקה | 83 היכולת להגדיר אופרטורים ב-++6 הופכת את מושג המחלקה לסוג חדש של משתנה המוגדר על ידי המשתמש. יכולת זו מאפשרת להרחיב את השפה. כלומר, להגדיר מחלקות אשר מתנהגות כמו משתניס וסוגיס בסיסייס בשפה, לדוגמה שלמים. בסעיף זה נראה אופרטוריס שוניס שניתן להגדיר באמצעות מחלקות, וכך לדמותס למשתניס בסיסייס של השפה. אופרטורים אונרים אופרטורים אונרים (6190019ק0 ץזגתט) מקבלים ארגומנט אחד. אופרטור כזה יכול להיות, למשל, אופרטור השלילה !יי של ++6 (וגס של 6). עבור מחלקה א ואופרטור סקס מגדיריס אופרטור כלשהו (אונרי, או בינארי) בדרך הבאה: 01858 % ) 7 ; (00)820-118% 02628602 81ט-6%6ע2 ;ו לדוגמה, נגדיר את אופרטור השלילה עבור המחלקה 58 באופן הבא: ] 6ם1ע56 01858 0 :טס 7 2 () !00628602 %6ם1 [ ;(0==(ע8%%) ם56%16) מע00ס6ץ? + ל האופרטור הוא אונרי (עְזגּחט), משוס שהוא פועל רק על האובייקט הנוכחי. במבט ראשון, נראה האופרטור קצת מוזר משום שאינו מקבל ארגומנטים. השימוש בו מסביר מדוע הוא אונרי: ;("")8 8ם1ע56 0 // ... 60 806018 ] האופרטור פועל רק על האובייקט שלו, ונראה כאילו הוא מקבל ארגומנט אחד. במקרה זה האופרטור יי!יי יחזיר ערך אמת (אורך המחרוות הוא אפס), ולכן יתבצע משפט 11. אופרטורים בינארים אופרטורים בינארים (619007ק0 ץזאחוט) הס כאלה הפועלים על שני ארגומנטיסם, לדוגמה האופרטור *>י. אופרטור כזה מחזיר ערך השונה מאפס אס התנאי שהוא 4 ++6 ו-009 למתכנת המקצועי אמור לבדוק נכון, אחרת יחזיר ערך אפס. למחלקה כמו 50188 אפשר להגדיר מספר אופרטוריס בינאריס : ] 8ם1ע56 01858 7+ תַַם0 :טס 7 (88 0ם1ע8% 86ת628602>)00ק0 %ם1 [ ;(0 > (ע5.58 ,ע562) קת0סע5%) םמעט60ע2 + (88 0ת1ע8% 56ת628%02==)00ק0ס %6ם1 [ ;(0 == (ע5.86 ,ע56) קת0ע8%) מעטס6ץ + ;ו בקטע קוד וה מוגדרים שני אופרטורים. אחד עבור ייקטן לקסיקוגרפית'י, ואחד עבור יישוויוויי. למרות ששני האופרטוריס נראים כאילו הס מקבליס פרמטר אחד, הס פועלים למעשה על שני פרמטריסם. הפרמטר הראשון סמוי - האובייקט הנוכחי, ואילו הפרמטר השני הוא האובייקט 5 שנמסר להס. השימוש בשני האופרטוריס הוא כזה: ; ("52)"52 ,("81)"51 8ם1ע56 15 )81 == 82( ף>מסעח שעשט 08ם1ם8006% // (82 > 81) 15 61586 // 6% כאשר מתבונניס בקטע הקוד שמשתמש בשני האופרטורים, קל להבין מדוע אלה אופרטורים בינארים, כי הס מקבלים שני אובייקטים. האובייקט השמאלי (81) הוא האובייקט שעבורו הופעל האופרטור. במיליס אחרות, זהו האובייקט שהמצביע 018 מצביע עליו. האובייקט הימני (52) הוא האובייקט שמועבר כארגומנט לאופרטור. אופרטור חשוב במיוחד הוא אופרטור ההשמה (61400ק0 %מ10ַמ85%18). לעיתים, אופרטור גה נקרא גס אופרטור העתקה (61000ק0 שְקסס). עבור מחלקה % כלשהי ייראה אופרטור ההשמה כך: ;(68 % 5%6ת600628602=)00 א כלומר, האופרטור מקבל ייחוס קבוע לאובייקט של א ומחזיר ייחוס לאובייקט של א. אופרטור זה חשוב במיוחד, משוס שהוא מוענק אוטומטית על ידי המהדר, גס כאשר המתכנת אינו כותב אותו. ההעתקה המתבצעת על ידי האופרטור הזה היא העתקה רדודה (עְקסס שס[51381), כמו במקרה של בנאי ההעתקה 6050700000 עק00 כלומר, רק השס מועבר ולא הקוד עצמו). במקרה של המחלקה 8ה5₪1, לאחר העתקה כזו ישנס שני מצביעיס אשר מצביעיס לאותו אזור זיכרון: ; ("51)"51 8ם1ע56 ; ("")52 6ם1ע56 פרק 3: המחלקה | 85 כתוצאה ממצב זה ישוחרר אזור זיכרון זה פעמיים, פעם אחת על ידי פונקציית הפירוק של 81, ופעסם אחת על ידי זו של 82. דבר וה יכול לגרוס לתוצאות בלתי צפויות במחלקות שיש להן מצביעים, לכן יש להגדיר עבורן אופרטור העתקה. במקרה זה נגדיר את אופרטור ההעתקה באופן הבא: ] 8ם1ע56 01858 7 ;(88 06ם1ע562 8%6ת00)= ע600028%0% 6ם1ע56 ;ן ברגע שמוגדר אופרטור כזה, המהדר אינו מגדיר את אופרטור ברירת המחדל ואנו יכוליס להגדיר את האופרטור שלנו שיישס את פעולת ההעתקה. הפעולה תתבצע על ידי הקצאת אזור זיכרון מתאיס שלתוכו תועתק המחרוזת של האובייקט השני המשתתף במשפט ההשמה. אופרטור ההעתקה עבור המחלקה האחרונה ייראה כך: (88 8ם1ע55%2 58ם00) = ע62860%ק0::0ם69%21 8מם1ע56 ;57 [] 061666 2[ + (ע5.56)ם82]5%216ם0 חסם = ע56 ;(2ע8.85 ,7)562ץ56200 ו אופרטור העתקה (61400ק0 עקסס) אינו יכול להיות פונקציה קבועה, מכיון שהוא משנה את האובייקט עליו הוא פועל. חוק: למחלקה עס מצביעים מומלצ לכתוב אופרטור העתקה. דבר וה מומלץ גס למחלקות אשר העתקה רדודה אינה מתאימה להן. סיכום האופרטורים לפי עדיפות הטבלה הבאה מתארת את האופרטורים השונים של השפה ואת רמת העדיפות היחסית שלהם. האופרטור :: הוא בעדיפות 17, לכן הוא קודס לכל שאר האופרטוריס. אופרטור הפסיק הוא בעל העדיפות הנמוכה ביותר. האופרטורים : "812601'י, '::', !יי יי1יי אינס ניתניס להעמסה (8הו611040צס, להגדרה מחודשת, או נוספת) על ידי מחלקה כלשהי. כל שאר האופרטוריס ניתניס להעמסה. אופרטוריס אשר לא תארנו עד עתה בפירוט יתוארו בהמשך הספר. אופרטור ועדיפות דוגמה 1 (17) | ציון שס מקומי, כמו שדה של עסמתסת: :פתהת 01858 מחלקה 11 (17) | ציוןו שס גלובלי במרחב מקומי סתהת:: . (16) | ציוו שדה במחלקה או מבנה מס [פס ;051 א 6 ++6 ו-009 למתכנת המקצועי 12% +- שטסת 5% 0 -<* )16( )16( )16( )16( )16( )15( )15( )15( )15( )15( )15( )15( )15( )15( )15( )15( )14( )14( ציון שדה דרך מצביע ציוו תא במערך קריאה לפונקציה בניית אובייקט החזרת גודל של אובייקט בבתיס הגדלה באחד (6זק 6ם8 205%) הקטנה באחד (16 6ם8 +205) פעולת המשלים, הופך סיביות של מילה נתונה פעולת השלילה, הופך ערכים לוגייס של אמת ושקר. מינוס אונרי - שינוי סימן של משתנה פלוס אונרי לקיחת כתובת של משתנה תוכן של מצביע הקצאת זציכרון (גס של מערך בתוספת יין ]'') שחרור ציכרון המרות של סוגיס ציון שדה ציוו שדה באמצעות מצביע עססמתפסת<-62ס ;ע2סס* א% ; [20]%ע82 ע8%ם60 ;'8' = [5]לע8 ; (820-1186)סםתט1 ; (826-115%)א <% ;א א% ; (א) 512605 512605 )%( ; , 3 ;9+ <ךָ סמב ל תה 72 1 2 סםב ו ] 1 ;א- = 7 ;א%,7ך %ם1 7 = סך ;סךָ* ,ךָ סם1 ;סךָ* = ך ;סךָ* ,ךָ 6םמ1 ?סא << שַהתס ;[5] ע8םת0ס טסם = 5 ;א חסם = קא ;קא* % ;58* פַהַםס 061666 ][ 2 ;סקא 061666 7 פאת6 ;ך %ם1 [(82ת0) = 60 ו ;| ;2א ;א א ;(ק*::א) %ם1 ;%1א.א6% = ס ,1א 6ם1 2 = ק*.א ;סא* % = פרק 3: המחלקה | 87 * (13) : (13) + (12) . (12) << ע1) >> ע1) >, >= (10) <, <= (10) == (9) = | (9) 8% (8) 2 (7) (6) )5( 6% )4( [ כפל חילוק חיבור חיסור הווה ימינה בסיביות. הזוה כזו גורמת לחלוקה בשתיים. הזוה שמאלה, שקולה להכפלה בשתייס קטן, קטן שווה, מתפתח לערכי אמת גדול, גדול שווה שווה מקבל ערך אמת אס שני הצדדים זהיס שונה (אינו שווה), מקבל ערך אמת, אס האופרנדים שוניס פעולת ייוגםיי על סיביות 'יאויי אקסלוסיבי - סיביות שונות בלבד מקבלות ערך 1 ייאויי של סיביות. מספיק שסיבית אחת נמצאת במקוס המתאים, אז התוצאה היא אחד, בסיבית המתאימה. 'יוגס'י לוגי. כדי לקבל אמת, שני האופרנדים חייביס להיות אמת ייאויי לוגי. 8 ++6 ו-009 למתכנת המקצועי |, 2 3? 2 * 2א% = 3 22 2[ 2 / 2א = 7 ,7 ,א ;ץ + א 7,ץ,א + 7 ,ץ ,א ;ץ %< 7,ץ,א ;ץ | א % - ₪ 8 +. ₪ ₪ ₪ ₪ 7% (2) | תנאי 7 סמסםמ1 ; (ץ א ? צְ<א) = 2 = (2) | פעולת השמה ;ץצ,א %6ם1 ;ץ < =עססס (2) | פעולה על האופרנד השמאלי. זסקס ;א 8ם1 יכול להיות : **, 'י/", "6", *'+", =*א ו ו "<<", "א" ישוי ואחוו, , (1) | פעולה סדרתית. התוצאה של ;ץ ,א 6ם1 הביטוי האחרון בסדרה ;(2 ,1<ץ) = א בכל מקרה של ספק בעדיפות אופרטוריס, אפשר להשתמש בסוגריים (כלומר :(...)'), כפי שאנו לציין את סדר הפעולות בביטוייסם מתמטייס. שדות סטטיים המשותפים לאובייקטים ב-++6 יש לכל אובייקט את השדות שלו ושדות אלה אינס משותפים למספר אובייקטים. אך לעיתים נגלה צורך בשדות אשר משותפיסם לכל האובייקטים. שדות המשותפים לכל האובייקטיס נקראים, לעיתים, שדות מחלקה (116165 61888), או שדות סטטיים (116165 51810). לדוגמה, אס אנחנו רוציס לדעת את מספר האובייקטיס ממחלקה מסוימת בכל זמן שהוא, היינו רוציסם שדה המשותף לכל האובייקטים, שיּמֶנֶה את מספר האובייקטיס. השדה הזה יכול להיות מוגדל בבנאי ומוקטן במפרק: ) 8% 01858 ;%מטססא 6סםת1 568610 :טס [ ;++סתטססא + ()א [ ;--%תטססא + ()%< ;ן שדה המשותף לכל האובייקטים יכול להיות מכל סוג בסיסי של השפה (או מחלקה אחרת), כאשר לפני שמו וסוגו מופיעה מילת המפתח 5)866. שדה כזה אינו שייך לאובייקט מסוים, אלא לכל המחלקה. על כן, אין השדה נוצר כאשר יוצרים אובייקט מסויס. השדה קיים לפני כל האובייקטיס כשהתוכנית מתחילה, והשדה נעלס (מפורק) רק כאשר התוכנית מסתיימת. לכן, יש לאתחל את השדה במקוס כלשהו בתוכנית. אתחול כזה נעשה בצורה הבאה: 2 = סתגטססא::א 6ם1 מומל לאתחל שדות של מחלקה בקוב המקור (00עט50) של המחלקה. קבצים כאלה כוללים את פונקציות המחלקה ומסתיימיס בדרך כלל ב-6 או 677. פרק 3: המחלקה | 89 פונקציות סטטיות פונקציות הפועלות על אובייקטיס מקבלות ארגומנט, או פרמטר נוסף בצורה לא מפורשת. ארגומנט זה הוא המצביע לאובייקט הנוכחי. ארגומנט זה מוענק באופן אוטומטי לכל פונקציה החברה במחלקה על ידי המהדר. מילת המפתח 118 היא הארגומנט החבוי הזה. עבור מחלקה כלשהי א ופונקציה כלשהי השייכת למחלקה, אפשר להתייחס למצביע 8 בתוך הפונקציה כמצביע לאובייקט הנוכחי אשר עליו פועלת הפונקציה. למשל: ) % 01858 ;81טא 6םת1 :טס [ ;א = 81טא + (א שת1)א [ ;81טא תעטספע + 008% ()66%6 6ם1 ;ו לפונקציה 86 יש פרמטר חבוי אשר מצביע לאובייקט הנוכחי שדרכו מוחזר הערך של השדה [4צא באובייקט הנוכחי. הפונקציה 8% יכולה להיות כתובה גם באופן הבא, והיא שקולה לגירסה הקודמת : [ ;81טא<-218ת% מעגמסשע + 008% ()66%6 6ם1 לפונקציות סטטיות אין מצביע לאובייקט הנוכתי, מכיון שאין להן אחד כזה. לפונקציה סטטית יש גישה לחלק הפרטי של המחלקה, אבל כדי לגשת לחלק הפרטי של אובייקט מסוים, יש להעביר לפונקציה מצביע לאובייקט. לעומת זאת, אם היא פונה לשדות סטטיים של האובייקט היא אינה צריכה מצביע לאובייקט, היות והשדה הסטטי אינו שייך לאובייקט מסויס. למשל: ) 8% 018858 12 סם1 ;+תטסס 6ת1 568610 :טס [;++פ6תטסס ;ט = 81ט + (ט 6ם1)א [ ;--פתטסס + ()%<> [ ;%תטסס מתעטס6ע + ()%ם86%00[60%5000 6ם1 568610 [ ;81ט<-ע%2קא מתעט6ס6ע + (ע6קא* %)86%6781 6ם1 568610 [ ;81ט םתעט6ס6ע + ()66%6 6ם1 ;ו במחלקה זו יש שני שדות. אחד (81) רגיל, והשני טמטס6) סטטי. למחלקה יש שתי פונקציות סטטיות: הראשונה (8610200[60800021) מחזירה את מספר האובייקטים הנוכחייס במחלקה. פונקציה זו אינה צריכה לקבל מצביע לאובייקט. הפונקציה הסטטית השנייה, אשר מחזירה מצביע לשדה של האובייקט, צריכה מצביע לאובייקט כדי לגשת לשדה המבוקש. 0 ++6 ו-009 למתכנת המקצועי הפונקציה השלישית של המחלקה (860) אינה פונקציה סטטית, ולכן אינה צריכה מצביע לאובייקט משוס שזה האחרון מסופק אוטומטית על ידי המהדר. הפונקציה יכולה לגשת באופן ישיר לכל שדה של האובייקט, וגסם לשדות המוגדריס כשדות סטטיים. דוגמה לשימוש בשדות ופונקציות סטטיות כדי להמחיש את השימוש במנגנון של שדות ופונקציות סטטיות נעיין בדוגמה. נתונה לנו מערכת מדפסות. מותר להגדיר שלוש מדפסות לכל היותר בעת ובעונה אחת. כדי לענות על דרישה זו נגדיר מחלקה זטומוו? שמייצגת מדפסת. ) עסשסתנגעקת 018588 2מטסס 6ם1 568610 72 סמס>תםב [ ;++%תטסס ‏ ;()6עקתפקס = 1116265 + ()62סםת1צק ; (6 ע6סת1עק 8%ם00)ע662םת1צק :טס [ ;--%ת6000 ;(11186261)%ע2ק01056 + ()662םת1עק- ()%062ם1ת0268%62* עס%םת1עקע 568610 [ ;(0 : ()ע682סת1עק שסם ? 3 > סתטסס) םמעט66ת ) ; (ע5%* ע8ת0 8%ם%6)00ם1עס 6ם1 7 למחלקה םוצ יש שדה טמטסס) הסופר את מספר האובייקטים הקיימים בכל זמן ושייכים למחלקה. נניח, שהקשר למדפסת הוא דרך 10000 816-6050) של א1אנז, שהוא מספר שלם. כמו כן, נניח שיש פונקציות של המערכת המאפשרת פתיחה של ערוצ למדפסת וסגירה של ערו כזה (7ק01050 ,6וקת6קס). לכל מדפסת יש מספר המאפיין אותה במערכת ההפעלה. נמקס את הבנאיס של המחלקה בחלקה הפרטי, כדי למנוע מהמשתמש במחלקה זו להגדיר מספר אובייקטים בלתי מוגבל של המחלקה. כתוצאה מכך, אין המשתמש במחלקה יכול להגדיר אובייקטיס באופן הבא : 2 מעס6סת1עק כדי להגדיר אובייקטיס ממחלקה זו, עליו להשתמש בפונקציה 007ם081671ע0. פונקציה זו בודקת אם מספר האובייקטים קטן משלושה. אם כן, מייצרת אובייקט חדש ומחזירה מצביע אליו, אס יש יותר משלושה אובייקטיםס מחזירה הפונקציה מצביע שערכו אפס. מצביעים מאופסים ב-++6 שקולים ל-1 1זצז. המשתמש משתמש בפונקציה ז10ם6268+0711 באופן הבא : ()662ם62::026886221סת1עע2 = סעק* עססםנ1נצק (סעס) +15 ; ("חַם1ע56 ת")6>םנ1עס<-6עק הקריאה לפונקציה סטטית נעשית על ידי צירוף של המרכיביס האלה: המחלקה, לאחריה ''::'* ולאחר מכן שס הפונקציה, כמו שראינו בדוגמה למעלה. פרק 3: המחלקה ‏ 91 מנגנון החבר (1680) מנגנון המחלקה מאפשר הסתרת מידע ממשתמשי המחלקה. הסתרת המידע נועדה להגן על המשתמש במחלקה מפני שינויים במבנה הנתוניס הפנימי שלה. שינוייס אלה לא צריכים להשפיע על משתמשי המחלקה, אלא על פונקציות המחלקה בלבד. ייתכנו מקריס בהס נרצה לאפשר לפונקציות, או למחלקות אחרות, גישה לחלק הפרטי של המחלקה. באופן עקרוני דבר וה אינו מומלץ ויש להשתמש במנגנון וה רק כאשר אין אפשרות אחרת להשגת פונקציונליות רצויה. כדי לאפשר גישה למחלקה, או לפונקציה אחרת, יש לצייןו את הדבר במחלקה שמאפשרת זאת. לדוגמה, נניח שמחלקה % מאפשרת לפונקציה + ולמחלקה צ את הגישה לחלק הפרטי שלה. המחלקה א מציינת את חבריה, המחלקה צ והפונקציה +, בעזרת מילת המפתח 1686ש1. לדוגמה: ) % 01858 ;ל 61858 06ת16ת1+ ; (*א)5 16סט 6ם12168 :טס 0 ;ן במקרה הראשון יש גישה לכל החברים (פונקציות) של מחלקה צ לשדות הפרטייס של א. כמו כן יש גישה לחלקיס הפרטיים של א על ידי הפונקציה 1. מנגנון החבר בשימוש כעת נחזור למחלקה 50156 ונוסיף לה מנגנונים ואופרטוריס נוספים אשר ישתמשו במנגנון החבר. בחלקה הפרטי של המחלקה נגדיר שתי פונקציות שמעדכנות את המחרוזת שמחלקה זו מכילה. פונקציות אלו ישמשו את פונקציות המחלקה, או חבריס של המחלקה. הפונקציה הראשונה שמקבלת פרמטר אחד, מצביע לתווים, מעדכנת את התכולה לערך מצביע וה. הפונקציה השנייה מקבלת שתי מחרוזות ומשרשרת ביניהן. שאר הפונקציות של המחלקה הן פונקציות 6פו!מוּ המשתמשות בפונקציות עדכון המצביע 8 של המחלקה 8םוזו5. שתי הפונקציות המוזכרות הן בעלות אותו שם (5600). דבר וה חוקי ב-++6 ונקרא 061030 או העמסה בעברית. ההבחנה בין פונקציות אלו נעשית במקוס הקריאה לפונקציה, על פי הארגומנטים שמעבירים לפונקציה. המהדר אינו משתמש בערך המוחזר מהפונקציה כדי להבדיל בין פונקציות מועמסות. אס יש שתי פונקציות מועמסות השונות ביניהן אך ורק בערך המוחזר, המהדר יציין ואת כשגיאת הידור. חוק ה נובע מהעובדה שקריאה לפונקציה אינה חייבת להשתמש בערך המותזר על ידה. לכן, אס יש שתי פונקציות השונות רק בערך המוחזר, אין אפשרות להבדיל ביניהן במקרה כזה. 2 ++6 ו-009 למתכנת המקצועי בנאים ל-4ח5471 לאחר הגדרת הפונקציות הפרטיות, מוגדריס הבנאיס של המחלקה בחלק הציבורי שלה. הבנאי הראשון מקבל מצביע למחרוות ויוצר אובייקט מסוג פַתו8. בנאי וה משתמש בגירסה הראשונה של הפונקציה 8%6. הבנאי מאפס את המצביע 56 לפני גוף הבנאי. משפטיס כאלה, המתרחשים לפני גוף הבנאי ומופיעים מייד לאחר ":" ולפני הסוגריים המסולסלים, מסמניס את תחילת גופו של הבנאי (כלומר, הקוד של הפונקציה). אס יש מספר שדות המאותחלים לפני גוף הבנאי, מופיעיס אלה אחד לאחר השני כאשר פסיק מפריד ביניהם. בנאי זה נקרא לעיתים גם אופרטור הבנאי (0ו8זסקס מס6סט50ת600). בנאי המקבל פרמטר אחד יכול לשמש גס להמרה מסוג הפרמטר לאובייקט של המחלקה. לדוגמה, אס נתונה פונקציה שמקבלת אובייקט מסוג 8ת5₪1, וקוראיס לה עס מצביע למחרוזת, יבצע המהדר המרה אוטומטית של המצביע לאובייקט של המחלקה בעזרת בנאי ההמרה. לדוגמה: (8 6םת1ע5)56 %ב1סט ו // ; ("0ם1ע56 1)"0 לפני הקריאה לפונקציה ייצור המהדר אובייקט זמני מסוג 56158 מהמחרוזת, ויקרא לפונקציה עס אובייקט ומני זה. המהדר עצמו ידאג לפרק את האובייקט לאחר הקריאה לפונקציה. הבנאי השני יוצר אובייקט מסוג 5158 המכיל מצביע למחרוזת, שהיא שרשור של שתי המחרוזות המועברות אליו. בנאי ה משתמש בגירסה השנייה של הפונקציה 86. הבנאי השלישי הוא בנאי ההעתקה. בנאי וה מוענק למחלקות שאינן מספקות אותו כבנאי ברירת המחדל. כשהמהדר מעניק בנאי וה, הוא משתמש בשיטת העתקה רדודה. היות ויש לנו מצביע במחלקה, עלינו לספק בנאי העתקה. המפרק של המחלקה משחרר את הזיכרון אשר הוקצה באחת מפונקציות 8%. השחרור נעשה ואת בעזרת קריאה לאופרטור 861666 של מערך. ] 8ם1ע56 018588 למ%ם* עהתס ; (8* ע8םת0 8%6ם586%)00* 6םת1ע56 ; (82* 82ת0 008% ,81* ע8םת0 8%6ם5856%)00* 6ם1ע56 :טס 8 // [ ;(86%6)5 + (8₪2)0 : (5* ע8%ם0 8%מ6)00ם1ע562 (5862)0 : (52* ע8%ם0 6פתסס ,51* ע8ם0 8%מ6)002ם1ע562 + 865)81, 52(; [ פרק 3: המחלקה | 93 [ ;(ע56%)8.850 + (585₪2)0 : (865 6ם1ע5% 8%מ6)002ם1ע562 [ ;802 [] 861686 + ()6מם8621- 8 סמסםתס7תםש851 // ; (ע586%)8.5%* מע6%0ע +(865 8ם1ע5% 56ת00ס)=602628%02 0ם1ע56 [ ;(56%)8* מעגמסשע + (8* ע8ם0 56ת00ס)=602628%02 0ם1ע562 8 צשצ 6408110 // (88 0ת1ע8%2 86ת628602==)00ק0 %6ם1 [ ;(0==(ע58.802 ,ע5602) קת0ע552) תעטס6ץ ]1 (88 8ם1ע55% 5%ת00 ,8%2* ע8ת0 58םת628%02==)00ק0ס 6םת1 8₪ם1216+ [ ;(0 == (ע8.58 ,ע8%) קת0ע5%2) םמעט266 ) 8 ([8108א16 // (88 0ם1ע8%2 8%ת628802>)00ק0 %ם1 [ ;(0 > (ע8.86 ,ע8%2)קת0ע5%2) מעט66ת ] (88 06ם1ע55% 8%ת00 ,862* ע8ם0 6פ5םתסס)>628%02ק0ס 6ם1 8₪ם1216 [ ;(0 > (ע8.86 ,ע8%)קת0ע5%) מעט266 ) 8 סחם 05 ת8%10ת0866ם00 // (882 8םת1ע8% 008% ,81* ע8ם0 00286)+02ס6286קס 8םת1ע5%6 0מם1216 [ ;(ע82.8% ,06)891םת1ע86 מעט66ת ] (88 06ם1ע562 8%ת628%02+1)00ק0 06ם1ע562 [ ;(ע8.8% ,ע06)562םת1ע86 םמעט66ת ] (65 06ם1ע5%2 8%6םת00)=+6002628%02 0ם1ע562 [ ;(ע8.85% ,ע86%)85%2* םע600? + 8 /]|/ [ ;862 תעט60ע2 + 86ת00 ()0852 96%6* עהם0 856ת00 ;ו למחלקה 50158 יש שני אופרטורי השמה (8)08זסקס 1ם20ם35%18), אשר קרוייס לעיתיס גם בשס אופרטורי העתקה (019ו619ק0 ע600). האופרטור הראשון מקבל ייחוס לאובייקט מסוג 8מו5₪. הוא יוצר אובייקט המכיל מצביע למחרוזת הזהה למחרוזת עליה מצביע האובייקט הנתון. האופרטור מחציר י*יחוס (0800ש00ו) לאובייקט של מחלקה מסוג 188ו507. דבר זה נעשה כדי לאפשר מספר השמות בזו אחר זו: ; ("52)"52 ,("81)"51 8ם1ע56 ; ("")53 06ם1ע56 4 ++6 ו-002 למתכנת המקצועי משפט ההשמה המורכב מאפשר השמה של 82 ל-81 וגם ל-83. גם במקרה זה הייחוס שימושי. האובייקט המוחזר מאופרטור ההשמה הוא ייחוס, ולכן נמנעות העתקות מיותרות של אובייקטים. האופרטור השני מאפשר השמה של מחרוזת רגילה לאובייקט מסוג 8ַתו5₪. אפשר להשתמש באובייקטים אלה בדרך זו: ;"6ם1ע56 חטסם בת" = 53 אופרטורי ההשוואה (079ז619ק0 87150ק601) מאפשרים להשוות בין שני אובייקטיס מסוג 5₪128, או בין מחרוזת לאובייקט מסוג 8םו50. אופרטור ההשוואה השני מוגדר כחבר של המחלקה. אופרטור זה אינו פונקציה של המחלקה. הסיבה לכך היא, שאופרטור שהוא פונקציה של מחלקה חייב לקבל אובייקט בצידו הימני. לכן, אס אנו רוציס לכתוב למשל: (53 == "6ם1ע5%2 חטסם ת") 11 8 אנחנו חייביס להגדיר את אופרטור ההשוואה כחבר (111606) של המחלקה. מומלצ שלא להגדיר פונקציות כחברות של מחלקה, משוס שזה פוגע בהסתרת המידע. יש להימנע מהגדרת פונקציות כאלו, פרט למקרים מיוחדים, כמו המקרה לעיל. האופרטור ההפוך, המקבל מצביע למחרוזת, אינו מחויב המציאות, מכיון שיש בנאי המאפשר המרה של מצביעים למחרוזות, לאובייקטיס של 8תוש5. המהדר יודע ליצור אובייקט זמני במקריס אלה, לאחר מכן המהדר משתמש באובייקט הזמני כדי לקרוא לאופרטור ההשוואה הראשון. באופן דומה מוגדריס אופרטורי הסדר הלקסיקוגרפי של אובייקטיס מסוג 8ַמוזו5. לבסוף, מוגדריס האופרטורים לשרשור בין שתי מחרוזות. האופרטור הראשון הוא חבר של המחלקה ומאפשר לשרשר בין מחרוזת של 6 לבין אובייקט מסוג 5005. הפרמטר הראשון של אופרטור זה הוא מחרוזת של 6. האופרטור השני מאפשר לשרשר בין שני אובייקטיס מסוג 8₪156. בעזארתו אפשר לכתוב: 3 שק( 67 הפ 7 167% תד 53 = 81 + 27 אופרטור חיבור- השמה (701800ק0 6מ0גתת105-85818ק) האחרון מאפשר שרשור של אובייקט אחד לשני, ולהשתמש בתוצאה. דוגמה: 2 =+ 51 שתי הפונקציות, המבצעות את רוב העבודה, הן %%. הן מאפשרות לקבוע את הערך של אובייקט מסוג 5188 למחרוות אחת, או לשתיים. הגירסה הראשונה של הפונקציה 86% מקבלת מצביע לתו. הפונקציה מקצה מערך של תוויס הגדול באחד מאורכה של המחרוזת הנתונה 8. הפונקציה מעתיקה את המחרוזת שהיא מקבלת (6 לאזור הזיכרון החדש ולאחר מכן, משחררת את אזור הזיכרון הישן. הפונקציה מחזירה מצביע לאובייקט הנוכחי. הדבר מאפשר להפעיל את הפונקציה פרק 3: המחלקה | 95 ברציפות מספר פעמים. עובדה זו מנוצלת על ידי האופרטור "= המחזיר ייחוס (00מ261070) לאובייקט הנוכחי כדי לאפשר השמות כפולות של אובייקטים מסוג פתו. (5* 082 8%ת0::56%)00ם5%21* 8ם1ע56 2 + (8)ם82]88216ת0 טחסם = עספשסם* ש8םס ;(8 ,עספאסם) צץ56200 061666 ][ 2; ;עספחסם = ע562 7 תעג6סע ו הגירסה השנייה של הפונקציה 5% מקבלת שני מצביעיסם למערכים של תוויס. הפונקציה מקצה זיכרון המספיק להכיל את שתי המחרוזות, בתוספת של תו אפס המסמן את סוף המחרוזת. לאחר מכן, משרשרת הפונקציה את שתי המחרוזות ומחזירה מצביע לאובייקט הנוכחי. עובדה וו מנוצלת על ידי האופרטור "=+". אופרטור זה קורא לפונקציה זו ומחזיר ייחוס לאובייקט הנוכחי. האופרטור מחזיר את תוכן המצביע המוחזר על ידי הפונקציה %%. עובדה זו מאפשרת להפעיל את האופרטור הזה ברציפות באותו משפט. (82* 0282 008% ,51* ע8%ם0 8%ם06::56%6)00ם1ע5%2* 6ם1ע56 ; (82)ם8%216 = 12 ,(81)ם8%216₪ = 11 6ם1 ;[1 + 12 + 11]ע82ם0 חטספם = עספטחטסם* מַַַםס ;(81 ,עספשס6ם) ץ56200 ; (52 ,11 + ע6פא6ם) ץ56200 461666 ][ 2 ;עספחסםת = ע562 ;615 תעגו6%ת ו לפיכך, לאחר פעולת הפונקציה האחרונה מכיל האובייקט הנוכחי את השרשור של שתי המחרוזות הניתנות לפונקציה. קטע הקוד הבא מדגיס את השימוש במחלקה זו: ()תנאת %ם1 ו ; ("53)"53 ,("52)"5245 ,("51)"81 מת5621 2 = 84 6מם1ש56 54 = 81 + 27 15 )"51" == 81( 12 >> "81 == 81 08" >> 6גוסס (81 > "50") 15 12 >> "81 > 50 א0" >> 0006 6 ++6 ו-009 למתכנת המקצועי 12 >> ()08902 84.00% >> " = 54" >> סוסס 2 26600 ו בקטע קוד זה מוגדריס מספר אובייקטים מסוג שַתו5₪, ולאחר מכן מופעליס האופרטוריס השוניםס. קטע הקוד מראה שהשימוש באובייקטים מסוג וה דומה לשימוש באובייקטיס בסיסיים של ++6, כגון שלמים, תוויס ומספריס ממשיים. המחלקה ב-++6 היא סוג חדש המרחיב את שפת המתכנת. המחלקה שהו5₪ יכולה גס להיכתב בעזרת פונקציות ההקצאה והשחרור של 6, כדי להשיג יעילות גבוהה יותר. אפשר להשתמש בפונקציה 1641100 ובפונקציה ₪66 כדי לאפשר שימוש חוזר באותו אזור זיכרון, במקוס להקצות מחדש את הצזיכרון בכל פעס שמשרשרים מחרוזות או מבצעיס השמה. בדרך כלל, מומלצ להשתמש באופרטוריס המתאימים, שסת ו(-66166, של ++6. הערה: הפונקציה 1691106 מאפשרת לשנות את גודל הזיכרון שהוקצה על ידי 41106מ. הפונקציה 1966 משחררת אזור זיכרון שהוקצה על ידי סס11ג או על ידי 0ס10811. אובייקטים כשדות של אובייקטים אחרים לעיתיס יש צורך ליצור אובייקטיס המורכביס ממספר אובייקטיס אחרים. אס נרצה לנהל מערכת שאוגרת ומבצעת פעילויות שונות של אנשים, יהיה לנו אובייקט שיתאר אדס. לכל אדס במערכת כזו יש שס פרטי ושס משפחה, ואולי גס פרטים נוספים. אס לפנינו מערכת לניהול שכר, יכולה להיות לאובייקט מסוג זה משכורת חודשית ושעות עבודה חודשיים. הגדרת תת-אובייקטים נתייחס למערכת ניהול שכר כמתואר לעיל ונגדיר אובייקט המייצג אדס במערכת זו. השס הפרטי ושס המשפחה הס מחרווזות, ואנו רוציס להגדירס כאובייקטים של המחלקה 8חוש8. דבר וּה ניתן לעשות ב-++6 בצורה הבאה: ]) ת80ע6ע 01858 מתספל6ק ₪6 01 שתהת 6ם6 // ;סתהם סַם5%621 סתהת 180117 // ; סתהאעט5 08ם1ע562 ץ5818% 6ם6 // ;ץ8 6ם1 ת%תסת 1886 ע0+ פעגוסםן // ;פעוסם 6סת1 :טס ; (%8ת %ת1 ,881 6ם1 ,םפ5* ע8ם0 ס6פתסס ,תםת* ע8ם6 6פתסס)םספלסק (תת* 82ת0 56ם0ס) פתת6ע סנ1נסט [ ;תחת = סתאַםת + ;(8 מ80ע62ע 58ם628602==)00ק0 6ם1 ;ן פרק 3: המחלקה | 97 השדות 86 ו-6ננגאט5 הן השס ושס המשפחה של אדם הנמצא במערכת. שני שדות אלה הס אובייקטיס של המחלקה 88ו0ו5. שדות אלה הס תת-אובייקטים באובייקט מסוג ם80ז26. פרט לכך, מוגדריס שדות נוספים שמייצגיס את המשכורת החודשית ואת מספר השעות שאדס זה עבד בחודש האחרון. הבנאי של מחלקה וו מקבל ארבעה פרמטרים אשר מייצגים את הערכים ההתחלתיים שיש לאובייקט ממחלקה וו. תבנית פונקציית הבנאי של המחלקה נראית כך: (8עת %םמ581,1 %6ם1,תפ* עהתס 6פתסס,תת* לַַםת0 86םת0סס)תספפסק::תספלסק (ם5) פתהאעגופ ‏ , (תם) פתּהּת 581827 = 2 ;פעת ספשטסת ו לפני גוף הבנאי מופיע רשימה של אתחול השדות שהם אובייקטים. במקרה זה, יש שני שדות כאלה: שת ו-סננאאתט5. האתחול נעשה בצורה דומה להגדרה של משתניס רגיליס מהמחלקה 8ַתו5₪. הבנאי הראשון של המחלקה 50188 מופעל ומקבל מחרוזת שהיא השם, או שס המשפחה. רשימת האתחול של השדות, שהם אובייקטים של מחלקות אחרות, מתחילה מהאופרטור 'י:" ומסתיימת בסוגר המסולסל השמאלי ('י)'י) המסמן את תחילת גוף הבנאי. אתחול שדות אלה נכתב לפני גוף הבנאי. סדר האתחול, או ביצוע הבנאיס של תת-האובייקטיס הוא לפי סדר ההגדרה שלהס במחלקה. במקרה זה יאותחל תמיד השם (סתאּה) לפני שס המשפחה (סַאּא50), גס אס סדר שדות אלה ברשימת האתחול של הבנאי יהיה הפוך. בגוף הבנאי מאותחליס השדות האחרים, שהס מבניס בסיסיים של השפה, כגון המשכורת החודשית. סדר אתחול זה הוא לפי סדר המשפטים בגוף הבנאי. למרות שלא הוגדרה פונקציית פירוק למחלקה מספעסק, תוגדר כזו למחלקה באופן אוטומטי על ידי המהדר. סדר הפירוק של תת-אובייקטים יהיה הפוך לסדר האתחול. ראשית, ייקרא המפרק של האובייקט המורכב, במקרה זה ם680ע, ולאחר מכן ייקראו המפרקיס של האובייקטים סגגאטפ ו-סַּת לפי סדר זה. הפונקציה 1608186 משתמשת באופרטור ההשמה של המחלקה ממחרוזת כדי לשנות את השם הנוכתי של אובייקט מסוג 802ז6ק. העתקת אובייקטים מורכבים כוכור, לכל אובייקט יש שתי פונקציות אשר מוגדרות באופן אוטומטי על ידי המהדר. לעומת זאת, יכול המתכנת להגדיר פונקציות אלו עצמו ולדרוס את גרסת המהדר. פונקציות אלו הן בנאי ואופרטור ההעתקה. הגירסה של פונקציות ההעתקה שמייצר המהדר, מבצעת את בנאי או אופרטורי ההעתקה של תת- האובייקטים. לפיכך, במקרה זה לא נזקקנו לאופרטור העתקה. 8 ++6 ו-009 למתכנת המקצועי אס נרצה לספק בנאי העתקה (או אופרטור העתקה) למחלקה זו, נכתוב ואת כך: (8062 תספ8ע6ק 56ת00)ם6280ק::ם6250כ (6ת8א2טפ . 62ס) סותהאמגופ | , ( סתהם. ע6ס) ספת ;ץ58182.תסס = 58182 ;פמוסת. עסס פטסם ו גירסה זו של בנאי העתקה שקולה לגירסה המסופקת על ידי המהדר כברירת מחדל (מס1)קס ]401801). במצב שאין סמנטיקה של העתקה עמוקה, אין צורך להגדיר את הפונקציות האלו (בנאי ואופרטור העתקה) שמיוצרות באופן אוטומטי על ידי המהדר. |3.9.3 דוגמה לשימוש במצביעים לתת-אובייקטים בפרק וה ראינו איך להגדיר מחלקה המגבילה את מספר המופעים של אובייקטיס ממחלקה זו. לדוגמה, המחלקה 21506 הגבילה את מספר המופעיס של אובייקטיס ממחלקה זו לשלושה אובייקטיס, לכל היותר. בסעיף זה נשיג את אותה התוצאה תוך שימוש במחלקה החברה למחלקה אחרת. נגדיר שתי מחלקות. ראשונה מבצעת את הפעילות האמיתית על המדפסת. מחלקה זו נקראת 2115007. המחלקה השנייה משמשת כמעטפה (קס61עם6) למחלקה הראשונה ותיקרא צםםזס)תוצק. תאפשר ליצור אובייקטים של שסומוזק. ) עססתנ1עעת 018588 ;טםתמץ?ס6תנ1עק 018898 6₪םת16ע12 662תנ1עס 60 תס1סס6תתס6 // 2 סת1 ; () ע%6ת1צק :טס ; (ע5%* ע8ת0 8%ם6)00ם1עק 6ם1 ;ו ]) טתמעססתנ1עק 018588 ;%מט 0 עס 6ם1 568610 ע66ת1עק 808881 6ם6 // * ע6סםת1שק :טס ]+ () טםמלס%ת1ק ;++%תטסס 2 חששסתם = סעס (3 > סתטסס) 15 ;0= מע 6156 ] [ ;%עק 86616686 ;--6תטסס + ()טםטעסספםת1צק- [ ;%עק תעטסשע + ()46%6* ע6סםת1צק פרק 3: המחלקה | 99 המחלקה טמ05)םו?? היא חברה של המחלקה ז6)מוזע. למחלקה טמםזט)םוזק יש שדה סטטי המציין כמה אובייקטיס ממחלקה זו קיימיס. הבנאי של מחלקה או יוצר אובייקט מסוג עשופוו? רק אס מספר האובייקטים קטן משלושה. מאחר והבנאי של זטזהוז? נמצא בחלק הפרטי, אפשר ליצור אובייקטים מסוג זה רק דרך שטמחזטומוזק שמגבילה את מספר האובייקטים מסוג זעסומוזק. הגדרה מקוננת של מחלקות ++6 תומכת בהגדרה מקוננת (ת0601819010 65166ם) של מחלקות. כלומר, ניתן להגדיר מחלקה בתוך הגדרה של מחלקה אחרת (פג6501ה, קינון מלשון 'קן'י). מחלקה שמוגדרת בתוך מחלקה אחרת אינה מעמיסה את מרחב השמות הגלובלי ואינה גורמת להתנגשויות עס מחלקות אחרות בעלות אותו שסם. שס אחר למחלקה מקוננת הוא מחלקה פנימית. תחוס המחלקה הפנימית הוא תחומה של המחלקה החיצונית. למשל: ) פת1ם 018588 ]) %ם1סס 01885 ;ץ,א %ם1 :טס [ סץ=ץ ;0סא=א + (סץ %6ם1 ,סא סם1)פ>תנסק [ ;א מעט6%ע + 00286 ()668% 6ם1 [ ;ץ מעט6%ע + 00286 ()צ668 6ם1 ; (8 %ת1סס 28%ם60081)00 6ם1 ;ן 2 ,1 סמתנסס :טס ו המחלקה |מוסק מוגדרת בתוך המחלקה 6מ11, בחלק הפרטי שלה. במקרה זה, המחלקה הפנימית תהיה מוכרת לשאר המחלקות, או הפונקציות, רק אס היא בחלק הציבורי של המחלקה התיצונית. מחלקות המוגדרות בחלק הפנימי מוכרות רק לפונקציות של המחלקה התיצונית, או מחלקות, או פונקציות אחרות המוגדרות כחברות של המחלקה התיצונית. לפיכך, המחלקה )מוסק מוכרת אך ורק לפונקציות המחלקה 1.1:6. לפונקציות המחלקה 6 יש זכות גישה לחלק הציבורי בלבד של המחלקה )מוסק. ראינו שרוב הפונקציות של המחלקה )םוסק מוגדרות בגוף המחלקה. לעיתים, יש צורך להגדיר פונקציות כאלו מחוצ למחלקה. במקרה כזה יש לציין שהפונקציה היא של מחלקה המוגדרת במחלקה אחרת באופן הבא: (ק8 %ת1סק 585%ת60081)00::%ם01ק::6ת21 6ם1 // ] 0 ++6 ו-009 למתכנת המקצועי שס המחלקה המכילה מופיע לפני שס המחלקה המקוננת, בתוספת אופרטור התחוס ''.:'י. בתוך הפונקציה, וגם ברשימת הפרמטרים, ההתייחסות היא לאובייקטיס מסוג +הוסק של המחלקה המקוננת. בדוגמה זו מודגש שהמחלקה המקוננת הינה מחלקה פנימית, וכך היא גם נקראת. כעת נוכל להגדיר, בחלק אחר של התוכנית, מחלקה )תוסק באופן הבא: ]) %ם1סק 01885 ;ץ ,א %ם1 :טס (0=סץ %ם1 ,0=0א סםת6)1תנ1סק [ ;סץ=ץ ;0א=א + [;א תעט6%ע) 5%ת60 ()א 666 6ת1 [ ;ץ תעטסס6ע + ספתסס ()צ668₪ %6ם1 ;ו ;01 סתנסס המשפט האחרון מגדיר אובייקט מסוג זמוסק, אבל לא של המחלקה המקוננת, ולכן אפשר להשתמש בו באופן הבא : ;()א 1.06%ק=א 6ת1 ; () צ460. 1ק=ץ 6ם1 אס, לעומת זאת, היתה המחלקה המקוננת מוגדרת בחלק הציבורי של המחלקה 6מו.1, ניתן היה להגדיר אובייקטיס של מחלקה זו כך: ;(2)3,4 ,(1)1,2ק 6ת1סס::6מת1ת1 הפונקציות המופעלות על אובייקטיס אלה תהיינה פונקציות של המחלקה המקוננת ולא של המחלקה הגלובלית. מומל להשתמש בתכונה זו כאשר מגדיריס ספריות, מבלי יילזאהסיי את מרחב השמות הגלובלי. אם הספריות הן גנריות, ולשימוש נרחב, יש סיכוייס להתנגשויות של שמות עס ספריות אחרות. | 3.11 | רשומות כמחלקות ב-++6 יש אפשרות להגדיר רשומות 5660 כמו ב-0. ההגדרה הבאה היא חוקית: ] %ףתמנ1נסק 56206 ;ץ,א %ם1 ל ;סק %תםנ1סק שלא כמו ב-6, אין צורך להוסיף את מילת המפתת 501000 כאשר מגדיריס אובייקטיס (מופעיס) של הרשומה. ב-++6 יש שתי תוספות נוספות: אפשרות להגדיר אזורי גישה, ואפשרות להגדיר פונקציות החברות ברשומה. פרק 3: המחלקה | 101 אזורי גישה ברירת המחדל של אזורי הגישה ברשומות היא גישה ציבורית. כלומר, לכל הפונקציות יש גישה לשדות הרשומה. אפשר לשנות את הגישה של שדות בעזרת שימוש במילות המפתח 6)גצוע או 6ו1פטש. שימוש במילות מפתח אלו מגדיר אזור גישה פרטי או ציבורי, בהתאמה, עד לשימוש הבא במילת מפתח אחרת. לדוגמה: ] %ףתנ1נסק 56206 7 סב :טס ;ץ %ם1 :טנס 6: 2 קז (ק68 פת1נסק)5 6נ1נסט 8% צס 116מטס - 0% // 72 = א.ס טס - 08 // 7 = צץ.ס |!|6סט1עק - עסעע6 // 72 = 2.ס הפונקציה 1 אינה יכולה לגשת לשדה הפרטל* 2 משוס שהוא בחלק הפרטי של הרשומה. לעומת זאת, היא יכולה לגשת לשדות האחריס של המחלקה, משוס שהס בחלק הציבורי. יש אפשרות לשנות את אזורי הגישה מספר לא מוגבל של פעמים. פונקציות של רשומות אפשר להגדיר שדות פרטים לרשומה, ולכן אך טבעי הדבר שתהיה אפשרות להגדיר פונקציות הפועלות על רשומות. ב-++6 רשומה היא מחלקה לכל דבר. אפשר להוסיף פונקציות המטפלות בשדות הפרטים של ומוס בצורה הבאה : ] %ףתנ1נסק 06גע56 ;א 6ם1 :טס ;ץ %ם1 : עס 7 סם1 :טס [ ;20 = 2 + (20 6ם5662)1 הנ1בסט [ ;2 מעטמ6ע + 00286 ()6662 6ם1 2 ++0 ו-009 למתכנת המקצועי שתי הפונקציות בחלק הציבורי של הרשומה מאפשרות טיפול בשדה הפרטי 2 של הרשומה. לפונקציות כאלה יש מצביע מוסתר (181) לאובייקט הנוכחי, בדומה לפונקציות של מחלקה, והשימוש בהן הוא כזה: ;סק %תנ1נסק ; (5662)5.ס ;()86%2.ק = 2 6ם1 לאחר סדרת משפטים זו יקבל המשתנה 2 את הערך 5. לכן, רשומות הס אובייקטיס רגיליס ב-++6. ההבדל בין רשומה למחלקה הוא שאזורי הגישה הס ציבוריים, אלא אם כן צוין אחרת. | 3.12 | מחלקות חסכוניות ++6 תומכת בשני מושגיס המאפשרים לדחוס זיכרון: איחוד (מסומט) ושדה סיביות (01111016). הא*חוד שימושי במקרה שיש מספר משתנים, ורק אחד מהם פעיל בכל רגע נתון. במקרה כזה, ניתן לארוז את המשתנים באזור זיכרון אחד. שדה סיביות שימושי כאשר יש מספר משתניס המקבלים ערכי אמת (6טו) או שקר (48150) בלבד. הדוגמאות המופיעות בסעיף ה נמצאות בקוב 80616.0 בדיסקט המצורף לספר. איחוד (חסוחט) איחוד (מסנמט) הוא מבנה המאפשר לקב מספר משתנים באזור זיכרון משותף. גודל המבנה המאוחד הוא כגודלו של המשתנה הגדול ביותר. הדבר מצמצס את אזורי הזיכרון המאחסנים אוספי שדות. הדרך להגדרת איחוד היא זו: 1 <סש6תהת-תס1תט> תסנתט ; ץע סמחתסות ו איחוד הוא מחלקה שכל חבריה הם ציבוריים, לפי ברירת המחדל. גישת שדות האיחוד ניתנת לשינוי על ידי מילות המפתח : 6ו[גוק, 0060060-ז (-3)6 טוז. אפשר להגדיר את האיחוד הבא : ;[ ;א %ם1 ;0 ע8ם6ס + א% תסנםתט גודלו של אובייקט מסוג א יהיה והה לגודל של שלס (מםו). גודל זה תלוי, כמובן, במחשב עליו מופעלת התוכנית. אובייקט מסוג א מכיל שני שדות החופפים באזור הזיכרון: א ו-6. למהדר אין שוס אפשרות לדעת איזה ערך נמצא כרגע באיחוד, לכן האחריות מוטלת על המתכנת. לדוגמה: ;א א ;7 תס ל פרק 3: המחלקה | 103 ;ך = א.א ו ההשמה בשורה האחרונה תגרוס לאיבוד מידע במקרה הטוב, ובמקריס אחריס להפסקת התוכנית. מכך ניתן להסיק שהשימוש באיחודיס אינו פשוט כלל ועיקר. הטכניקה אותה מפעילים, בדרך כלל, היא: להכניס איחוד כוּה לתוך מחלקה השומרת את הסוג הנוכתי של האובייקט שנמצא באיחוד. המחלקה הבאה (מסום!/) מדגימה ) מתסנמש 01858 טכניקה זו. ,6סץם עהת0 ,6קץ6 סת1 + 6סץ6 6ט1הט תגותס ; (6ס7ץ5 600016 ,6סקץ6 11086 ) א מסנתט ; 0781 ע8ם0 ;1 סםת1 11086 5081; ;0781 16סטס ;ו ;א % ;6סץ6 6קץ6 106א8ט (0ס 8%םת60)מסנמט [ ;6סץ6 0282 = 6סץ6 ;0 = 1הטס.א ] (1ב %ם1)תסנמש [ ;6סץ6 %ם1 = 6סץ6 ;1 = 1081.א 1 (?2 5108%)תסנמש [ ;6סץ6 5108% = 6סץ% ;1 = 5781.א ] (8 16סטסף) פמסנמט [ ;6סץ6 600016 = ס6סץ6 ;0 = 60081.א ן (80 82ם86%)0 6ם1 [ ;(6סץ6 ע8ת0ס == 6סץ6) םמעטס6ע ;0081.א = 6 ] (טצ8 %ם86%)1 6ם1 [ ;(6סץ6₪ 6ם1 == 6סץ6) םע2600 ;1081.א = ט ) ()1108% ע62860%קס [ ;81ט1.א םע0ט60? + :טס :עס :טס לן האיחוד המוגדר במחלקה מכיל מספר שדות שמתחלקים באותו אזור ויכרון בו-1מנית. המחלקה שמכילה את האיחוד, מחזיקה שדה נוסף שמסמן את סוג המשתנה הפעיל בכל רגע באיחוד. שדה זה מוגדר כ-נמטפתט. בנוסף, המחלקה העוטפת את האיחוד מגדירה בנאיס המקבליס ערכיס בהתאס לערך של האיחוד. במקרה זה, למשל, מוגדריס בנאיס עבור ערכים שלמים וערכים מסוג +11094. 4 ++6 ו-009 למתכנת המקצועי כדי לקבל את הערך של האיחוד מוגדרות מספר פונקציות גישה. כל פונקציה מחזירה ערך אמת (ערך השונה מאפס, בדרך כלל אחד) אס האיחוד מתאיס לערך המבוקש. לדוגמה: הפונקציה ‏ 86 הראשונה מחזירה ערך שלס בייחוס שהיא מקבלת, ואינדיקציה המסמנת לפונקציה שקראה לה אס הערך הנוכחי מתאיסם לערך המבוקש (במקרה ה - שלס). שדות סיביות (85פ) לשדות מסוימיס יש ערכי אמת בלבד, אפס או אחד. במקריס כאלה אפשר להציג את הערכיס במשתנה מסוג +ג618. אס יש מספר שדות כאלה, הרי זה בזבוז זיכרון לנצל 8 סיביות (6(81), מכיון שכל שדה כזה וקוק לסיבית אחת בלבד. כדי לפתור בעיה זו, מאפשרת השפה להגדיר סיביות בשדות ולהתייחס אליהס בהתאסם. הצורה הכללית של הגדרת סיביות היא : 57 : מססתסת 6סץ6 כאשר 106 מסמן את סוג המשתנה ויכול להיות סוג של שלס בלבד (גתס, זגסט, +ת1, +תנט, 11סם5, +נסםפט, פַתס1, פפסוט), לאחר מכן מופיע שס השדה, ולאחריו מופיע הסימן :יי ואחריו מספר הסיביות שמשתתפות בשס הנוכחי. הדוגמה הבאה מראה מחלקה עס שדה המחולק לסיביות. במחלקה 188% יש שלוש סיביות שמסודרות בשלם חסר סימן. המחלקה מאפשרת להכניס ערכים לסיביות השונות ולקבל את ערכס בעזרת פונקציות גישה. 018585585 518068 ] 72 : 016% 26סחץ6א 66ת16פגו 72 : 16ס םע66א6 66ת14פ8תגו 2 : 016 568610 66ת16פגו :טס 11885)( [ ;0 = 16 808610 = 16ם םע06א6 = 01% במסחץסם ] (צ 060ם10פ5תט)1%ס ב2סחץ%6 566 16סע [ ;ט = 1% 6שפסחץ6א ) 8% ()016 בעסחץ6א 666 60ת1פםגו [ ;01% 26סחאץ6א םע600ת ] 5 ()16 םמע66א6% 666 60ת14פו [ ;01% מע66א6% מעט266 ] לן הדוגמה הבאה מדגימה את השימוש בשתי מחלקות אלו. הפונקציה הראשית מגדירה מספר אובייקטיס מסוג מסנפ!ז ומכניסה לתוכס ערכים. כמו כן, היא מגדירה אובייקט מסוג 188 ונותנת ערכיס לסיבית המסומנת כ-6זסאוץ6א. פרק 3: המחלקה | 105 <ת.ת108%2608> 610866ת1+ ()מ1נהת %ם1 ק((5)5108%)4.1ט ,('06)'8 ,(1)1ט מסנמטס 7 11868 ;(01%6)1 בעסחאץ6א 1188.866 (5128601)8600016 >> " = (128601%)800016פםת" >> סגוסס (בט)812601 >> " = (1מ)12601פם" >> 1 >> " = 81ט 11086 1טם" >> ;[01ם6 >> (%ט)1108% >> " = 1הט 11086 +טמ" >> (60מ510םט) 5812601 >> " = (686ם510ם12801)0פת" >> סגוסס ()1%מ סעסאץ%6 1168.666 >> " = 16 בעסאץס6אם" >> ()1%ס ם662א6 1168.666 >> " = 16מ מעססאפם" >> ;01ת6 >> ;0 םעגו26% הפלט של התוכנית הזו יחיה: (0016ַ80) 51260 0 = (51260%)01 9. >= 91 51088 1גו 1 = 81ט 511086 %+ג 2 = (606ם18פםתט) 512605 1 = 016 6עסאץ%6 0 = 016 ם66%א0 הגודל של וט הוא עשרה בתים, לעומת שמונה בתיס של 400016, מאחר והוא מחזיק שדה נוסף המתאר את סוג השדה הפעיל בכל רגע באיחוד. הגודל של אובייקט מסוג 8 הוא שני בתים. אס היינו מחזיקיס את שלושת השדות בתווים, היינו מקבליס שלושה בתים. בדרך זו חוסכים בית אחד. ]3.13 | מצביעים לשדות ופונקציות במחלקה ב-++6 קיימת אפשרות להגדיר מצביעים לשדות או מצביעים לפונקציות מחלקה. בסעיף זה נלמד כיצד ניתן להגדיר מצביעים מסוג וה. בסעיף זה נשתמש, לצורך ההדגמה, במחלקה הבאה: ] 8ע6סת1סע 0185885 2 סמ :טס 2 סם1 6 ++6 ו-009 למתכנת המקצועי [) (סא)2א ,(סא)1א : (סא %ם5655)1ם1סק [;א = 1א + (א %6ם1)1א 566 ב1סעט ([ ;א = 2א + (א %6ם2)1א 566 ב1סעט [ ;81 תעטס6ע + 0086 ()1א 666 6ת1 .תס 0ם פעססת1סק 0% 007606 תה פסטקסטס מסונתט 6םת216+ בת // (ק6 %628ם01ת2 86ת6,00:גו60 602028602>>)05%208(8 (05%208 0₪מ1216 ; (01ת6 >> 2א.ק >> "6\" >> 1א.ק >> סטס) םע2600 + ] ;ו למחלקה יש שני שדות שלמים, הראשון בחלק הפרטי והשני בחלק הציבורי. למחלקה יש גס שתי פונקציות שמאפשרות לעדכן את ערכי השדות האלה. לשדה הפרטי [א, יש פונקציית שירות (1א 5%) המאפשרת לקבוע את ערכו. יש לו גם פונקציית שירות (1א 8%) המאפשרת לקבל את ערכו. האופרטור ''>>*י מוגדר למחלקה זו כחבר (11626) של המחלקה. הסיבה שאופרטור וה הוא חבר, ולא פונקציה במחלקה, היא שפונקציה במחלקה חייבת לקבל אובייקט של המחלקה כאופרנד שמאלי. והו אחד המקריס הבודדים שיש הצדקה לשימוש במנגנון החבר. מצביעים לשדות מצביע לשדה של מחלקה א כלשהי, שסוג השדה הוא 06ץ+, מוגדר באופן הבא : ;ק*::א ססץם מוסיפים את האופרטור רזולוציה (::) של המחלקה לפני סימן המצביע "*י. האופרטור '::' נקרא אופרטור רזולוציה (8)0זסקס מסםטט[650?), או אופרטור הבחנה, משוס שהוא מאפשר הבחנה בטווח של משתנה. למשל, הגדרת ק היא מצביע לשדה של מחלקה א, ולא של מצביע גלובלי. כאשר נבקש להגדיר מצביע לשדות השלמים של המחלקה הזו נעשה ואת כך: 8 ְ ְ פמססת1סס עסשסתספת 6ת80 צץ1סק8 // ;ק*::629סת1סק %6ם1 = כ השימוש במצביע לשדה של מחלקה חייב לבוא בצמוד לאובייקט. הסיבה לכך היא שאין משמעות למצביע כזה ללא אובייקט מתאים. לכן, במקרה הכללי של מחלקה כלשהי א נשתמש במצביע בצורה הבאה: פרק 3: המחלקה | 107 זו הסיבה שהפעלה של מצביע לשדה של אובייקט נעשית דרך אובייקט נתון. האובייקט יכול להיות אובייקט, או מצביע לאובייקט. במקרה השני (מצביע לאובייקט) ההתייחסות למצביע לשדה היא דרך המצביע לאובייקט. בדוגמה שלנו המצביע לשדה (ק) הוא מסוג שלס והשימוש בו הוא כזה: ;אסק* ,(0)א 8פע6סת1סק ;א >> " > א 0ע26 06 16ט0סם8 ם1610ם6611 81862 ם" >> 60006 7 = ס*.א ;א >> " = א 2א ₪0 2 ת89910 81862 ם" >> 0006 ;% = אס 2 = ס*<-אס ;א >> " > א 3 6ט1א8ט 2א סם מש85810 81665 ת" >> סגוסס מצביעים לפונקציות של אובייקטים ב-++6 יש אפשרות להגדיר מצביעיס לפונקציות של מחלקות. מצביעיס אלה דומים בהגדרתס למצביעים רגילים, פרט לכך שהםס משתמשים באובייקט שמסופק להם. באופן כללי עבור מחלקה א ופונקציה 1 נגדיר את המצביע באופן הבא : ; (8206-1180) (ע6ק סםתט1*::א) 6סץ66-6ע2 לכל מצביע לפונקציה יש לפרט את הערך שמחזירות פונקציות המוצבעות על ידו, ואת רשימת הפרמטריס שהוא מקבל. הפעלה של פונקציה כזו חייבת להיות דרך אובייקט. לדוגמה, כשיש מצביע כזה לאובייקט אק, הפעלת פונקציה כזו תיעשה כך: ; (8006-118%) (ע6ק סתט5*<-אס) אס נחזור לדוגמה הקודמת, של המחלקה 68מוסע, כאשר מוגדר מצביע לאובייקט, נגדיר מצביע לפונקציה של המחלקה. נאתחל את ערכו של המצביע לפונקציה כך שיצביע לפונקציה 1[א 5%, ואז נקרא לפונקציה דרך המצביע עס ארגומנט 1. קריאה זו תכניס את הערך 1 לשדה 1א. ; (%ם1) (ע6קסםט628::*1סת1סק) 1בסט 2 6628::890₪ת01ק = עס6קסתט1 ; (1) (62קסמםגות *<-אס) ;א >> " = א 1א ₪0 1 89910 81862 ם" >> 0006 לסיכוסם נושא מצביעיס לשדות של מחלקות, או לפונקציות של מחלקות, אני רוצה לציין שלשפת ++6 יש מנגנוניס רבי עוצמה אחרים. מנגנוניס אלה, שנכיר בהמשך הספר, עדיפים על מצביעים לשדות או פונקציות מחלקה. השימוש במצביעים אלה הופך את הקוד לבלתי קריא, והייתי ממליצ להימנע משימוש בהס, אלא במקריס מיוחדיס והם נדיריס ביותר. 8 ++6 ו-009 למתכנת המקצועי סיכום בפרק זה למדנו את מושג המחלקה ב-++6. המחלקה ב-++6 היא מודול שמסתיר את מבנה הנתוניס אשר עליו הוא פועל, ומספק פונקציות שירות שמודוליס אחרים יכוליס לקרוא. פונקציות אלו מספקות אלגוריתמים שוניס הפועלים על מבנה הנתוניסם של המחלקה. בפרק זה למדנו להבדיל בין מחלקה לאובייקט. מחלקה היא תבנית שמאפיינת את כל האובייקטיס במחלקה. אובייקט הוא מופע של מחלקה. משתניס הס אובייקטים. כתוצאה מהסתרת המידע, והשימוש בפונקציות שירות לקבלת שירותיס על מבנה הנתוניס, אפשר לשנות את מבנה הנתוניס באופן כזּה שחלקי התוכנה האחרים, המשתמשיס במחלקה זו, לא ישתנו. שינוי וה מאפשר ליצור תוכנה באיכות גבוהה החסינה לשינוייס וניתנת לשימוש במספר רב של מקומות ללא צורך בשכתובה. המחלקה ב-++6 יכולה להגדיר אופרטוריס בסיסיים שיפעלו על אובייקטיס של המחלקה. המחלקה יכולה, למשל, להגדיר אופרטורים כגון "+", "=", "==" וכוי. הגדרה כזו מאפשרת לכתוב מחלקות שהאובייקטים שלהן מתנהגים כמו משתניס בסיסייס של השפה, וכך להרחיב את השפה בסוגיס חדשים. ראינו שאפשר להגדיר שדות, או פונקציות סטטיות אשר משותפות לכל האובייקטיס במחלקה. שדות סטטים שימושיס למקריס בהס רוציס לשמור מידע המשותף לכל האובייקטיס במחלקה. פונקציות סטטיות אינן קשורות לאובייקט מסויס, אך יש להן גישה לחלק הפרטי של אובייקט נתון. לכל מחלקה יש אזורי גישה: ס6ו[טטק, 866שוז2, שקובעיס את הגישה לשדות, או לפונקציות של המחלקה מקטעיס אחרים של התוכנה. 6ו[טטק מסמן גישה ציבורית, (אילו 9)66וזק מסמן גישה פרטית המותרת רק לפונקציות של המחלקה, או לחבריס של המחלקה. אפשר להגדיר מחלקות מקוננות, אשר מוגדרות בתוך גוף הקוד של מחלקה אחרת. מחלקה מקוננת (מסנוסמג1 8מנז5סם) יכולה להיות מוגדרת בכל אחד מאזורי הגישה של המחלקה העוטפת. אזור הגישה קובע את הגישה למחלקה המקוננת. 08 שאלות ממש את האופרטורים ''>>'י, ''>=, ''=<יי במחלקה שחושף. 2 ממש את המחלקה 57188 בעזרת 41100ת, 166 ו-1681100. 3 ממש את המחלקה אַמו5₪ בעזרת האופרטורים אסם ו-46100. דאג שהקצאת זיכרון חדשה לא תתרחש בכל שינוי המחרוזת שהאובייקט מצביע עליה. רמו: הקצה זיכרון גדול למהדר ורק כשנגמר הזיכרון הקצה ויכרון אחר. 4. האס צריך לכתוב אופרטור מסוג (* 0241 +6018)=+6070078107 51058 !+ נמק! פרק 3: המחלקה | 109 110 מה קורה כאשר מעביריס מצביע שהוא .1.1(זא לבנאי של 8ַמםוז60: הגדר אופרטור העתקה למחלקה מספעסץ. כתוב מחלקה שמייצגת קוב במערכת, ומגבילה את מספר הקבצים הפתוחים של התוכנית למספר נתון, שאינו קבוע אלא ניתן לשינוי. כתוב מחלקה אשר מייצגת ספרייה (ץ81160001) במערכת ההפעלה, ומגבילה את מספר הקבציס בה למספר נתון. מה ההבדל בין מחלקה זו למחלקה מהשאלה הקודמת! ++6 ו-009 למתכנת המקצועי פרק 4 קלט ופלט בפרק וה נראה את אמצעי הקלט/פלט של ++6. אמצעים אלה אינס חלק מהשפה אבל הס בנוייס בתקן שלה. אפשר להשתמש בספרייה הסטנדרטית של 6 גם ב-++6 אבל הספרייה של ++6 עדיפה. ספריית הפלט/קלט מאפשרת להעמיס אופרטורים כגון *>> ן-"<<י לאובייקטים, כדי לשלוח את האובייקטים ישירות לפלט, או לקרוא אובייקט שלס מהקלט בדרך זו. בנוסף, ספרייה זו בטוחה יותר לשימוש. עובדה זו נובעת מהיכולת של ++6 להעמיס אופרטוריס לפי סוגי המשתניס. בפרק זה נראה מדוע ספרייה זו עדיפה. חסרונות הספרייה הסטנדרטית של 6 מדוע עלינו להשתמש בספרייה חדשה! האס הספרייה של 6, לה אנו רגיליס זמן רב, אינה טובה! בסעיף זה נענה על שאלות אלו, ונעמוד על היתרונות והחסרונות של ספריית הקלט/פלט הסטנדרטית של 6. כאשר רוציס לפתוח קוב בספרייה זו יש לבצע קריאה, למשל : ; ("מצחט" ,"2116")םסס0ס+ = 2+0* מתךק הפונקציה ת1006 פותחת את הקובץ 8186. הקוב נפתח לקריאה ולכתיבה, לפי הארגומנט השני. הפונקציה מחזירה ידית (6[0ם18) לקובצ הפתות. הפונקציות האחרות של הספרייה משתמשות בידית האחרונה כדי לבצע את הפעילויות שלהן. ספריית הקלט/פלט של 6 היא מודול המטפל בקריאה, או כתיבה לקבציסם. מודול זה דומה למודולים עליהס למדנו בפרק 2. נניח שיש לנו פונקציה שפותחת קוב כלשהו ומעבדת אותו: (6תהת* ע8ם0 6פםתסס)5 ב1סע - ; ("+צ" ,ס6תהת)ם6ק0ס1 = 0ס?+* מתזתץ // .. 60 806518 פרק 4: קלט ופלט | 111 לפונקציה הזו יש בעיה. המתכנת שכח לסגור את הקוב>. התוכנית תמשיך לרוץ, אבל לאחר הפעלה של הפונקציה 1 מספר פעמיס תפסיק התוכנית לתפקד, מכיון שהיא אינה סוגרת את הקבצים ואינה מחזירה משאבים למערכת. מסקנה: החיסרון הראשון של מודול וה הוא שיש לזכור לסגור קבציס (חיסרון דומה ראינו בפרק ?). נניח שמתכנת רוצה לכתוב ערך כלשהו לתוך הקוב. לשס כך הוא ישתמש בפונקציה ]ומוס באופן הבא : (1+116* ע8ת6 6פת00ס)5 ב1סטע זָ ; ("ט" ,5116)ם0ק0+ = 0ש+* מתךק ;א %ם1 ;(א ,"%5" ,65)10םת1צס+ ] הפונקציה 1)מוזט1 מקבלת, כארגומנט ראשון, ידית (1ַ0ַמ189) לקובצ שנפתח בעזרת מ6ק10. הארגומנט השני של הפונקציה הוא מחרוזת המתארת כיצד יש להתייחס לארגומנטיס המופיעיס בהמשך. במקרה זה המחרוזת מסמנת שיש להדפיס מחרוזת של תוויס. הבעיה כאן היא שהארגומנט שניתן לפונקציה הוא שלס, כך שאין אפשרות לדעת מה יודפס לקובצ. התנהגות התוכנית אינה צפויה. ההצהרה של הפונקציה תת היא כדלהלן: ;(... ,8%ת102* ע8ת0 58ת00 ,* שםת1ע)61ת1עס+ בנ1בסט חוסר התיאוס בין המחרוזת לבין הארגומנטיס הבאיס אחריה הוא המקור לבעיות. בעיות אלו אינן יכולות להתגלות ברמת הידור התוכנית, מכיון שהארגומנט השלישי והלאה של הפונקציה צמוט1 הוא יי...'י (הפונקציה מקבלת מספר לא מוגדר של ארגומנטיס), לכן המהדר אינו יכול לבדוק את תקינות הפרמטרים. אותן בעיות יכולות להיווצר כתוצאה מהפעלת הפונקציות 86821 הקוראות קלט מקובץ ועורכות אותו (פורמט). במקרה הטוב, תופסק התוכנית בנקודת הקריאה לפונקציה. במקרה הרע, נגלה את הבעיות מאוחר יותר. בעיה אחרת יכולה להיגרס אס מתכנת משתמש בידית לקוב לפני שהוא פתח את הקוב עצמו. אין דרך למנוע מהמתכנת לעשות פעולה כזו הגורמת לשגיאה בזמן ריצה. (...)5 ב1סט ו ;0+* תדע ; ("ס6ת1ע5%6 ת" ,">" ,ס65)5םתנ1מס+ ו התנהגות הפונקציה אינה מוגדרת. במקרה הטוב התוכנית תפסיק בנקודת הקריאה לפונקציה +)מוזנ1, במקרה הפחות טוב, התוכנית תמשיך עס תוצאות בלתי צפויות במקוס אחר ללא קשר למקום בו נעשתה השגיאה. נרצה דרך אלגנטית ופשוטה, בה יכול המהדר לגלות בעיות בומן ההידור ולהתריע עליהן (דבר שהיה חוסך זמן המבוזבז לגילוי ואיתור בעיות כאלו). 2 ++6 ו-009 למתכנת המקצועי קלט/פלט פשוט ב-++6 ב-++6 יש מספר מחלקות אשר תומכות בקלט ובפלט. הן תומכות בקלט, או בפלט, של כל סוגי הנתוניס התקניים בשפה. סוגי נתונים אחרים, כמו אובייקטיס שהמתכנת מגדיר, אינס נתמכים ישירות על ידי ספריית הקלט/פלט. אולם, מתכנת המגדיר אובייקטיס אלה יכול להגדיר להם אופרטוריס מתאימיס המאפשריסם לכתוב, או לקרוא, את האובייקטים כאילו היו אובייקטים תקניים של ++6. קלט/פלט בסיסי מתבצע על ידי האובייקטים הבסיסיים: '>>: ן-"<<יי. האופרטור 'י<<יי מוגדר עבור קלט, והאופרטור '>>יי מוגדר עבור פלט. אופרטוריס אלה עורכיס מחדש את הנתוניס (16101189), כלומר, לוקתחים מחרוות וממירים אותה למשתנה המתאים. העמסת אופרטורים יש מספר אופרטורים מסוג ">> ומסוג "<<יי, עבור כל אחד מסוגי הנתוניס הבסיסייסם של השפה. אפשרות זו נקראת העמסה (8תו611080ע0). המהדר בוחר את הגירסה המתאימה של האופרטור לפי סוג המשתנה. לדוגמה, נתונה מחלקה א ולה מספר אופרטורים י'>> אשר כתוביס במשפטים שוניס: 018858 8% ) / :טס 1 מסס // ; (צ %6ם600628602>6>6)1 א 2 עסס // ; (82ת0) >>600628%602 א 3 צסס // ; (* 82ת8600628602>6>6)0 א ;ו % 7 2 6ת1 ;%2פ* ,0 עהתס 7 >> 0 >> 1 >> א בקטע הקוד הזה יש שלושה אופרטורים. הראשון מקבל ערך שלם, השני מקבל תו והשלישי מקבל מצביע לתו. אפשר להפעיל את האופרטוריס בשרשרת, מכיון שכל אחד מהס מחזיר ייחוס (161016206) לאובייקט מסוג א. המהדר בוחר את האופרטור המתאים על פי סוג הארגומנט המועבר לאופרטור. עבור המשתנה :1 ייבחר האופרטור הראשון (1 זקס), עבור המשתנה 6 יופעל האופרטור השני (2 זקס) שפועל על תווים, ואילו עבור המצביע לתוויס יופעל האופרטור השלישי, שפועל על מצביעים לתוויס. פרק 4: קלט ופלט | 113 אובייקטים בסיסיים האובייקטיס הבאיס קיימיס בכל תוכנית המשתמשת בספריית הפלט/קלט הסטנדרטית של ++0: * | 61 | שייך למחלקה 150682 ונועד לקלוט נתוניס מהקלט הסטנדרטי. * 6006 שייך למחלקה 050082 ומאפשר פלט של נתוניס לפלט הסטנדרטי. * | 064 שייך למחלקה 051602 ומאפשר פלט של נתוניס לאמצעי דיווח השגיאות הסטנדרטי. * | 0108 שייך למחלקה 05681 ומאפשר לכתוב נתוניס לאמצעי הרישוס הסטנדרטי. אובייקטיס אלה קשורים, בדרך כלל, למסך או לחלון שממנו מופעלת התוכנית. כדי להשתמש בהם יש לכלול בתוכנית את הקובצ .₪ 64ע105. הדוגמה הבאה מדגימה שימוש פשוט באובייקטיס אלה. <ת.ת108%268> 61066ת1+ ()מ1נהת %ם1 ו ;0 מַת0 ":צְ6א צֶם8 ע6סת6 6110מת" >> סגטסס ל יר ;"ת" >> 0 >> ":18 ם1 66סעץ5 טסץ צֶ%8 6םמך7" >> סטסס 2 תעט66ץ ו התוכנית מדפיסה לפלט את המחרוזת : '':ץ6א עת8 07+ת6 116110'י. לאחר ההדפסה לפלט ממתינה התוכנית לקלט כלשהו מהקלט הסטנדרטלי (טקת1 06816ת548). הקלט מוכנס למשתנה 6. לבסוף, מדפיסה התוכנית את הקלט לפלט ומסיימת. אפשר לראות איך בפעולה אחת ניתן לשלוח לפלט אחד מספר משתנים. באופן דומה ניתן לקרוא מספר משתניס בפקודה אחת. למשל: ] %ףתנ1נסק 06גע562 ;ץ,א %ם1 ו ()מ1נהת %ם1 ;+תס >תנ1נסס ":ץ 6םת8 א עס6סתסת" >> 0006 ;ץ.>םס << א.%םס << מנס 7 תעגו66ע 4 ++6 ו-009 למתכנת המקצועי תוכנית זו קולטת שני ערכים שלמיס מהמשתמש ומכניסה אותם למשתנים א ו-ץ של הרשומה )מק. על המשתמש להכניס רווח בין שני הערכים (כדי שהתוכנית תקבל שני ערכים). אס המשתמש אינו מכניס רווח בין שני המספריס תוהה הספרייה מספר אחד בלבד ותמתין למספר נוסף. אס המשתמש מכניס ערך שאינו שלם, יעבור האובייקט חוּס למצב לא תקין. כדי לנקות מצב לא תקין וּה, צריך המתכנת לקרוא לפונקציה 616808 שתנקה את הדגליס המסמנים את מצב האובייקט. קריאה מקבצים עד עתה ראינו קריאה וכתיבה (קלט/פלט) לאמצעיס הסטנדרטייס של התוכנית. אפשר גס לקרוא ולכתוב מקבצים. בסעיף וה נלמד כיצד קוראים מקבציס. המחלקה שמבצעת קריאה מקבצים היא ₪ 160908 וכדי להשתמש בה, יש לכלול את הקובצ 61.1 בקובצ המתאיס. קריאה עם עריכה קריאה עס עריכה (על פי פורמט) היא קריאה של מחרוזת תווי 45011 והמרתה לסוג המשתנה המבוקש. למשל, אס אנו מנסיס לקרוא שלם, תתבצע המרה אוטומטית של המחרוזת לשלסם. המחלקה שמטפלת בקריאה מקבציס היא ₪ 180083. הבנאי של המחלקה יכול לקבל את שס הקוב שאליו יהיה קשור האובייקט ועליו יתבצעו פעולות הפלט. פעולת פתיחת קוב יכולה להתרחש גס תוך שימוש בפונקציה סקס המקבלת את שם הקוב ופותחת אותו. לאחר פתיחת הקוב אפשר לבדוק, בכל רגע, שהאובייקט נמצא במצב תקין (למשל, שקוב כוּה באמת קיים) על ידי קריאה לפונקציה 8006 שמחזירה ערך השונה מאפס אס הקוב נמצא תקין, וערך אפס אם לא. לחילופין, אפשר לבדוק את האובייקט בביטוי לוגי שיציג ערך אמת (₪06) אס האובייקט תקין, ואחרת - ערך שקר (88186). דבר זה ניתן לביצוע, כי המחלקה מממשת אופרטור המרה של אובייקט המחלקה אל מצביע השונה מאפס כאשר האובייקט במצב תקין, ואחרת לאפס. הפונקציה הבאה, 16867116, מקבלת שס קובצ לקריאה וקוראת אותו. היא מגדירה אובייקט 116 ששייך למחלקה 181092 ומקבל את שס הקוב. לאחר מכן, מוכנסת המחרוזת הראשונה מהקובצ לתוך מערך התוויס +טט. בתוך לולאת 16 נערכת בדיקה אס הקוב תקין. הבדיקה המתבצעת היא, האס הוא פתוח ועדיין לא הגענו לסופו (ע50). כל עוד הקובצ נמצא במצב תקין נקראות ממנו מחרוזות ונכתבות לפלט הסטנדרטי. פרק 4: קלט ופלט | 115 בסופו של דבר מחוירה הפונקציה את מספר המילים שנקראו מהקוב. אובייקט מסוג 117081 סוגר את הקובץ שאליו הוא קשור בפונקציית הפירוק שלו. מכיון שפונקציית הפירוק של האובייקט נקראת באופן אוטומטי כאשר יוצאים מהפונקציה, היא גם תסגור את הקוב באופן אוטומטי. לכן, אין צורך לסגור את הקובץ באופן ידני בסיוס הפונקציה. כוכור, במקרה של מודולים מצב זה אינו נכון. אס לא היינו סוגריס את הקוב היינו מבובזיס את משאבי המערכת, ובשלב מאוחר יותר היתה המערכת מפסיקה לתפקד. למרות האמור, אפשר להשתמש בפונקציה 01056 כדי לסגור את הקוב באופן מפורש. פונקציה זו קיימת גם עבור אובייקטי קלט וגם עבור אובייקטי פלט. הפונקציה אינה מקבלת ארגומנטים, או מחזירה ערך. (6ת116%8+* %ע8ם0 8%6ת26809116)00 6ם1 / 2 = 55126טס סת1 6פםתסס 2 = סתטסס 6ם1 ;[5126+טמ]+טס ש8םס ; (6ת8א116+)5116+ (ת115%208 ; 0[1ת6 >> סגטסס ;טס << 1116 ]+ (1116) 16נגתט ;טס >> 0006 ;טס << 1116 ; ++6תגוסס ו ;%תטסס מעו66ע ו אם היינו יודעים את מבנה הקוב>, למשל שני שלמיס ולאחריהס מחרוזת, היינו יכוליס לקרוא זאת כך: 2 ,11 סם1 ;[1]64טס עַַאם0 2ט << 12 << 11 << 1116 העריכה היתה מתבצעת באופן אוטומטי על ידי האובייקט הקורא (486). בשתי ההפעלות הראשונות של האופרטור '<<'י היתה מתבצעת עריכה לשלמיס והערכיס המתאימים היו מוכנסיס למשתנים 11 ו-12, והקריאה השלישית היתה מכניסה ערכיס מתאימיס למחרוזת. קריאה ללא עריכה קריאה ללא עריכה קתו 46006מהחס1מט) מיועדת לקריאת קבציס במבנה בינארי. קבציס כאלה נחשבים, על ידי האובייקט הקורא כזרס של בתים. האובייקט הקורא (אובייקט הקלט) אינו מבצע כל המרה על בתיס אלה. קריאות של קבצים בינאריס 6 ++0 ו-009 למתכנת המקצועי מתבצעות על ידי הפונקציה 1646 של המחלקה 16708(2. הפונקציה מקבלת כארגומנט ראשון את החוצצ שלתוכו יש לקרוא את ורס הבתים. הארגומנט השני שמועבר לפונקציה הוא מספר הבתים שיש לקרוא. הפונקציה מחזירה ייחוס לאובייקט הנוכחי, וכך אפשר לבדוק את תקינות הקריאה, או לבצע קריאה בשרשרת. הפונקציה הבאה מבצעת קריאה בינארית של קובצ, ומניחה שבקוב> מצויים מבניס מסוג +תוסק. אס בקובצ יהיו מבניס מסוג אחר, תהיינה תוצאות הקריאה בלתי צפויות. הפונקציה מגדירה אובייקט מסוג ב150690 שמשמש לקריאת הקובצ. האובייקט מקבל את שס הקוב כפרמטר ראשון; הפרמטר השני מסמן שהקובצ הוא בינארי. דבר זה ייחודי למערכת ההפעלה 205 שמבדילה בין קבציס בינארייס לאחריס. פרמטר זה אינו קייס בתקן הספרייה, ובוודאי שאינו נמצא בספריות שבמערכת ההפעלה אזאנ). לאחר מכן, הפונקציה קוראת בלולאה מבנה נוסף מהקובץ ומדפיסה את המבנה לפלט הסטנדרטי. בתוך הלולאה מוגדל מונה המציין את מספר הרשומות שנקראו מהקובצ. בסוף הקריאה מוחזר ערך המונה. (6ת8א1+116* 02829 8%ת116)00תםת26₪8021 %6ם1 ָ ;תס סתנ1סס ; (לצ8ת1ס::105 ,6ת8א1116)1116 ת155%6268 72 = סתטסס %6ם1 (1) // ;01 >> "116תעת8621ס2ת" >> ס6טסס 1 (((5םק)512601 ,6םתס6 (*1116.26886))0282 66 5116) 16ג1גתט א.%תק >> " = א.6םת1סק" >> סטסס ;01ת6 >> ץ.סםמק >> "=ץ.6םת1סק, " >> ; ++%תטסס ] ;%תטסס מע6%0ע2 ו השורה בקוד ה המסומנת ב-(1) מדפיסה את שס הפונקציה ואחריו 61מ6. הדבר מסמן לאובייקט סט להתחיל בשורה חדשה. בנוסף, הוא מוודא שכל מה שנמצא בחוצציס הפנימייס של האובייקט וסט ושל המערכת ברגע זּה, יישלח לתצוגה על המסך. תו וה נקרא מטַפָלָל (09ו9]גוקותגות - נחזור לדון בו בהמשך פרק זה). כתיבה לקבצים גם בכתיבה לקבצים יש שתי אפשרויות: כתיבה עם עריכה (טווזאו 4006מוזס)) וכתיבה בינארית (סוח עְזגחוט). בכתיבה עם ערויכה מומרים הערכים של הפרמטרים למחרוזת 48011. כדי שעין אנוש תוכל לקרוא את הקוב> לאחר מכן. בכתיבה בינארית לקבציס לא מתבצעות המרות והמשתניס השונים נכתבים כוזרס של בתים, ולמעשה - סיביות. המחלקה שמאפשרת כתיבה לקבציס היא 8ג05069. כדי להשתמש במחלקה זו יש לכלול את הקוב .1906011 בקבציס המתאימיס שמשתמשים באובייקטי פלט. פרק 4: קלט ופלט | 117 כתיבה עם עריכה בכתיבה עס עריכה מומר הערך המבוקש למחרוות קודס לפעולת הכתיבה ורק אז נשלחת המחרוות לקובצ. כדי להשיג מטרה זו מנצלת הספרייה את תכונת ההעמסה (9ת0/610801) של ++6. במקרה זה נעשית ההעמסה של האופרטור '<<יי (אופרטור הפלט). ההעמסה של האופרטור נעשית באופן דומה לאופרטור הקודס. כל אופרטור כוה מחזיר ייחוס לאובייקט הנוכתי (שעליו פועל האופרטור), כדי לאפשר הפעלת האופרטור בשרשרת. הפונקציה הבאה, 169116, שולחת מחרוזות לקובץ נתון. היא מקבלת כפרמטר את שס הקוב שאליו יש לכתוב את המחרוזות, מגדירה אובייקט מסוג 0150092 ומעבירה אליו את שם הקוב לכתיבה. פעולה זו פותחת את הקוב לכתיבה. אפשר להשיג את אותו האפקט על ידי קריאה לפונקציה מ6ק0 של אובייקט זה. לאחר מכן, הפונקציה קוראת מחרוזת מהקלט הסטנדרטי, כל עוד המחרוזת שונה מ-606. דבר זה מתבצע בלולאת 6ומש. בגוף הלולאה נשלחת המחרוזת לקוב הפלט ונקראת מחרוזת נוספת. תוך כדי כך גס מוגדל מספר המחרוזות שנכתבו לקוב. לבסוף מוחזר מונה מספר המחרוזות (מטסס). (6ת116%8+* ע8ת0 86ת1667116)00עש 6ם1 2 = 055126 6ם1 00856 ;[0+5126מ]+טס 08% 72 = סתגסס 6ם1 ; (6ת8א1116) 1118 ת0185%208 ;טס << םמ01 1 ((5גס ,"סם6")קתסע56) 116תט ;טס >> 1116 ;טס << םמ01 ; ++6תגוסס ו ;%תטסס מעט6%ע2 ו הפונקציה יכולה לכתוב כל משתנה בסיסי לקובץ הקלט תוך שימוש באופרטור '>>'י. האופרטור מועמס גם הוא עבור כל המשתניס הבסיסיים. כתיבה בינארית לקבצים בכתיבה בינארית לקבציס לא מתרחשת המרה של ורס הבתים. החוצציס המועבריס לפונקציית הכתיבה נכתביםס ישירות לקבציס כמו שהם. הפונקציה שמשמשת לכתיבה בינארית היא 166, המקבלת את כתובת ההתחלה של החוצ> אותו יש לכתוב לקוב. בנוסף, הפונקציה מקבלת את גודל החוצצ, או את מספר הבתים שיש לכתוב לקובצ. 8 ++6 ו-009 למתכנת המקצועי הפונקציה מחזירה ייחוס לאובייקט שעליו היא פועלת, כדי לאפשר שרשור של קריאות לפונקציה זו. הפונקציה 16215"16זאי כותבת שלוש רשומות מסוג !ומוס לקובצ נתון. הפונקציה מקבלת את שס הקוב כפרמטר. היא מגדירה אובייקט מסוג 080682 ומעבירה לו את שס הקוב>. כמו במקרה של קריאה בינארית, מעבירה הפונקציה מוד בינארי (60סגת עזאתוס) לבנאי של האובייקט 816. דבר וה אינו חלק מהסטנדרט והוא בר-יישוס רק במקרה הפרטי של מערכת ההפעלה 05, שמבדילה בין קבציס בפורמט 1 לבין קבצים בפורמט בינארי. במערכות הפעלה אחרות אין צורך להבדיל בין סוגי קבצים. הפונקציה כותבת שלוש רשומות לקובץ, כשהשדות א ו-ץ של כל רשומות מקבלים את הערך הנוכחי של המשתנה 1 ובמקרה זה, את הערכים 0, 1 ו-2. לבסוף, מחזירה הפונקציה את מספר הרשומות שנכתבו לקוב (וםס). (6ת8א116+* עא8םת0 8%ם116)00עת16621עח %6ם1 / 2 = 06% 6ם1 0056 ;+תס סתנ1סס ; (צע8ת1ס::105 ,6ת%8א1116)5116 ת018%208 ] (++1 ;%ת1>0 ;1=0 %ם1) 05ס+ ;1 = ץ.סתס = א.>םק ;((סםמק)512601 ,%םס6 (*2ע8ב166))0עח.1116 ו ;%מס מעגו6ססע שילוב קלט ופלט לעיתים עלינו גס לקרוא וגס לכתוב לקבצים. אפשר להגדיר אובייקט שמבצע את הקריאה ואובייקט שמבצע את הכתיבה. אך ניתן גם להגדיר אובייקט בעל יכולת כפולה, שיבצע הן קריאה והן כתיבה. בסעיף ה נראה את שתי האפשרויות האלו. שילוב בין אובייקטי קלט לפלט כאשר יש פעולות קריאה מקוב אחד ופעולות כתיבה לקוב> שני, אפשר לבצע זאת על ידי אובייקטיס נפרדיס. אובייקט אחד אחראי לקריאה מהקובץ האחד, והאובייקט השני אחראי לכתיבה לקוב השני. הפונקציה 116תץ0סס מעתיקה קוב מקור לקובצ יעד. הפונקציה מקבלת, כפרמטר ראשון, את שס קובצ המקור וכפרמטר שני את שס קוב היעד. הפונקציה מגדירה משתנה מסוג שלסם (מו), שישמש לקריאת התוויס בקובצ המקור. הסיבה להגדרת משתנה מסוג שלס כשצריך לקרוא תו תתברר בהמשך. פרק 4: קלט ופלט | 119 הפונקציה מגדירה שני אובייקטים : * טס - אובייקט מסוג 0818ז080, המשמש לכתיבה לקבצים. * מו - אובייקט מסוג ו זג110, המשמש לקריאה מקבצים. בהמשך, הפונקציה קוראת בלולאה לפונקציות של אובייקטי הקלט והפלט שמבצעות קריאה וכתיבה של תו אחד בלבד. הפונקציה ‏ 86 קוראת תו אחד מהאובייקט גנ, ומחזירה את ערכו כשלם. הפונקציה מחזירה את הערך ?0 כאשר מגיעיס לסוף הקוב. הערך ₪0 מוגדר כמינוס אחד, לכן אי אפשר להגדיר את המשתנה 6 כתו חסר סימן, לפיכך 6 מוגדר כשלם. כל עוד נקרא תו השונה מסוף קובצ (?50) קוראת הפונקציה לפונקציה )וק של האובייקט זטס, השולחת תו אחד לאובייקט )זס. (0סע8* 082% 86ת00 ,68%* 0282 116)0028%6עצ000 בנסט 7 ד ; (6)08ט0ס 0156268 ; (820)ם1 ת155%208 (01 =! (()86%.ם1 = 60)) 116תט ; ((82)0ם0)סגק. סוס ו בכל שלב של הלולאה נקרא תו אחד מקוב הקלט ונכתב תו אחד לקובצ הפלט. הדבר גורר קריאה לפונקציה כדי לקרוא כל תו בקלט, ועוד קריאה לפונקציה כדי לכתוב את התו. אפשר היה לשפר מצב זה על ידי קריאה לפונקציה 1696. במקרה זה הינו קוראיס מספר גדול יותר של תוויס, 1024 למשל. ומדוע שלא נשתמש בפונקציה 12686 מכיון שהיא אינה מחזירה את מספר הבתים שאכן נקראו. כדי לקבל את המספר האמיתי של בתים שנקראו, ניתן להשתמש בפונקציה +טסס8, המחזירה את מספר הבתיסם שנקראו בפעולת הקריאה האחרונה. אני משאיר לקורא בעיה וו כתרגיל. שימוש באובייקטי קריאה וכתיבה לעיתים, צריך לקרוא ולכתוב לאותו קובץ, כמו בעבודה בדיסקים מגנטיים. בספריית הקלט/פלט הסטנדרטי יש אובייקטים שיכוליס לקרוא ולכתוב בעת ובעונה אחת לאותו קוב. אובייקטים מסוג ₪693 מאפשרים קריאה, או כתיבה של אותו קובצ בו-ומנית. כדי להשתמש באובייקטיס אלה יש לכלול את הקוב 15009.2 בתוכנית. קביעת מיקום מצביע הקריאה או הכתיבה לאובייקטיס פלט/קלט כלשהם יש אפשרות לקבוע את המיקוס בקוב שממנו תתבצע פעולת הקריאה, או הכתיבה הבאים. הדבר נכון לכל האובייקטיס הקשורים לקבצים, ובפרט לאלה המסוגליס רק לקרוא, רק לכתוב או לקרוא ולכתוב. 0 ++6 ו-009 למתכנת המקצועי כדי לקבוע את מיקוס פעולת הקריאה הבאה, יש להשתמש בפונקציה 509%8, כאשר 5 מסמל את המילה 866. כדי לקבל את המיקוס של פעולת הקריאה הבאה יש להשתמש בפונקציה %1!8 שמחזירה מספר מסוג שלם מורחב (8םס). כדי לקבוע את מיקוס פעולת הכתיבה הבאה יש להשתמש בפונקציה 860%0, שקובעת את מיקוס מצביע הכתיבה בקוב. הפונקציה 1611 מחוירה את ההיסט של מצביע הכתיבה מתחילת הקובצ. גם פונקציה זו מחזירה ערך של שלם מורחב. הפונקציה 15ם61828600706170101 מקבלת שס של קובצ שבו יש שלוש רשומות מסוג וס ומחליפה את הסדר בין הרשומות. הרשומה הראשונה תעבור להיות הרשומה האחרונה, והרשומה האחרונה תהיה הראשונה. (סתהת* 0282 8%6ת%65)00ם060206201201ת8ת6 נ1בסט ו ; (צעא8ת1ס::105 ,סתַה8םת)5116 ת185%208 ; (105::00% | ם1089::1 | צעאתנ1ס::105 ,פתהם) ם6קס.1116 (1116!) +1 12 >> "1116 6ם5 ת6קס ₪0 181166ם" >> 0006 27 ,01 סתנסק ; (2 * (1116.566%0)512601)01 ;((1ק)512601 ,82*('601ם1116.2686))0 ; (0) 1116.866%0 ;((2ק)5812605 ,802 (*2ע28ת1116.2688))0 ; (2* (02) 512601) ק566%. 1116 ;((2ק)512601 ,82*('802ם166))0ע2ח.1116 ; (0) ק1116.566% ; ((01ק)812605 ,601 (*2ע166))028עח.1116 ," >> א.1ק >> "=א.1ק" >> "ת6שסתה8תסת" >> סטסס ," >> א.2ק >> "=א.2קם" >>7ץ.1ק >> "=ץ.1ס 2 >> ץ.02 >> "=ץ.2ס ] הפונקציה מקבלת את שם הקוב עליו היא פועלת. הפונקציה מגדירה אובייקט מסוג 691 שמשמש לקריאה ולכתיבה של הקוב הנתון. היא מעבירה לבנאי של האובייקט את שס הקוב שעליו יש לבצע את פעולות הקריאה והכתיבה. לאחר מכן, היא משתמשת בפונקציה מסטס, שלה מועבר שס הקובצ ואופן (מוד, 8066) הפעולה על הקוב. הקובצ נפתח במוד בינארי (ייחודי למערכת ההפעלה 05 ואינו כלול בסטנדרט של ספרייה זו) לקריאה ולכתיבה. כדי להשיג את הפונקציונליות הדרושה נבצע זס על הסיביות המתאימות, ונעביר אותן לפונקציה סקס כפרמטר שני. לאחר מכן, נבדק האובייקט 816 כדי לדעת אס הצליחה פעולת הפתיחה. אם לא - מודפסת הודעת שגיאה לפלט הסטנדרטי. הפונקציה מגדירה שתי רשומות מסוג )םוסק המשמשות להחלפת הרשומות בקובצ המתאים. פרק 4: קלט ופלט | 121 הפונקציה מבצעת הזזה של מצביע הקריאה בקובצ לתחילת הרשומה השלישית, ולאחר מכן היא קוראת את הרשומה הראשונה. בהמשך, מזיזה הפונקציה את מצביע הקריאה לתחילת הקוב וקוראת את הרשומה השנייה. בשלב הכתיבה מזיזה הפונקציה את מצביע הקריאה לרשומה השלישית וכותבת את הרשומה השנייה. מייד לאחר מכן, שוב מוזז מצביע הכתיבה והפעס לתחילת הקובצ. כעת נרשמת הרשומה הראשונה שנקראה. התוצאה של פעולה זו היא החלפת הערכים של הרשומה הראשונה והשלישית בקובצ. עריכת נתונים בזיכרון אפשר לערוך נתוניסם בוּיכרון. אפשרות וו דומה למשפחת הפונקציות הקיימות ב-86610.1 : +מ808. לצורך עריכת נתוניס בוּיכרון מוגדרות שלוש מחלקות : > 15%%04 - מאפשרת קלט נתוניס ערוכים ממחרוזות. > 051570821 - מאפשרת פלט נתוניס בצורה ערוכה אל חוצ בזיכרון. > 1ת68ע5)7%0 - מאפשרת פלט וקלט של נתוניס ערוכיס. כדי להשתמש במחלקות אלו עליך לכלול בתוכנית את הקוב ג.807807000. הפונקציה וטטט0טק5)118 מדגימה את השימוש בשתי המחלקות הראשונות. תחילה היא מגדירה אובייקט מסוג 08018008 ומבקשת מהמשתמש להקליד שני שלמים ומחרוזת. ערכיס אלה נקראיס לתוך המשתנים 1א, 2א ו-1טפ, בהתאמה. לבסוף, מוכנס התו 6068 המסמן את סוף המחרוזת. הפונקציה מגדירה אובייקט מסוג (ת 18080069 שמקבל את אזור הזיכרון שנצבר במהלך הפעולות הקודמות על ידי האובייקט 5₪. הבנאי של 86 מקבל גס את גודל אזור הזיכרון. לאחר מכן, הערכיס שנכתבו קודס לכן מחולציס אל המשתנים א, ץ ו- 1וטט שבזיכרון. לבסוף, משחררת הפונקציה את אזור הזיכרון שהוקצה על ידי האובייקט 07 הפונקציה 846 של המחלקה 050800822 מחצירה מצביע לאזור הויכרון הפנימי שלתוכו נכתביס המשתניס בצורה ערוכה. אס משתמשים בפונקציה זו, האובייקט פס אינו משחרר את אזור הזיכרון שהוא הקצה, לכן האחריות לשחרור עוברת לפונקציה שקראה לפונקציה צו. () 0600%00%וקת5%521 1סט ו 7 (08ע05%285%2 ;ץצ ,א ,2א ,1 שם1 ;[1]32+טס ,[32]+טס צ8ם0 ; ":60םת1ע56 8 0ם8 פסת1 סשטם ע66%ם6" >> סגסס לצוס << .2 << 1אי<. הנס 82 >> %טס >> " " >> 2א >>" " >> 1א >> ע0856ס 12 >> ()089%2.802 >> סטסס 2 ++6 ו-009 למתכנת המקצועי ;(1 + (()ע89%2.ע05%2)ם16ע89%2 ,()8%2.ע15%2)09%2 ת(ת18%28%208 2ט << ץ << א << 18965 2 >> "=1טס ," >> ץ >> "=ץ ," >> א >> "=את" >> סגוסס ק()0502.852ס [] 061666 ] אפשר להעביר לבנאי של :0508009 מצביע לאזור זיכרון ואת גודל אזור הזיכרון הנתון, אך או האובייקט לא יקצה ויכרון בעת הצורך, אלא ישתמש אך ורק בחוצצ הנתון לו. במקרה כזה אין צורך לשחרר את החוצצ. כמו לאובייקטי הקלט/פלט הקודמים, אפשר לשנות את מיקוס הקריאה, או הכתיבה הבא תוך שימוש בפונקציות 80088 ו-ק800%. אפשר גס לקבל את המצביע הנוכחי של הקריאה, או הכתיבה, בעזרת הפונקציות 16110 ו-1118, בהתאמה. האובייקט 509681 משמש לעריכת נתוניס המוזניםס לזיכרון או שיוצאים ממנו. כלומר, קריאה או כתיבה לויכרון בו-וּמנית. אובייקט וה דומה לאובייקט המקביל, הפועל על קבצים, 01ג1806. שילוב פונקציות פלט/קלט הפונקציה מוגו משתמשת בכל הפונקציות שראינו עד עתה. היא מקבלת שסם קוב ומייצרת קוב פלט ששמו 5009188.006. אס לא נמסור לתוכנית שס קובץ, היא תשתמש בקוב> ו100.08. בקוב וה הרשומות יהיו בסדר הפוך! ([]טףע8* ע8םת0 ,8260 6סם1)תג1את 6ם1 ָ ;[1]טףע8 = 6ת8א11106* ע8ם0 6פ5תסס ; "פגוס. 8ת5%208" = 116ע6טס* ע8ם0 ס6פתסס ] (2 =! 8260) 11 12 >> "סתַהַם-1116 " >> [0]עט0ע82 >> " :8806ט" >> שעסס ;01ת6 >> "500.086 1116 6ם1פט" >> שעסס ; "100.08%" = 6ת8א1116 ; (6ת11688+) 66118 בעשט ; (6ת8א5116) 18 20680691 ; (6ת8א1168+) 116עת01 6 נעשט ; (6ת511688) 18 נעם 2680951 ; (6ת8א5116 ,116ע116)00%6עצקס0 ; (116ע6ט0) %65ת08286020620+201 ; (116ע6ט0) 116עם 268651 ; () 6006:ו1160קת5621 2 6%02ע פרק 4: קלט ופלט | 123 מניפולטורים מניפולטוריס (מטַפְּלָלִים - 18910%וק1ת4]א) הס פונקציות הפועלות על אובייקט מסוים ומשנות את מצבו, או קוראות לפונקציה של האובייקט ומחזירות ייחוס לאובייקט הנתון. הדבר מאפשר להפעיל את המניפולטוריס ברצף הפקודות, ללא צורך בפתיחת משפט חדש. ראינו מספר מניפולטוריס בפרק זה: 62061 ו-6265. הראשון מכניס תו בקרה 'סוף שורה' לאובייקטיס שמבצעיס פלט לקבצים, והשני מכניס תו בקרה 'סוף מחרוזת' לאובייקטיס מסוג 05118004(1. תמיכה במניפולטורים במחלקה נתונה עבור מחלקה כלשהי א, המניפולטור (מַטַפְלֶל) של המחלקה היא פונקציה + הנכתבת כך: ; (%8)+61 % כדי שמחלקה א כלשהי תאפשר קריאה למניפולטורים כאלה, יש להגדירה כך: 01858 % ) 6 :טס ב ; () 301% ב1סט [1. + (ט 6ם1)>>ע600628602 < ((68א)(6)*1 %)>>600028602 %< [ ;((15ם>ף*)+) מעט66ע ) ;ן אס למחלקה יש אופרטורים מסוג ">>" נגדיר אופרטור נוסף מסוג זה. הוא יקבל מצביע לפונקציה שמחזירה ייחוס אל האובייקט שעליו היא פועלת. האופרטור יפעיל את הפונקציה ויחזיר את האובייקט שמחצירה הפונקציה. כעת אפשר להגדיר מניפולטור כלשהו, או פונקציה: (88 %)61 < ן ; ()0016.א ;א מע6%02ע2 השימוש בפונקציה נעשה באופן הבא: ;א א ; ,1ט סם1 7 2 >> 5 >> [ט >> א 4 ++6 ו-009 למתכנת המקצועי כאשר המהדר רואה את התו 1 הוא 'מבין' שלפניו שם פונקציה. כלומר, כתובת הפונקציה נתונה לו. לפיכך, מופעל האופרטור שמקבל מצביע לפונקציה כזו. הואיל והאופרטור מחציר ייחוס לאובייקט מסוג א, אפשר להפעילו בשרשרת כזו. האופרטור מפעיל את הפונקציה שמועברת לו ומחזיר את התוצאה שלה. מניפולטורים במערכת קלט/פלט במערכת קלט/פלט יש מספר מניפולטורים (מטַפְלְלִים) הפועלים על אובייקטים שונים. למשל, יש מניפולטורים הפועלים על אובייקטי פלט כמו: 080068 או ם8008. מניפולטוריס אחריס פועליס על אובייקטי פלט, או קלט. לדוגמה: * 060 - ממיר את האובייקט למבנה אוקטלי (על בסיס 8). פועל על פלט וקלט. *= 606 - ממיר את האובייקט למבנה עשרוני (על בסיס 10). פועל על פלט וקלט. *= אסג - ממיר את האובייקט למבנה (על בסיס 16). פועל על פלט וקלט. > 01ם6 - שולח תו של שורה חדשה לאובייקט וכותב את החוצץ הפנימי שלו. פועל על אובייקטי פלט בלבד. *= 60% - שולח תו '0י המסמן את סוף המחרוזת. מניפולטור זה פועל על פלט בויכרון 05115010822. * 1081 - כותב את החוצ הפנימי של האובייקט למערכת הקבצים. כאשר משתמשים באובייקטי הפלט של הספרייה הסטנדרטית, נרשמיס הנתוניס לחוצא פנימי של האובייקט תחילה. רק כאשר החוצצ הפנימי מלא, מבוצעת הכתיבה למערכת הקבציס. כדי לכתוב את החתוצץ לפני שהוא מתמלא, אפשר להשתמש בפעולות כמו אלו: ; ("6)"1116.00%טס 018627088 ;תפט11 >> 3 >> 5 >> סטס 12 ָ >> 4 >> " ,">> 5 >> סטס בפעולת הפלט הראשונה נכתבים המספרים 3 ו-5. לאחר מכן, נכתב החוצ הפנימי לקוב>. בפעולת הפלט השנייה נכתביס המספרים 4 ו-5, לאחריהם מוכנס התו המציין שורה חדשה ומייד לאחר מכן נכתב החוצ הפנימי לקובצ. אפשר לשנות הבסיס של המספרים בדרך זו: 2 >> " " >> 008 >> 12 >> " " >> אפם >> 12 >> סטס0 עבור שורה כזו נקבל את הפלט הבא : 2 78 122 ראינו, שלאחר הפעלת מניפולטור מסויס תבוצע המרה על פי בסיס המספרים של אובייקט הפלט, או הקלט. פרק 4: קלט ופלט | 125 סיכום בפרק זה למדנו על ספריית הקלט/פלט הסטנדרטית של ++6. ספרייה זו אינה חלק מהשפה אבל מסופקת יחד עס המהדר. לספרייה הסטנדרטית הוגדר ממשק 1פאוג, לכן כדאי להשתמש בה ולמנוע קשיי התמרה של תוכניות מפלטפורמה לפלטפורמה. ספרייה זו בטוחה יותר מהספרייה הדומה לה ב-6. כאן אין פונקציות בעלות מספר וסוג לא ידוע של פרמטרים. המהדר יכול לגלות שגיאות מסוג וה כבר בומן ההידור ולא רק בומן הריצה. לספריית הקלט/פלט (או זרמי קלט/פלט, ב1050109) יש אובייקטיס הכותביס לקבצים, ויש גם אובייקטיס המאפשריס לקרוא מקבצים, ויש אובייקטיס שמאפשריס קריאה וכתיבה בו-זמנית. בנוסף, יש אובייקטיס ((05080068) המאפשרים להמיר נתוניס לתוך חוצציס בזיכרון. אובייקט אחר, ות1808008, מאפשר לקרוא מתוך חוצצ בציכרון. אובייקט מסוג 5080090 מאפשר להמיר נתונים בעת קריאה, או כתיבה. ראינו שיש מניפולטוריס הפועליס על אובייקטיס כאלה ומאפשרים, בצורה נוחה, לשנות מצב של ורס (קלט או פלט). מניפולטוריס כאלה מאפשריס למשל לשלוח את הנתוניס אשר נאגרו בתחוצצים הפנימיים של האובייקטיס לקבצים. תודות ליכולת של ++6 להעמסה של פונקציות והתזרת ייחוס (00מ101070) של אובייקטיס מפונקציה, ראינו שאפשר לבצע מספר פעולות פלט או קלט במשפט אחד של השפה. 8 | 4.10 | שאלות ממש פונקציה המעתיקה קובצ מקור לקובצ יעד תוך שימוש בפונקציות 1080 ו-1מגו860. 2 כתוב תוכנית המדפיסה את מספר המילים, התוויס והשורות שנמצאות בקוב מסויס. 3 כתוב תוכנית המוצאת מילה מסוימת בקוב נתון ומדפיסה את מספר המופעים של המילה בקובצ זה. 4 כתוב תוכנית הקוראת קוב מסויס ומצמצמת את כל הרווחים בו. 5 כתוב תוכנית אשר מקבלת שתי מילים ושם קוב>. היא תסרוק את הקובצ כדי לגלות בו את המופעים של המילה הראשונה ותחליף אותה במילה השנייה. למשל: 116 2 1 014086 תשנה את כל המללים 'י1אויי למילה "2ש* בקובצ 816. 6 ++6 ו-009 למתכנת המקצועי פרק 5 ירושה ככלי לשימוש חוזר בקוד בפרק וה נלמד על מושג הירושה ב-++6 (88806ז6הםו). נראה שירושה היא כלי בעל עוצמה רבה לשימוש והרחבה של תוכנה קיימת, נכיר סוגים שוניס של ירושה ב-++6 ונלמד את המשמעות של כל סוג. ירושה היא אחד מהתכונות העיקריות של תכנות מוכוון אובייקטיס (00). ירושה לכשעצמה, היא כלי יעיל אבל לא מספק. השימוש בירושה בא, במקרים רבים, בצירוף לשימוש במנגנון הפולימורפיזס (ראה פרק 6). זו הסיבה לחשיבותו של פרק וה בהבנת משמעות תכנות מוכוון אובייקטים. [5.1 | מהי ירושה במונח ירושה (ססמפוו6תםו) אנו נתקליס בתיי היוס יוס. בדרך כלל, מתייחס המונח לרכוש העובר בירושה מאנשיס שהלכו לעולמס. בשפות תכנות מוכוונות אובייקטיס מקבל המונח ירושה משמעות שונה לחלוטין. פעמיס רבות אנו מתייחסים למושג ירושה בהקשר של הורשת תכונות מאב או מאם, לבן או לבת. בשפות תכנות מוכוונות אובייקטיס המונחים ירושה או הורשה מתייחסיס להעברת תכונות של עצם (אובייקט) אחד לעצמים אחרים. ירושה הוא יחס בין שתי מחלקות, או יותר. כאשר שתי מחלקות משתתפות ביחס ירושה, אזי אומריס שמחלקה אחת מורישה ואחת - יורשת. ב-++6 המחלקה המורישה היא מחלקה בסיס*ת (018:8 088%6) והמחלקה היורשת היא מחלקה נגזרת (01888 6671/66). לעיתים מכניסם את המחלקה הבסיסית בשס מחלקת-על (8006101858) ואת המחלקה היורשת - תת- מחלקה (80501858). המחלקה הבסיסית מופשטת ובעלת תכונות כלליות. המחלקה הנגזרת היא מחלקה מפורטת, הכוללת את כל התכונות והפונקציות של המחלקה הבסיסית עס תוספת אפשרית. במחלקה הנגזרת אפשר להוסיף שדות או פונקציות לאלו של המחלקה הבסיסית. לפיכך, ירושה היא מעין הרחבת תכונות אובייקטיס. פרק 5: ירושה ככלי לשימוש חוזר בקוד ‏ 127 בניגוד לירושה בין בני אדס, המחלקה הבסיסית י'חיהיי וקיימת גס אס יש מחלקות אחרות שיורשות ממנה. בדרך כלל, ניתן להגדיר אובייקטיס גסם מהמחלקה הבסיסית (המורישה). הירושה, אם כן, היא צורה לשימוש והרחבה פונקציונלית של מחלקה נתונה. המחלקה הנגזרת יכולה להוסיף פרטים רביס למחלקה הבסיסית, מבלי לשנות אותה. תכונה זו חשובה מאוד, כדי לאפשר שימוש חוזר במחלקות נתונות, ובכך לחסוך שַכתוב מחדש של קוד. איך מסמניס ירושה ב-++6! עבור שתי מחלקות, בסיסית ונגזרת (או יורשת), נסמן ירושה באופן הבא (שיס לב, 2486 ו-06%66 הס שמות מחלקות, שיכולים להיות שמות כלשהם): ;ן ... + 28856 01888 ] 2886 110סטק : 606ט1ע6כ 018588 7 המחלקה הנגזרת (0185 611/66), 66שגז6ס, מצוינת על ידי הכנסת הסימן ":" לאחר שמה בצירוף מילת המפתח טוופטק, ולאחריה שס המחלקה הבסיסית. מילת המפתח יכולה להיות שונה, ובהמשך נראה את המשמעות של האפשרויות השונות. שורות הקוד שנכתבו למעלה ציינו שהמחלקה 26866 יורשת את כל התכונות והפונקציות של המחלקה 88485. לכל אובייקט של המחלקה 6066 יש את השדות של אובייקט השייך למחלקה 84:6. כך אפשר להפעיל כל פונקציה של המחלקה 8886 על אובייקטיס של המחלקה 6%664כ. הדוגמה שראינו זה עתה היא דוגמה לירושה יחידה (18800זסםם: 16פַמם51). כלומר, המחלקה היורשת יורשת ממחלקה בסיסית אחת ויחידה. לעומת זאת, יש מקריס שירושה יחידה אינה מספקת ויש צורך בירושה מרובה (ססמגוהחסחם: 16ק1טומו). ירושה מרובה מציינת שהמחלקה יורשת ממספר מחלקות. כמו במקרה של ירושה יחידה כך גם בירושה מרובה, מכילה המחלקה היורשת את כל השדות של המחלקות הבסיסיות, עס תוספת אפשרית. בנוסף, כל הפונקציות של המחלקות הבסיסיות, הן פונקציות של המחלקה היורשת. [5.2 | ירושה יחידה בירושה יחידה יורשת מחלקה אחת ממחלקה יחידה אחרת. נניח, לדוגמה, שיש לנו מחלקה 'אדם" (6800). לכל אדם יש שם, שס משפחה ומספר תעודת זהות. זהו המקרה הבסיסי ביותר של אדם. אס התוכנה שלנו עוסקת במוסד לימודי, כגון אוניברסיטה, נמצא סוגי אנשים שונים, למשל מרצים וסטודנטים. הסטודנטים חייביס בתשלוס שכר לימוד שנתי, והמרצים מקבלים משכורת חודשית. לכל אחת מיישויות אלו יש תכונה נוספת, השונה במשמעותה ואינה קיימת במחלקה הבסיסית. 8 ++6 ו-009 למתכנת המקצועי נגדיר את שלוש המחלקות הבאות שמייצגות את היישויות שתוארו כאן. ) ת80ע6ע 01858 ; [32] סתאם עַַם0 ; [32 ] סתהאץ11ת58 מַהַםת0ס ;62סתטא 1‏ 6ם1 :טס ;(10 %ת1 ,תת+* ע8ם0 ספתסס ,תת* ע8ת06 5%ם00)מם50ת6ק ; () פת1עס פנסט ;ן (10 %ם1 ,תם+* ע8םת06 59%ת00 ,תםת* 0282 286ת00)םספפפקע::ם0ס5ת6ק / ; (ותת , סתהם) ץ56200 ; (תת+ ,6תהאץ11ת18) ץ56200 = ע6קתגא18 ()%מ1נעק::ת0ס5ל62ק 1סט ו ;" " >> 10 >> " " >> סשתהאץ11ת18 >> " " >> סתהת >> סטסס ] המחלקה הבסיס'ת (0188 0886) מס8ת6? מספקת את המסגרת הבסיסית לאובייקט המייצג אדם. בבנאי של מחלקה זו מועתקיס השם, שס המשפחה ומספר תעודת הזהות. הפונקציה חמוזע מדפיסה את השדות של אובייקט מסוג 605 לפלט הסטנדרטי, כשבין כל שדה יש רווח. באובייקט מסוג ייסטודנטיי נוסיף את השדה המציין את שכר הלימוד השנתי שהוא משלם. ] םספע6ק 110סטק : 5000626 018558 ;%מסתלאס %6ם1 :טס (צהק %ת16,1 %ם1,תת+* עהתס ספתסס,תםת* ע8ם0 86םתסס) 6ם06ט56 (10 ,תת+ ,תת)םתספל6ק [ ;ץצ8ק = סתסתלהאס ] ; ()פת1עס פנ1נסט ;ו הבנאי של :566 מקבל את תכונותיו של אדס בסיסי, ובנוסף להן תכונות וערכיס המיוחדיס לסטודנטים, כגון שכר הלימוד. הבנאי של המחלקה הנגזרת (0128 867160) מעביר ארגומנטיס השייכים לאובייקט הבסיסי לאחר ה-''י:יי, ובעזרת קריאה לבנאי המתאיס של המחלקה הבסיסית. העברה זו מתבצעת לאחר התו המפריד ":". פרק 5: ירושה ככלי לשימוש חוור בקוד 129 הקריאה לבנאי הבסיסי המתאיס נעשה על ידי שס המחלקה הבסיסית והארגומנטיס שמועבריס לבנאי המתאיס בסוגריים עגולים. מנגנון העמסה (ַתו6080צס) יודע גס כאן למצוא את הבנאי המתאים לפי מספר הארגומנטיס וסוגס. במקרה זה, מועבריס לבנאי הבסיסי (6908) השם, שס המשפחה ומספר הזהות. ()6ם1עס::%ת56066 הנ1בסט ;()%ם1עק::םת6250ק ;%תסתלהאס >> סגוסס ] הפונקציה ומוק מדפיסה את השדות של אובייקט מסוג ייסטודנטיי. לאובייקט כזה יש שלושה שדות של האובייקט הבסיסי, ועוד שדה נוסף. כדי להדפיס את שלושת השדות הבסיסיס נקראת הפונקציה הבסיסית ז)מוזק, ולאחר מכן נדפיס את השדה הנוסף. כדי להפעיל את הפונקציה הבסיסית ממחלקה יורשת, עלינו לקרוא לה. לפני שס הפונקציה יש לכתוב את שס המחלקה הבסיסית בתוספת הסימן ''::'י. סימן זה הוא אופרטור המאפשר לקבוע לאיזו מחלקה שייכת הפונקציה הנקראת. הפעלה רגילה של פונקציה בתוך פונקציות של מחלקה יורשת תתייחס תמיד לפונקציה של המחלקה היורשת. גו גס הסיבה לכך שאם לא היינו משתמשיס באופרטור זה, היתה נקראת הפונקציה וחוזק של 56001 פעסם נוספת והיינו מקבליס לולאה אינסופית. רק אס שס הפונקציה הנקראת אינו מתאיס לפונקציה במחלקה היורשת, המהדר מנסה למצוא פונקציה כזו במחלקה הבסיסית. בדרך דומה נגדיר את המחלקה ייפרופסוריי: ] ם80ע6%ק 110סגמס : 20169899890%ע 01858 ;ץע5818 6ם1 :טס (88[1 %ת10,1 סת1,תםת+* עא8םת6 ס6פתסס,תת* עםת6 86ם00)ע105₪580ק (10 ,תת+ ,תת)ם50ת6ק [ ;881 = 88182 ) 1 ()פםתנ1בעס בנסט ;()%מ1עס::ת6250ק ;ץע5818 >> 0006 ו ראינו, שאפשר להפעיל פונקציה של מחלקה בסיסית מתוך מחלקה יורשת. הפעלה כזו מאפשרת שימוש בפונקציונליות של המחלקה הבסיסית במחלקה היורשת. מצב זה נקרא 8ת09671001 (דריסה). במקריס רביסם אף לא קייס הצורך לכתוב פונקציה במחלקה היורשת. אם, לדוגמה, היתה לנו פונקציה שבודקת אם שני אנשיםס הס זהים, יכולים היינו לכתוב אותה כך: ) ת80ע6ע 01858 % ((80 מספעס6קע 86ם00) 606081 %6ם1 [ ;(ע6סתגא16.ק == עסמתטא10) םעט266 + 0 ++6 ו-009 למתכנת המקצועי ו (2ק8 מ86250ע 5%םת00 ,621 מספע6ע 86ם628602==)00ק0ס 6ם1 ו ; (02) 60081. 1 םעגו26% ו הפונקציה משווה בין שני אובייקטיס מסוג ם680ק. שני אובייקטיס כאלה והים, אס מספר הזהות שלהס זהה. הוספנו אופרטור גלובלי, שאינו חלק של המחלקה, כך שאפשר יהיה לבדוק את השיוויון בין שני אובייקטיס מאותו סוג (במקרה זה - ם680ק) בצורה נוחה. במקרה של פונקציה זו, אין צורך להוסיף את הפונקציות במחלקות היורשות. מכיון שאובייקטיס היורשיס מהמחלקה הבסיסית הס אובייקטים בסיסיים, מאפשר המהדר להמיר אובייקט יורש לאובייקט בסיסי. לכן, למשל, מותרת ההמרה של 'יפרופסוריי לייאדס"י ושל יסטודנטיי לייאדסיי. ליתר דיוק, ההמרה נעשית באופן אוטומטי על ידי המהדר. לאור האמור, זהו אופן ההפעלה של פונקציות אלו: ; (500 ,"3302245" ,"תסםתס6ס" ,"8ע5)"1002 %ם66ג56 ; (5000 ,"220358" ,"שגנתה" ,"תהה")ק 0165802כ ו( 1-5 6 ;6061 >> "6ש6ת8%28 שעסט 0םמ1ם6%ת50" >> סטסס0 ; ()ףם1עס.5 ; () פת1עס.ס סוג הירושה עד כה הכרנו ירושה ציבורית בלבד, שבה כל השדות והפונקציות בחלק הציבורי של המחלקה הבסיסית נחשבות כציבוריות במחלקה היורשת. סוג הירושה נקבע על ידי מילת המפתח המופיעה לפני שס המחלקה. מילות המפתח הן אחת משלוש המילים : > 16![טטק - ירושה ציבורית. = )0+6006זק - ירושה מוגנת. > 6)ה טוק - ירושה פרטית. מילות מפתח אלו גם מתארות אזורי גישה שוניס במחלקה. אנו כבר מכירים אזורי גישה פרטי וציבורי. אזור הגישה החדש הוא האזור המוגן (0866660זע). אל השדות והפונקציות באזור זה יכולות לגשת מחלקות נגזרות בלבד. לאזור הגישה המוגן מותרת הגישה גס לחבריס של המחלקה. למשל: 0188585 2886 ] 0: פרק 5: ירושה ככלי לשימוש חוור בקוד ‏ 131 לשדה 41 יכולות לגשת רק מחלקות יורשות (או חבריס של המחלקה), ופונקציות או מחלקות אחרות אינן יכולות לעשות ואת. דבר זה תקף גסם לגבי פונקציות שנמצאות באזור זה. כלומר, לפונקציה + יכולות לגשת מחלקות יורשות, או חבריס של המחלקה. ירושה פרטית בירושה פרטית (ססתגוהסהתו והצחק) השדות והפונקציות הס פרטייסם במחלקה היורשת. אין גישה לשדות ולפונקציות אלו פרט לפונקציות של המחלקה היורשת, או חבריס של מחלקה זו. כלומר: ] 2886 0185855 :טס ;1אט סם1 2 26 6ב ל ]) 2886 866ט10עק : 262160 018585 [... ;50 + ()6 18סט ;ן ;5 28956 ;0 פטנ1עסכ 8 סם - מסעעס // 2 = 4.081 6% // ;1 = 81ט.ס ירושה פרטית שקולה להכלה (650מוחו9וחסס6), כלומר, אפשר היה להגדיר שדה במחלקה היורשת, שהוא אובייקט מסוג 84% ולכן, אובייקט מסוג 6אזפ היה מכיל אובייקט מסוג 28%. למרות זואת, קייס הבדל בין הכלה לירושה פרטית. בפונקציה > של המחלקה היורשת קוראיס לפונקציה +. במקרה זה, אין צורך להוסיף קידומת משוס ש-1 היא פונקציה השייכת למחלקה היורשת. לעומת זאת, אם היינו מגדירים שדה מסוג המחלקה הבסיסית במחלקה היורשת, היה עלינו להשתמש באובייקט המתאים בעת קריאה לפונקציה שלו: ) 66ט1עסק 018855 ;5 2856 4-6 5ם + )7 :בסל 2 ++6 ו-009 למתכנת המקצועי כמו שרואים בקטע הקוד הזה, הפעלת הפונקציה + נעשית דרך האובייקט. זו הדרך לסרבל את הקוד (מבחינה ויזואלית), לכן, יש מתכנתים המעדיפים להשתמש בירושה פרטית, ולא בהכלה. בהמשך נראה דוגמאות נוספות לירושה פרטית. ירושה מוגנת ירושה מוגנת (06ם6)8גמו 0160666זכ) מוגדרת בעזרת מילת המפתח 2:04600666. למילת מפתת זו יש שתי משמעויות. כאשר מילת המפתח מופיעה באזור של המחלקה - האזור הזה, עד לאזור הבא, פתוח לגישה של מחלקות יורשות. למשל: ] 2886 01888 : 66 הנע ;1 6ם1 :מ ?2 תד ;ו ] 2886 110סטק : 17606ע6כ 01858 [ ;ט = 2א + (ט סת2)1א 866 בשנסט ;ו 60ע1ע6כ 8 סם - 208עע6 // 2 = 2א.4 תס1פסתו2 2621060 משטספםס 0% // ;(2)2א 6.8566 לפי קוד וה, נראה שיש אפשרות לשנות ערך לשדות בחלק המוגן, או לגשת לחלק המוגן למחלקות יורשות בלבד. תכונה דומה לכך היא ירושה מוגנת : ] 2886 01858 :מ ;א 6ם1 ;ו ] 2886 660066סעס : 21 01858 ; (ק₪8* 21 ,סכ* 5)2886 16סט ;ן (ק9* 21 ,סס* 1::5)285856כ בנסע לא 06ב 8 סם - 69908 // ;א<-סס = 1א 1 6סץ5 0% 18 007608 - 608 // ;א<-00 = 2א פרק 5: ירושה ככלי לשימוש חוור בקוד ‏ 133 הפונקציה 1 של המחלקה 1כ יכולה לגשת לאובייקטיס מסוג 1 בלבד (כולל האובייקט הנוכחי ₪₪ו), אל שדה א שנמצא בחלק המוגן (0160660זכ). לפונקציה וו אין גישה לשדות בחלק המוגן של אובייקטיס מסוג 45, שאינס מסוג 1פ. ]1 21 110סטס : 22 018588 ; (02* 22 ,6* 51)21 ב1סט (62* 22 ,0* 1כ2::51)2כ2 %נ1בסט 7 ,1 סמב 8 סם - פסעעם // ;א<-0 = 1א 2 6סץ5 0% 18 007608 - 0% // ;א<-02 = 2א% בפונקציה 11 השייכת למחלקה 2 יכולים לגשת לשדה א רק אובייקטים מסוג 2פ. בפונקציה זו השייכת למחלקה 2ת, אובייקטיס מסוג 1 אינם יכולים לגשת לשדה א. הדרך הקלה לזכור נקודה זו (שגורמת לבלבול אפילו בקרב מתכנתיס מנוסים) היא, שאובייקט מסוג 01 אינו אובייקט מסוג 2כ. לכן, הגישה (0008ג) המוענקת לחלק השמור של אובייקטיס מסוג 22 היא רק לאובייקטיס מסוג 2כ, או ליורשים ממנו. למעשה, אובייקט מסוג 1 יכול להיות מסוג אחר היורש מ-1ת, לכן גישה כזו אינה אפשרית. הורשה ציבורית בהורשה ציבורית הופכיס השדות הציבוריים של המחלקה הבסיסית לשדות ציבוריים במחלקה היורשת. השדות המוגניס במחלקה הבסיסית הופכים לשדות מוגניס במחלקה היורשת, והשדות הפרטיים של המחלקה הבסיסית הם מחוצ לתחוס במחלקה היורשת. ירושה ציבורית מסומנת על ידי מילת המפתח ט6ו1טוש. ] 2886 110סטס : 23 018558 ;ו ; (ע 5)2856 18סט 3 2 5)8( ; יתרה מזאת, פונקציות הפועלות על אובייקטיס מסוג 88% פועלות באופן רגיל על אובייקטים מסוג 23. המהדר הוא גה שממיר את האובייקט מסוג ₪3 לאובייקט מסוג 6. במקרה שהאובייקט מועבר בקריאה רגילה (לא כייחוס) כמו לפונקציה +, מתבצע חיתוך (פחוטון3) של האובייקט לאובייקט הבסיסי. כלומר, המהדר מפעיל את בנאי ההעתקה כדי ליצור אובייקט בסיסי מהאובייקט הנתון. אס האובייקט מועבר כייחוס, אין צורך לבצע חיתוך מאחר וייחוס הוא שס אחר לאובייקט. 4 ++6 ו-009 למתכנת המקצועי דוגמה - רשימה מעגלית כפולה בסעיף זה נראה דוגמה לרשימה מעגלית כפולה, ונלמד את אופן השימוש בה במחלקות היורשות מהרשימה. הקוד לרשימה המעגלית הכפולה נמצא בקבציס 41562 ו-0ק01150.6. הרשימה מורכבת מצמתים, לכל צומת יש מצביע לצומת הקודם, ומצביע לצומת הבא. לרשימה יש צומת מיוחד המסמן את תחילת הרשימה ונקרא .זזא. צומת זה מצביע לראש הרשימה וגס לסופה, לכן הרשימה היא מעגלית. כדי לממש את הרשימה נגדיר שלוש מחלקות: > או - צומת ברשימה. = 166 118% - איטרטור לרשימה המאפשר לסרוק את כל הצמתים ברשימה. * 11% - אוסף הצמתים המייצג את הרשימה. +אסת סע איוד 5.1: מבנה הרשימה המעגלית הכפולה צומת ברשימה צומת ברשימה מכיל שני מצביעים (אסם ו-צסעק) שמצביעיםס לצומת הבא והקודם, בהתאמה. הצומת ברשימה מעניק לרשימה גישה לחלק הפרטי שלו, כדי לאפשר הכנסה והוצאה של צמתיס מהרשימה. ) %ם11 01888 2 018888 ₪מם1216 ;טסעס* %ם11 ;%6אסת* %ם11 :טס ; ()%ם11 ; () %ם11< [ ;%א6ת מעט66ע + ()6א6ת 66ש* א%ם11 [ ;טסעק מעטס6ע + ()טסעס 66ש* %ם11 הבנאי של הצומת מאתחל את המצביעיס אל האובייקט הנוכתי, 8ומו. פרק 5: ירושה ככלי לשימוש חוזר בקוד 135 ()אם11-::א%ם11 ו 1 המפרק של הצומת ריק כעת. עובדה בולטת היא שלצומת אין עדיין כל נתוניס, פרט למצביעים, ומייד נראה כיצד נוכל בעזרת ירושה להכניס בו נתונים. הפונקציות ואסח ₪66 (-עסזק ₪61 מאפשרות גישה לצומת הבא או הקודם, בהתאמה, ונועדו לשימוש האיטרטור. מכיון שלפנינו רשימה כפולה, יכולה האיטרציה לחיות דו- כיוונית, כפי שנראה בהמשך. האיטרטור הא*טרט)(ר (16000) מאפשר לעבור על צמתיס ברשימה, או פשוט - לסרוק אותם, ולכן אפשר לכנותו סורק. כדי לעבור על צמתים יש לאיטרטור שדה שמציג את הצומת הנוכחי, והוא מקבל אליו מצביע. האיטרטור מאפשר לעבור על הרשימה בשני הכיווניס, מראש הרשימה לסופה ולהיפך. מעבר כוה על הרשימה יכול לעבור דרך הצומת, שהוא שורש הרשימה. לכן, כשעובריסם על הרשימה יש לשים לב לכך במיוחד. כדי לקבל את הצומת הנוכחי, מגדיר האיטרטור אופרטור מסוג *'*יי. בעזרתו נראה האיטרטור כמצביע, שכן כשמשתמשים באופרטור '*יי מקבליס את תוכן המצביע, שבמקרה זה הוא הצומת הנוכחי שאליו מצביע האיטרטור. ) 1062 1186 018588 ;%תפעפטס* אםמג11 :טס [ ;1 = 6תשעעטס + (1* %ם1₪62)11 1186 () *628%02קס* %ם11 [ ; (%5ם6ת00?2ס) מעט6ס6ץ + ; () %א6ם* %ם11 ; () טפעק* %ם11 [ ;18ת%* םע00ס6ע2 ;()6א68ם + ()++600028602 1665 1186 ; (6ם1)++628%02ק0 1665 1186 [ ;18ת%* 26009 ;()ט26ק + ()--600028002 1662 1186 ; (0ם1)--628%02ק0 1665 118% % ((81 1608 1186 86ם00)==ע628602ק0ס 6ת1 ; (%ת1.002%6 == סםתסעע2טס) מעטססץ + 8% ((81 1608 1186 86ם00)=!ע628602קס 6ת1 ; (%ת1.002%06 =! סםתספעעטס) מעטספץ + 6 ++6 ו-009 למתכנת המקצועי הפונקציה ואפ מקדמת את המצביע של הצומת הנוכחי למצביע הבא, בעזרת קריאה לפונקציה אפ 86 של הצומת הנוכחי. הפונקציה שפוק מחזירה את המצביע הנוכתי צומת אחד לאחור. ()%א6ם::1662 1186* %ם11 ן ;()%6א6ם 666<-%ם6עע2ט0 = סמתפעפגוס 6 ;%ת6עע2טס תעג660ת ()ט6עס::1602 1186* %ם11 ו ; () טסעק 06%<-%ת26ע002 = סםתפעעטס ;מסעתטס תעגמ66ע ו ראינו שיש שני אופרטוריסם מסוג "++" המוגדריס עבור האיטרטור (000900. אופרטורים אלה מקדמיס את האיטרטור לצומת הבא ברשימה. האופרטור שאינו מקבל פרמטר מקדם את האיטרטור תחילה, ולאחר מכן מחזיר ייחוס לאיטרטור (00018+09 א11סיזק). הפעלת האופרטור האחרון היא במשפטים מסוג זה: ; (%ם1)1 166% 1156 + האופרטור השני, שמקבל שלם, מקדם את האיטרטור, אבל מחזיר איטרטור שמתאים למצב הקודם, לפני הקידוס. אופרטור זה נקרא ז400ז6קס 206% והוא דומה לאופרטור המגדיל שלם, אבל משתמש בערכו הקודם : הר הפרמטר שמקבל האופרטור נועד לציין למהדר שזה אופרטור אש ויש להפעילו במשפטים המתאימים. כדי לממש את הסמנטיקה המבוקשת, מעתיק האופרטור את האובייקט הנוכתחי לאובייקט ומני, מקדם את האיטרטור הנוכחי, ומחזיר את האובייקט הזמני. (0ם1)++16602::00628%02 1186 166% 115856 | ; (%ם26עגו0) קת6 1665 1186 ; () 6א6ת ; קתף תעגו0ס6ע2 ו באופן דומה, מוגדר האופרטור "--יי (אופרטור החיסור אשר מממש תזוזה לאחור). ראוי לוכור שיש שני אופרטוריס כאלה, א08/8ק (-אח6זק, בהתאמה. (0ם1)--16602::00628%02 1186 166% 1186 ו ; (%ם56עגוס) קת% 1662 1186 ; () טסעס ; תס מעמו60ע פרק 5: ירושה ככלי לשימוש חוור בקוד | 137 האופרטורים שמחזירים איטרטור המתאים למצב הקודם (אאוצסט) פחות יעילים, משוס שאובייקט המוחזר מהאופרטור מועבר לא כייחוס, אלא אל המחסנית של התוכנית. בנוסף, מגדיר האופרטור אובייקט ומני שאליו הוא מעתיק את האובייקט הנוכחי לפני ההעתקה. אופרטורים אלה מבצעים שתי העתקות, הראשונה לאובייקט הזמני בתוך האופרטור, והשנייה לאובייקט המוחזר אל המחסנית. מומלץ, אם כן, להשתמש באופרטוריס האחריס במידת האפשר. הרשימה מכילה צומת אחד, המציין את ראש הרשימה והוא ריק (אינו מכיל נתוניס). צומת וה מציין גס את סוף הרשימה. בנוסף, יש לרשימה שדה שמציין את מספר הצמתיס ברשימה. 01858 118% ] 6 תא 6םס // ;+* %ם11 8 05 מפסחטם // 37 סם1 ; (%*םת1* %ם11 ,5611* א%םת5615)11 85662 פטס בשנסט ; (א*ת1* את11 ,8615* א%ת585615)11 65026 סטס שנסט ; (*%ם11)אםת11תט 16סעצ :טס 118%)( ; 118% )( ; ; (* %ם0)11ת6סק8 הבנ1בסט ; (* %ם62%)11פת1 16סע (ת1%6* %ת11 ,פסק* %ם5626)11ת1 ה1בסט [ ;(ת166 ,08ק)8615 65026 פטס + 0 סתם 6668 // ; () 6808ם* %מ11 1 ס6תם 6668 // ;()5811* %ת11 ; ()680ם 6טסת26* %ם11 ;()6811 סטסת26* %ם11 ; (* %ת11) פטסתספע 1סע [ ;11א תעט6%ע2 + ספתסס ()11ם* %ם11 005856 [ ;(()086ם)1662 118% מעטססע + ()ם1שסס 1665 1186 [ ;(12א)1662 118% םע600ת 1 ()0ם8 166% 118% ;ו הפונקציה 5611 886 וטנ נמצאת בחלק הפרטי של המחלקה ומקבלת מצביעיס לשני צמתיס. הצומת הראשון נמצא ברשימה, הצומת השני הוא צומת שמכניסה הפונקציה לרשימה. הפונקציה מכניסה את הצומת השני לאחר הראשון. (א*ת1* את11 ,8615* %ם585611)11 85665 06קש::11586 בנסט 2 = טס6עס<-א%ם1 ;%אסת<-5611 = סא6ת<-א%םת1 ;את = טפעק<-%א6ם<-5611 ;את = ס6א6םת<-5611 8 ++6 ו-009 למתכנת המקצועי הפונקציה 8611 06106 וט מקבלת אף היא מצביעים לשני צמתיס (כמו הפונקציה הקודמת). הראשון מביניהס הוא צומת שנמצא ברשימה, והשני הוא הצומת שיש להוסיף לרשימה. פונקציה זו מכניסה את הצומת השני לפני הראשון. (%ם1* %ם11 ,8611* א%ם8611)11 65026 6טק::11856 בנסט ו 72 = סאפ6ת<-א%םת1 ; ט6עק<-+861 = ט6עס<-א%ם1 ;אם1 = סאס6ת<-טס2ס<-5611 ;את = טסמס<-5611 ] הפונקציה 6מו|פט מנתקת צומת משני הצמתים השכנים לו. הפונקציה מעדכנת את המצביע טסוק של הצומת הבא שיצביע לצומת הקודם, (במקוס אל הצומת הנוכתי). בנוסף, היא מעדכנת את המצביע :א6ם של הצומת הקודם לצומת הנוכחי, כדי שיצביע אל הצומת הבא (שאחרי הצומת הנוכחי). לאחר פעולת הפונקציה, המצביעים של הצומת המנותק (זה הצומת הנוכתי), מצביעיס אל הצומת עצמו. הצומת הבא הצומת הנוכתי הצומת הקודס (8615* %ת11)אםת11תט::118% ב1סע ;טסעס<-8615 = טס26ס<-6א6ת<-5615 ;%אסם<-85615 = 6א6%ם<-ט26ס<-5615 7 = טסעס<-8615 = סא6ת<-5615 בנאי הרשימה מקצה את הצומת הריק (11א) הראשון של הרשימה, והמפרק משחרר את הצומת הריק. הבנאי גם מאפס את מספר הצמתים ברשימה. גישה אחרת היא להגדיר צומת אחד בתוך הרשימה, ולחסוך את ההקצאה והשחרור של הצומת הריק. 115%::1185%6)( ;*ת11 חסם = תזא 7 = פססרְססת 1185%::-118%)( פרק 5: ירושה ככלי לשימוש חוזר בקוד 139 061666 9; ] הפונקציה 6ַפסקקג מגדילה את מספר הצמתים ברשימה ומכניסה צומת בסופה. כדי להכניס צומת בסוף הרשימה הוא מוכנס לפני הצומת הריק. מכיון שזו רשימה מעגלית, שקול הדבר להכנסת הצומת בסוף הרשימה. (%ת1* %םת0)11ם6סק115%::8 ה1בסט ןָ ;++60%8רססת ;(8ם1 ,11א)85615 65026ס פוש ] הפונקציה 68חו מכניסה צומת בתחילת הרשימה ומגדילה את מספר הצמתיס ברשימה. הכנסת צומת לאחר הצומת הריק שקולה להכנסה בתחילת הרשימה. (אם1* %ם11)%ע62פת118%::1 ב1סע ו ;++60%8רססת ; (אם1 ,11א)8615 85662 שוש שתי הפונקציות, 684 ו-911, מחזירות מצביעיס לראש ולזנב הרשימה, בהתאמה. ()0680ם::1158%* א%ם11 ;%אסםת<-1א מעט260 (3.1/0ה115%5::6* 136 ו ; טסעם<-11א תעטססץ ו הפונקציה 694( 16₪0%6ז מוחקת את הצומת הראשון מהרשימה. לאחר המחיקה מקטינה הפונקציה את מספר הצמתיס שברשימה. ()680ם 6טסת118%::26* %ם11 2 = אם1* א%ם11 4 (0 < 6068רמ0ם) 15 ;%א6ם<-1א = א%ם1 ; (%ם1)%ם11תט ;--65ס6רְססת ] ;אם1 תעג6%ע2 ו הפונקציה 911 פטסממטז מוחקת את הצומת האחרון ברשימה. לאחר המחיקה מקטינה הפונקציה את מספר הצמתים שברשימה. 0 ++6 ו-009 למתכנת המקצועי ()6811 6טסת118%::26* %ם11 1 02 = א%ם1* אםג11 ] (0 < 0076068ם) 11 ; טסמס<-ת1א = א%ם1 ; (%ם1)%ם11תט ;--6065רְססת ] ;את1 מעו66ץ ] הפונקציה 10%6ח16 מוחקת צומת נתון מהרשימה, ולכן קטן מספר הצמתיס ברשימה. (אם1* %םת11)פטסת9בת118%::2 ב1סע ן 4 (0 < 60608רְמסם) 15 ; (%ם1)אמ11תט ;--6065רְססת שימוש ברשימה בעזרת ירושה אין שימוש רב לרשימה המורכבת רק מ-%מ:1. אס רוציס להכניס נתוניס לרשימה, ניתן לבצע ואת בעזרת ירושה. למשל, אנו יכולים להגדיר צומת המכיל שלם, ויורש מהצומת הבסיסי של הרשימה: ] את11 116מטס : %ם11 6םת1 018588 ;1הט סם1 :טס [ ;ט = 081 + (ט 6ם1)אםת11 6ת1 [ ;781 מעט%ס6ע + ()%6ם1 6286052קס נן מכיון שהצומת א%מו] +מו יורש בירושה ציבורית מהצומת הבסיסי של הרשימה, אפשר להשתמש במצביע לאובייקט מסוג ה בכל מקוס בו, אנו משתמשים במצביע לאובייקט הבסיסי. אובייקט מסוג %םו[ )מו הוא בעל אותס השדות והפונקציות של אפון, בתוספת לשדה השלסם שלו ואופרטור ההמרה 06140 מסנפעסטמס6) לשלם. הכנסת אובייקטים לרשימה אפשר להעביר לרשימה מצביעים לאובייקטיס מסוג 118% +מוּ, ולכן אנו יכוליס להכניס אובייקטיס כאלה בתחילת הרשימה ובסופה: (ת %ם1 ,1 סת1 ,8186 6)118%ת6סק8 %הנ1בסט ] (++1 ;ם >> 1 ;1 > 1 6ם1) ע0+ פרק 5: ירושה ככלי לשימוש חוזר בקוד | 141 ;((1)את11 6ת1 טס6םת)0מ6סק18%.8 (םת %תם1 ,1 6םת1 ,818% 562%)1186םת1 ב1סע ] (++1 ;ם >> 1 ;1 > 1 6ם1) ע0+ ;((1)אם11 6ת1 אס6ם)862%ם186.1 ו הפונקציה 6ַמססקג מכניסה אובייקטיס בסוף הרשימה, והפונקציה 18804 מכניסה אובייקטיס בראש הרשימה. בשני המקרים מקבלת הפונקציה תחום להכנסת האובייקטים, וכל האובייקטיס בתחוס מוכנסים לרשימה בקצה המתאים. הוצאת אובייקטים מהרשימה כדי להוציא אובייקטיס מהרשימה, בתחילתה או בסופה, יש להשתמש בפונקציות המתאימות. שתי הפונקציות, 1646 6טסנתסז ו-1011 6ש0גת6ע, מרחיקות אובייקטיס מהרשימה בקצה המתאים. מספר האובייקטים המורחק הוא ם, וזהו פרמטר של הפונקציה. (ת %ם1 ,618% 686)118%6ם 6טסמ6ת ב1סעט ו (++1 ;ם >1 ;1=0 6ם1) ע0+ ; () 680 6טסת15%6.26 (ת %ם1 ,618% 6811)118%6 6טסת6ע ב1סע ו (++1 ;ם>1 ;1=0 %ם1) 105 ;()6811 סטסת6ע.18% מעבר על הרשימה עד כה הכנסנו או מחקנו אובייקטיס מהרשימה ללא צורך בהמרת מצביעים. בעת מעבר על רשימה יש להגדיר איטרטור שמחזיר מצביעיםס לאובייקטיס מסוג אםון, למרות שהכנסנו לרשימה אובייקטים מסוג אחו[ +חו. במקרה זה, עלינו להמיר את המצביע למצביע נכון. הפונקציה הבאה משתמשת באיטרטור כדי לעבור על הרשימה. בלולאה הראשונה עוברת הפונקציה על הרשימה מתחילתה לסופה. כדי לקדס את האיטרטור לאובייקט 2 ++6 ו-009 למתכנת המקצועי הבא ברשימה משתמשת הפונקציה באופרטור לאחר השימוש באופרטור וה מופעל אופרטור המצביע **' (00619401 6676107106), כדי לקבל את האובייקט. במקרה זה, יש להמיר את סוג המצביע לסוג המתאים (1:8% +מו). המרה כזו היא אחד החסרונות של השיטה. בהמשך נראה כיצד ניתן להתגבר על חיסרון זה. התנאי של האיטרציה הוא שהאיטרטור שונה מהאיטרטור שמסמן את סוף הרשימה. תנאי ה נבדק בחלק התנאי של הלולאה. בשלב השני משתמשת הפונקציה באופרטור "--'י המקדיס (א6זק) של האיטרטור. בשלב זה עוברת הפונקציה על הרשימה בכיוון ההפוך, מסופה לתחילתה. (8180 118%)%ם1עק ב1סע ו ;(()ם601כ.1)18% 1662 1186 ;עטס* %ם11 6ת1 ;(()0ת61)18%6.6 1662 1186 ;")ם" >> 0006 ] (81 =! 1) 16נ1תט 2 (++) * (*%מ11. 8םמ1) = סוס ;7-2 5% מ 6 >> 6006 ] ;")" >> 61ת6 >> " (" >> 0006 5 ->%* (*11%. סםב)י == הנוש ]1 (81 =! 1) 16נ1גתט 66 טס >> שטסס ל( 3==) %-(6% 130 )= ענו ] ;01ת6 >> -" (" >> 0006 ו התוכנית הראשית בקוב> מ0ש.1 +18 מנצלת את כל הפונקציות שתוארו עד כה, כדי להכניס אובייקטיס לרשימה ולהדפיס את האובייקטיםס הנמצאים בה. הפונקציה גס מבטלת חמישה אובייקטיס מתחילת הרשימה ומסופה. ()מ1נהת %ם1 5? ;(10 ,0 ,6)11ת6סקה8 ;(20 ,10 ,56₪0%)11םת1 ; (1ב6)1םנ1עס ;(5 -,11)בהסת פטסתסץ 600076 6811)11,- 5(; ; (6)11תנ1עס 2 תע0ט66ץ פרק 5: ירושה ככלי לשימוש חוזר בקוד | 143 הפלט של תוכנית זו ייראה כך: )10 11 12 13 24 15-16: 17" 18 19 20 0 1 25 3-46 36/76 9 10( )10 9 8 7 6 5 4 3 2 1 0 20 19 18 17 16 15 14 13 12 11 10( )15 16176 18: 192000 1-2 374 5( )5 4 3 2 1 0 20 19 18 17 16 15( ירושה מהרשימה כשנתונה המחלקה 11% אנו יכולים ליצור מחלקות חדשות שתשתמשנה בפונקציונליות של מחלקה זו. אנחנו יכוליס, לדוגמה, ליצור מחסנית (5480%) ותור (סגוסטך). מחסנית (54808) היא מבנה נתוניס המכיל אובייקטיסם אחרים. כאשר מכניסיס אובייקט למחסנית הוא מוכנס בראש המחסנית, כאשר מוציאיס אובייקט מהמחסנית הוא יוצא מראשה. כלומר, האובייקט האחרון שהוכנס הוא הראשון שייצא (סתז. אס נרשוס זאת כמשוואה, נקבל: א = ((א) םפגוס) ססס הפעולה תפטש "דותחפת""י אובייקט למחסנית, והפעולה קסש מוציאה אובייקט מהמחסנית. כדי לממש את המחלקה מחסנית נגדיר אותה כיורשת ירושה פרטית מהמחלקה מסוג יירשימהיי (1180). נבצע ואת בדרך הבאה: ] 118% 866ט1עק : 8680% 0185858 :טס [ ()5080%8 [ ;(6)1ע562ת1 + (1* א%ם11)םפטס הנ1בסט [ ;()680ם 6טסת6ע מעטס6ע + ()ססס* %ם11 ;ו לצורך מימוש המחסנית דרושות שתי שורות קוד, שמפנות את הקריאות לפונקציות הרשימה! כלומר, בעבודה מועטה ביותר ובעזרת שימוש בירושה פרטית קיבלנו מבנה נתוניס חדש. שים לב, השתמשנו בירושה פרטית, לכן שאר הפונקציות הציבוריות של המחלקה +18 הן מחוץ לתחום למשתמש במחלקה זו. מאחר והירושה פרטית, המשתמש במחסנית אינו יכול להשתמש בפונקציות של הרשימה כמו הכנסה של אובייקטיס לסופהה. הדבר תואס את הגדרת המחסנית, שבה אין אפשרות להכניס אובייקטיס לתחתית המחסנית, או להוציא אובייקטיס מתחתית המחסנית. תור תור (פט6טף) הוא מבנה נתוניס אשר בו האובייקט הראשון שמוכנס הוא גם הראשון שיוצא (10:). תור במדעי המחשב דומה לתור בסופרמרקט בעמדת התשלום, כאשר הראשון להגיע מקבל את השירות הראשון. גס מחלקה זו ניתנת למימוש בקלות בעזרת הרשימה וירושה פרטית. 4 ++6 ו-009 למתכנת המקצועי 1 118% 06ס8ט1עק : 60606 018588 :טס [ () 6גו6גו [ ;(86)1ם6ס0ס8 + (1* א%ם11)ש6טס 8%נ1בסע [ ;()680ם פטסתפע מעגוססץ 1 ()66ש* %ם11 ;ן מכיון שהשתמשנו בירושה פרטית, אין למתכנת המשתמש במחלקה זו גישה לשאר הפונקציות הציבוריות של הרשימה. אס היתה למשתמש גישה לשאר הפונקציות של הרשימה, הוא היה יכול להפר את חוקיות התור. לכן, במקרים כאלה יש להשתמש בירושה פרטית. ניהול זיכרון והגדרת אופרטורים בפרקס 3 למדנו על מחלקות וראינו שאפשר להעמיס אופרטורים (940ז6קס 8 שס). בין שאר האופרטוריס שניתן להגדיר למחלקה, הכרנו את האופרטור א6מ ואת האופרטור 861666. אלו הן פונקציות סטטיות לפי ברירת המחדל, שאינן קשורות למחלקה מסוימת. כאשר מפעילים את אופרטור הקצאת הזיכרון שסם, עדיין אין אובייקט, ולכן הוא אינו קשור לאובייקט מסויס. בדומה לכך, כשמפעילים את אופרטור השחרור, האובייקט כבר פורק, לכן גם אופרטור זה אינו יכול להיות קשור לאובייקט מסוים. בסעיף זה נראה כיצד להגדיר אופרטוריס אלה עבור מחלקות. נניח, שקיימות שתי מחלקות הכתובות כך: ] 2886 01858585 ;ס 6ם1 :טס [ ;0ס = מס + (סס 6ם2856)1 (82 6 6%9)8126ם עססה8עס6קס* 18סט [ ;(582)חאס6ם עססאעסקס:: מעטס6ץ ]1 (קס* 0106ט)661666 עסס6286קס סנסט [ ;(ס)84616₪6:: 1 ;ו ] 2886 110סגמק : 6ט1ע6כ 018585 2 6ת1 :טס [ ;00 = 6 + (ס0ס)28956 : (סס 6ם1 ,80 %ם1)פטנעסכ ;ו למחלקה הבסיסית יש שדה שלם אחד וגם למחלקה היורשת ממנה יש שדה שלם אחד. המחלקה הבסיסית מגדירה את האופרטוריס של הקצאת הציכרון. פרק 5: ירושה ככלי לשימוש חוזר בקוד | 145 הגדרת אופרטור ש6ח כאשר מחלקה רוצה לטפל בניהול הזיכרון ובהקצאת אובייקטיס שלה, על המתכנת להגדיר עבורה את אופרטור הקצאת הזיכרון א6ם. דרך כתיבת האופרטור יכולה להיות אך ורק כמו בדוגמה הקודמת. האופרטור יכול לקבל ארגומנט אחד בלבד מסוג 1 5126 (למעשה, זה שלס חסר סימן). ארגומנט זה מציין את גודל הזיכרון הנדרש להקצאה. האופרטור מחזיר מצביע מסוג וס שהוא מצביע לאזור הזיכרון שהוקצה. הארגומנט שמציין את גודל הזיכרון המבוקש נראה מיותר במבט ראשון, שהרי גודל אובייקט של המחלקה ידוע לפונקציה זו, הוא זהה ל-(512601)*)11. אבל, כאשר מגדיריס אופרטור כזה, הוא תקף גם עבור מחלקות נגזרות. על כן, כשמקציס אובייקט של מחלקה נגזרת, ייקרא אופרטור זה עס גודל שיכול להיות שונה מגודלו של אובייקט בסיסי. לדוגמה: ;2סס* ,1סס* ספַַם2 ;(2886)1 חטסם = 1סס ;(2 ,106)1ע62כ טסם = 2סס בשתי ההקצאות בקטע קוד וה ייקרא האופרטור שהוגדר במחלקה הבסיסית. גודלו של הזיכרון המבוקש יהיה שונה בכל מקרה. הגדרת האופרטור 66!616 תפקיד האופרטור 861666 לשחרר זיכרון שהוקצה קודם לכן על ידי שסם. כמו במקרה הקודם, אפשר להגדיר אופרטור זה כפי שהצגנו בדוגמה. כלומר, האופרטור מקבל מצביע מסוג 6וסץ, המצביע לאזור הזיכרון שיש לשחרר. כמו במקרה הקודם, אופרטור זה עובר בירושה. במיליס אחרות, כאשר מפעיליס את האופרטור 66166 על מצביעיס למחלקות יורשות, ייקרא אופרטור זה אס הוגדר כפונקציה במחלקה הבסיסית, או אס הוגדר במחלקה היורשת. כלומר, הפעלת 66166 על אובייקטים של מחלקה יורשת תגרוס להפעלת האופרטור שהוגדר במחלקה הבסיסית. לפיכך, לא יופעל האופרטור הגלובלי לשחרור ויכרון של המערכת. למשל: 061666 1; 4616066 7 בשני המקרים ייקרא האופרטור 661606 של המחלקה הבסיסית. שימושים באופרטורי ניהול הזיכרון כאשר מוגדריס האופרטוריס לניהול ויכרון עבור מחלקה מסוימת, תיעשה הקצאה ושחרור של אובייקטיס בעזרתם. בדוגמה הקודמת ראינו שאופרטוריס אלה השתמשו באופרטורים הגלובלים של המערכת. לשימוש מסוג זה אין שוס יתרון. מתי אס כן שימושי להעמיס את אופרטורי הניהול של זיכרון: כדי לענות על השאלה, נניח שיש לנו מחלקה שמייצגת נקודה במרתב דו-מימדי. 6 ++6 ו-009 למתכנת המקצועי המחלקה מוגדרת כך: ]) %ם1סק 01888 ;ץ,א %ם1 ;ו נניח, שאנו מקציס אובייקטיס רביס כאלה בתוכנית. לכל הקצאה של אובייקט כוה שומרת המערכת מידע ניהולי נוסף, כמו למשל גודל אזור הוּיכרון שהוקצא. במקרה כזה, אס אנו מבקשיס הקצאה שמספיקה לשני שלמים, תקצה המערכת זיכרון לשלושה שלמים. באחד מהס תשמור המערכת את גודל אזור הזציכרון המוקצה. בדרך זו יש בואבוז של חמישיס אחוז בכמות הזיכרון! בנוסף לבעיה הקודמת, צריך האלגוריתס להקצאת זיכרון לחפש אזור זיכרון מתאיס לבקשת ההקצאה. אזור כזה חייב להיות מספיק גדול כדי לספק את הדרישה. מאחר וכך, אלגוריתס ההקצאה הכללי יבזבז זמן בכל הקצאת זיכרון, כדי למצוא את בלוק הויכרון המתאים. אפשר לשפר מצב זה, מפני שאנו יודעיס בדיוק את גודל אזור הזיכרון המבוקש. אס נגדיר מאגר זיכרון המיועד למחלקה זו בלבד ובו מספר רב של בלוקי זיכרון, נוכל לצרוך ממנו את מספר בלוקי הזיכרון הדרושיס לנו בכל פעס. אס נוצלו כבר כל הבלוקיס במאגר, נקצה בלוקיס נוספים. מכיון שכל הבלוקיס הס באותו גודל, אין צורך לחפש בלוק בגודל מתאים, ולכן נחסוך זמן חיפוש. בנוסף, בזבוז הויכרון במערכת יהיה קטן יותר, כי מקציס מספר גדול של בלוקים, ומידע הניהול נשמר פעס אחת עבור כולס יחד. כדי להקצות זיכרון מאגר, נלקח הבלוק הראשון הפנוי במאגר, ולכן אין צורך לחפש בלוק מתאים, משוס שכולס באותו גודל! בדרך זו ניתן להקטין את כמות הזיכרון הנדרש מהמערכת, ולהגדיל את מהירות העבודה שלה. ]1 2001 01858 ; צ%קתסת* 08% %תסת611 +0 8126 // ;168126 6ם1 :טס ()81106* ב1ס [;268 מעגמ6%ע ;%א6ם<-%2קחפת = עסקחספת ;2סקתסת = 268* בשנסט ) ;ן כתרגיל, אני משאיר לך להגדיר מחלקה כמו המחלקה 001ע, שמקצה בלוקי זיכרון בגודל קבוע. פרק 5: ירושה ככלי לשימוש חוזר בקוד | 147 [5.3 | ירושה מרובה בסעיף וה נעסוק בירושה מרובה. ירושה מרובה (6118200תת1 10016טוע) היא כזו בה מחלקה יכולה לרשת ממספר מחלקות. בשפות מונחות אובייקטיס אחרות אין תמיכה בירושה מרובה ואכן, בתחילת דרכה לא תמכה בה גס שפת ++6. בירושה מרובה נמצא גם כן סוגי ירושה ציבורית, מוגנת ופרטית, כמו בירושה יחידה. המשמעות של סוגי ירושה אלה היא כמו בירושה יחידה. | 5.3.1 | הגדרת ירושה מרובה כשרוציס להגדיר מחלקה היורשת ממספר מחלקות, יש לפרטן ברשימת הירושה בדומה לירושה יחידה. לכל מחלקה בסיסית יש לציין את סוג הירושה בעזרת אחת ממילות המפתחת: 806טנעק, 0160406זכ ו-10[טטש. נניח, למשל, שיש לנו שתי מחלקות. הראשונה מייצגת רכב ימי בלבד, כגון ספינות או סירות. המחלקה השנייה מייצגת רכב יבשתי בלבד, כגון מכוניות או אופנועיס. כשרוציס לייצג רכב אמפיבי בעזרת מחלקה, אנחנו יודעיס שרכב כזה הוא רכב ימי וגם רכב יבשתי. לכן, המחלקה יירכב אמפיבייי צריכה לרשת מהמחלקה ירכב ימייי ומהמחלקה יירכב יבשתייי. כדי לציין עובדה זו נפרט את הירושות ברשימת המחלקות הבסיסיות (115 ם11181128010ם1) של המחלקה יירכב אמפיבייי. ) 10616ם8%02/6 018588 6 התגות1אאת // שר סת1 :טס [ ;פ = 660ספ5א8ת + (פת %ם1016)1ם₪8%662/6 [ ;806060א8ת םע2660 + ספתסס ()660ס5א8ת 666 6םת1 קז ]) 616נ1ת6הסםת8 018588 התותנ1אאת // שר סת1 :טס [ ;פת = 666ספאה8ת + (פת 6םת10616)1ם0₪762ם18 [ ;8060060א8ת םע26602 + ספתסס ()660ס5א8ת 66 6ת1 ;ו 68 שטנ סנםקתת 01888 ,16 ס1160סטס 8 ++6 ו-009 למתכנת המקצועי ]) 1016ם676םת8 116סטס ו כאשר מגדיריס את המחלקה המייצגת רכב אמפיבי כיורשת מהמחלקה המייצגת רכב ימי ומהמחלקה המייצגת רכב יבשתי, אנו מעניקיס לכל אובייקט מסוג רכב אמפיבי את התכונות של רכב ימי ורכב יבשתי. כלומר, המחלקה רכב אמפיבי תכיל את כל השדות והפונקציות של רכב ימי, ובנוסף לכך, יהיו בה כל השדות והפונקציות של רכב יבשתי. ומעבר לכל אלה, יש לו את כל התכונות הנוספות המיוחדות לרכב אמפיבי, ואשר אינן שייכות למחלקות הבסיסיות. לאובייקט מסוג רכב אמפיבי יש עתה שתי פונקציות בשס ()506606א18 86 שמחזירות ערך שלם. מצב כזה אינו מוגדר, או ברור. כשרוציס לקרוא לפונקציה ()506600א4ג 506 עבור אובייקט מסוג רכב אמפיבי, איוו מהן תיקרא! ;צה 1016ם576גט0ס1מנםסחת צ6נטס1סת8 - 02עע6 //‏ ;()668ס5א8ת 66% .טה8 = 82660 6ם1 1 תמסנבססםט1 בירושה מרובה יכול להיווצר מצב של חוסר ודאות באשר לפונקציות, או שדות בעלי אותס השמות. אפשר להתגבר על כך בצורה הבאה: ; () 88800600 1016.06%ם₪88%6276::ע8 = 50660 במשפט זה אנו מקבליס את מקסימוס המהירות (50060א₪8) על ידי קריאה מפורשת לפונקציה של רכב ימי. הדבר נעשה על ידי אופרטור הבת*רה "::' (ם10ו105010 50076 ), שמציין את המחלקה הבסיסית המבוקשת. דרך אחרת להתגבר על בעיה זו, היא להגדיר פונקציה מתאימה במחלקה היורשת. 68 שטטטנסנםקתת 01885 ) 1016ם076ם8 110סטס ,1016ם8662762ח 116סטס :טס 0% ()660ס5א8ת 96% 6ת1 [ ;()50660א8ת 1016::06%ם076ת28 םעט260 1 0% ()866250000טא8ת 066 6ת1 [ ;()000ק8א8ת 86627621016::066ח םעט260 1 ;ו עתה הגדרנו שתי פונקציות, כשהפונקציה המתחזירה את המהירות המקסימלית מחזירה את המהירות המקסימלית של רכב יבשתי. הפונקציה השנייה מחזירה את המהירות המקסימלית של רכב ימי. פרק 5: ירושה ככלי לשימוש חוזר בקוד | 149 אתחול של מחלקות בסיסיות כאשר הבנאיס של המחלקות הבסיסיות מקבליס פרמטרים, יש להעביר אותס דרך הבנאי של המחלקה היורשת. לדוגמה, אס הבנאיס של המחלקה הבסיסיות מקבליס מהירות מקסימלית, כך: 018855 806761616 ] אהת סת1 :טס [ ;פת = 80660 אהת + (פת 6ם1616)1ם8%6276א ;ו ]) 616נ1ת6סםת8 018588 אהת סת1 :טס [ ;פת = 506060 אהת + (פת %6ם1016)1ם6ע6ת18 ;ן 68 שטטנסנםקתת 01885 ) 1016ם076ם28 110סמטסק ,1016ם8662762ח 116סטס :טס ; (18ת %םת1 ,פטת %ם1016)1ם576ג0ס1סנ1מסחת ;ו (18ת %ם1 ,פחטת %ם1016)1ם576ט10ס1מקחת: :1016ם76פגס נס נםסחת (18ת) 018 1ת6076ם8 , (פחת) 616 1ם2/6 8% ו אנו מעביריס את הפרמטרים למחלקות הבסיסיות ברשימת האתחול של הבנאי במחלקה היורשת. בדוגמה זו מקבל הבנאי של המחלקה היורשת מהירות מקסימלית כאשר הרכב נע ביס ומהירות מקסימלית כאשר הרכב נע ביבשה. ייתכנו מקרים בהס המחלקה היורשת אינה מקבלת פרמטרים מהמחלקות הבסיסיות, ואז עליה לספק נתוניס אלה בעצמה. 0 ++6 ו-009 למתכנת המקצועי ירושה וירטואלית אס המהירות המקסימלית ברכב אמפיבי היא אחת, ואין הבדל בין מצב ימי ומצב יבשתי, אפשר להגדיר מחלקה נוספת (1010ת6) שתתאר את המושג יירכביי בצורה הכללית ביותר. במקרה זה נגדיר את המחלקות הבאות: 018588 761016 ) אהת סת1 :טס [ ;8 = 80660 אהת + (8 6ם1016)1ם76 [ ;5850060 א8ת םע26602 + ספתסס 660)0ס5א8ת 666 6ם1 ;ו ]) 761016 110סטמסם : 1016ם8%6276ח 01855 2 ] 761016 110סוסק : 1016ם076ם28 01855 3 68 טנס נםקתת 01888 ]) 1016ם676םת8 110סטס ,1016ם866276ח 116סטס ו במקרה זה קיבלנו גרף ירושה, שבו לכל אובייקט מסוג רכב אמפיבי נקבל חלק השייך ל-611616/ פעמיים. כלומר, שתי מהירויות מקסימליות לרכב אמפיבי, למרות שאנו זקוקיס לאחת בלבד. 6 | 6 | 6 6 ] 6 8/6 [ | 6 6נ וקו 6נ וקו איור 5.2: ירושה מרובה רגילה ווירטואלית פרק 5: ירושה ככלי לשימוש חוזר בקוד | 151 איור 5.2 מתאר בחלקו השמאלי את המצב שתארנו. המחלקות השונות מצוירות כמלבניס שבמרכזס מופיע שם המחלקה. חצ בין שתי מחלקות מסמן יחס ירושה, שכיוונו מהמחלקה היורשת אל המחלקה הבסיסית. בחלקו השמאלי של האיור אנו רואיס שלאובייקט מסוג רכב אמפיבי יש שני חלקים המציינים אובייקטיס שעובריס בירושה מרכב ימי ומרכב יבשתי. בחלקו הימני של האיור אנו רואים מופע יחיד בגרף הירושה של המחלקה רכב. דבר זה קורה כאשר מגדיריס ירושה וירטואלית. כדי לבטל כפילויות כאלו בגרף הירושה, משתמשים בירושה וירטואלית. כאשר נוסיף את מילת המפתח [6%04]צ ברשימת המחלקות הבסיסיות, לשתי המחלקות 6 0 ו-1.800/01016, מצב זה לא יקרה. לכל אובייקט של רכב אמפיבי יהיה רק חלק אחד של רכב. בדרך כתיבה זו, לכל אובייקט רכב אמפיבי תהיה מהירות מקסימלית אחת. ]) 761016 110סטס 81ט1260ט : 1016ם8%6276א 01855 2 ] 761016 110סטס 126081ט : 1016ם076ם28 01855 ;ו 68 טנסנםקתת 01888 ) 1016ם076ם8 110סמטס ,1016ם8662762ח 116סטס ;ן כדי לפתור מצב זּה, נעביר את הירושה לירושה וירטואלית של שתי המחלקות (61616 80077 1.806/621016) היורשות מהמחלקה הבסיסית (67621686). מחלקה זו (61010י) מופיעה יותר מפעס אחת בגרף הירושה. המחלקה הבסיסית שמופיעה מספר כפול של פעמיס בגרף הירושה, תופיע עכשיו פעס אחת בלבד. במקרה זה, המחלקה רכב היא המחלקה הבסיסית הווירטואלית (01855 0856 |גטזוט). פעולה זו פתרה גס את בעיית אי הוודאות וההבחנה בין שדות (או פונקציות) כפולים הנגרמיס כתוצאה מירושה מרובה. אפשר להחליף את הסדר בין מילות המפתח [4ט!זוץ ו-סו1סטק. אתחול במצב של ירושה וירטואלית ראינו שהמחלקה היורשת אחראית לאתחול הבנאי המתאיס של המחלקה הבסיסית. דבר וה נכון גס בירושה וירטואלית. אבל כשיש מחלקה אחרת, היורשת מהמחלקה היורשת, אחראית המחלקה היורשת האחרונה לאתחול המחלקה הבסיסית הווירטואלית. אחד הכללים של ירושה וירטואלית הוא, שהמחלקה היורשת ביותר (6671700 1086 8 בגרף הירושה אחראית לאתחול המחלקה הבסיסית הווירטואלית. בדוגמה של 2 ++6 ו-009 למתכנת המקצועי היררכיית הרכבים אחראית המחלקה רכב אמפיבי לאתחול של המחלקה רכב, למרות שהמחלקות רכב ימי ויבשתי מאתחלות אף הן את המחלקה הבסיסית. יתרה מזאת, אס המחלקה היורשת הנמוכה ביותר בגרף הירושה לא תאתחל את המחלקה הבסיסית הווירטואלית, נקבל שגיאת הידור כאשר נגדיר, למשל, אובייקטיס מסוג רכב ימי או יבשתי. כדי להמחיש חוקיס אלה נתבונן בדוגמה הבאה: <ת.ת108%268> 61066ת1+ ) 761016 018588 אהת סת1 :טס [ ;08 = 506606 אהת + (פת 6ת1616)1םס7 [ ;80060 אא תעט0ס6ע + 00286 ()060כ5850 אהת 66 6ת1 ;ו ]) 761016 110סמטס 81ט1260ט : 1016ם8%6276א 01855 :טס [++ (1016)05ת76 : (פת %םת1016)1ם8%6/6ח ] 761016 110סטס 126081ט : 1016ם076ם28 01855 [+) (5פת)1016ת076 : (פת %6ם1616)1ם076ם18 7 ס116טס : 1016ם876ט10סמ1תקתת 01888 ]) 1016ם076םת8 116סטס :טס , (8ת) 761016 : (פת %ם1016)1ם576ט0ס1קנמסחת (10616)0ם8%62/6ח₪ , (1616)0ם076םת18 ל רכב אמפיבי היורש מרכב ימי ורכב יבשתי, מאתחל את הבנאי של רכב, כי הוא המחלקה היורשת ביותר בגרף הירושה. כלומר, וו המחלקה הנמוכה ביותר בגרף הירושה ושממנה לא יורשת מחלקה אחרת. האתחול האחרון נראה אולי מיותר בדוגמה זו, מכיון שהבנאיס של מחלקות אלו רק מאתחלים את הבנאי של המחלקה רכב. במקריס רביס אחרים יהיו למחלקות היורשות בדרג הבינייס, שדות נוספיס שהן מאתחלות. המהדר מתעלס מהאתחול של המחלקה הבסיסית הווירטאולית (61855 0886 |פגזוע) שנעשה במחלקות הביניים במקרה זה, המחלקות רכב ימי ורכב יבשתי, עבור אובייקטיס מסוג רכב אמפיבי. פרק 5: ירושה ככלי לשימוש חוזר בקוד ‏ 153 (ט8 7621016 008% ,800% ת6020628802>>)05%208 מ(05%6268ס 6ם11םת1 ָ ;(()850600 אהת 76%6.ט >> "=50060 אאת" >> סטס) מעג6ס6ע ()מ1נהת %ם1 ; (87)90 1005761016 נםסחת ; (50) טש 1016םת₪8662/6 ; (89)ט1 10616ם0₪76םת18 טה8 >> ":פטסנ1נסנםקתת" >> סגוסס טט >> ":8062ח " >> ;1 >> ט1 >> ":בם8 " >> 7 תעגו6%ץ התוצאה של התוכנית שלפנינו חיא : 0 אַת:8662ח 50660-90 אהת:פגוסנס נמסחת 9 אהת:0ת18 אתחול הבנאי של רכב אמפיבי שולט על ערך המהירות המקסימלית. אולס, כאשר הוגדר אובייקט מסוג רכב ימי, שלט אתחול הבנאי של רכב ימי, וכשהוגדר אובייקט מסוג רכב יבשתי שלט האחרון על ערך המהירות המקסימלית. סדר בנייה ופירוק של אובייקטים במקרה של ירושה מרובה (07118206החו 11016טוגת) בין אובייקטיס, צריך לשמור על סדר האתחול של תת-האובייקטיס המרכיבים אובייקט מורכב. באופן דומה (אך הפוך) צריך לשמור על סדר לפירוק אובייקטיס. בסעיף זה נלמד על סדר הבנייה והפירוק של אובייקטים במצב של ירושה. סדר בניית אובייקטים כאשר יש אובייקט של מחלקה יורשת (למשל, רכב אמפיבי) נבניס תת-האובייקטיס שיוצרים אובייקט כזה, מהמחלקה הבסיסית ביותר למחלקה היורשת ביותר. תחילה מופעל בנאי המחלקה הבסיסית ביותר, ולאחר מכן הבנאיס של המחלקות היורשות. בסוף התהליך מופעל בנאי המחלקה היורשת ביותר. סדר הפעלת הבנאים ובניית האובייקטיס ממחלקה בסיסית למחלקה יורשת נכון, פרט למקרה של ירושה וירטואלית. בירושה וירטואלית נקראים בנאי המחלקות הווירטואליות לפני כל בנאי אחר, ורק לאחר מכן נקראים בנאי המחלקות הבסיסיות. בסוף התהליך מופעליס בנאי המחלקות היורשות. 4 ++6 ו-009 למתכנת המקצועי כאשר מחלקה יורשת ממספר מחלקות, יש סדר קריאה לבנאי המחלקות הבסיסיות. הסדר בין המחלקות הבסיסיות הוא לפי סדר הגדרתן, משמאל לימין. אם כל עניין הבנאיס וסידורי הבנייה נראה מסובך, אל דאגה, נראה דוגמה מפורטת בהמשך פרק זה שתבהיר את כל אי ההבנות. סדר פירוק אובייקטים בעיקרון, סדר פירוק אובייקטיס הפוך לסדר בנייתם. תחילה מפורקת המחלקה היורשת ביותר, ולאחריו המחלקות הבסיסיות יותר. לפיכך, נקרא תחילה המפרק של המחלקה היורשת ביותר, ולאחריו נקראיס המפרקיס של המחלקות הבסיסיות יותר. סדר ההפעלה של המפרקים הוא כזה: תחילה, מפרקיס של מחלקות יורשות ולאחר מכן - מפרקיס של מחלקות בסיסיות. סדר זה נכון פרט למקרה של ירושה וירטואלית. בירושה וירטואלית ייקראו המפרקיס של המחלקות הבסיסיות הווירטואליות (11₪81 8 0886) לאחר כל המפרקיס האחרים. כשמדובר בירושה מרובה שבה יש מספר מחלקות בסיסיות לאותה מחלקה, סדר הפירוק של המחלקות הבסיסיות הוא מימין לשמאל על פי הסדר ברשימת המחלקות הבסיסיות. סדר זה הפוך לסדר הבנייה. דוגמה לסדר בנייה ופירוק של אובייקטים כדי להמחיש את החוקים שתארנו, נוסיף למערכת ההיררכיה של רכביסם שורש נוסף. נוסיף מחלקה בסיסית שתייצג י'יאובייקט ימייי ((9061700/) כלשהו. לאובייקט ימי כוּה יש תכונה המגדירה באיזה לח מקסימלי הוא יכול לעמוד ולאיזה עומק מתחת לפני המיס הוא יכול לרדת. נגאור את המחלקה רכב ימי מהאובייקט הימי הבסיסי. בכל בנאי ומפרק נוסיף הדפסה המתארת את שס הבנאי, או המפרק. כך נוכל לראות מתי נבנה, או מפורק אובייקט, ואת הסדר של האובייקטים השונים. 01855 ₪8%6200( ] 5562 עס אהת 6ת1 :טס (עת %ם1) כ₪8%66200 [ ;01ם6 >> "ך866200חא" >> סטסס ;קת = 265858026 את ] () כ66200 ₪88 [ ;061ת6 >> "7ך866200א-" >> ס6טסס ] ;ו 018588 761016 ) ;0 אהת סםת1 :טס פרק 5: ירושה ככלי לשימוש חוזר בקוד 155 (8ת %ת1016)1ם76 [ ;01ם6 >> "1016תפט0" >> סטסס ‏ ;8ת = 50660 אאת ] ()1616ם76- [ ;01ת6 >> "407821016" >> סטסס + [ ;5806060 אהת ת2ט6%ע2 + 0086 ()506060 אהת 666 6םת1 ;ו ,8566200 110סטסק : 1016ם8662762ח 018588 ]) 1016ם76 110סגמס 81מ6ע נט :טס (8ת)1016ם6ט , (55) כ866200א : (פת 6ם1016)1ם8%62/6ח [ ;01ם8 >> "1016ם8602/6ח" >> סטסס + () 1016ם08662/6- [ ;01ת6 >> "1016ם08%02/8>-" >> 6טסס + 02 ] 761616 110קטס 81ט6ת1ט : 1016ם076ת28 01899 :טס (8ת)1016ת76 : (פת %ם10616)1םת676ת18 [ ;01ת8 >> "1016ם676ת8" >> 6טסס ]1 ()10616ם676ת8/- [ ;01ם8 >> "1016ת006םת8-" >> סטסס + ;ו 6 ,86627621016ח 110סטס : 1016ת6ע5ט0ס1סנםקתת 01855 ]) 1807621016 :טס , (8ת) 7621016 : (פת %ם1016)1ם576ט0ס1קנםמסחת (10616)0ם8%62/6ח₪ , (1616)0ם0076םת18 [ ;01ם6 >> "1016תפטפטסנסנםקתת" >> 0006 ]1 () 016 1ם576גוס בס בםסחחת = [ ;601 >> "118סםת6טפטס1סנ1םקתת-" >> 6ט00 ) ;ו ()מגנאת 6ם1 ; (90)ט8 1016ם576גו0ס1ס1נםקחת 02 םעגו6%ע2 פלט תוכנית זו ייראה כך: 6 [₪8%66200 6 16 68 טס בס 1 סחחת 6 ++6 ו-009 למתכנת המקצועי 6שטפטטט ב בם סחת = 6 6 [08%66200- 6 תחילה נקרא הבנאי של המחלקה יירכביי (61168/). דבר זה קורה משוס שרכב היא מחלקה בסיסית וירטואלית. ואס לא כן, היה נקרא הבנאי של אובייקט ימי לפניה (כי הוא מופיע ראשון משמאל על רשימת המחלקות הבסיסיות של רכב יממי). כמו כן, ניתן להבחין כי הבנאי של רכב ימי נקרא ראשון ולאחריו הבנאי של רכב יבשתי (שכן האחרון מופיע לימינו של רכב ימי על רשימת המחלקות הבסיסיות של רכב אמפיב. לבסוף, נקרא בנאי מחלקה הבסיסית ביותר, יירכב אמפיבייי. בפירוק ניתן להבחין שהמפרק של רכב אמפיבי נקרא ראשון (שכן ו המחלקה היורשת ביותר). לאחר מכן, נקרא המפרק של רכב יבשתי (שכן הוא מופיע מימין לרכב ימי ברשימת המחלקות הבסיסיות שמורישות לרכב אמפיבי). אחריו נקרא המפרק של רכב ימי, ואחריו נקרא המפרק של אובייקט ימי. לבסוף, נקרא המפרק של רכב (שהרי רכב היא מחלקה בסיסית וירטואלית). אם המחלקה רכב לא היתה מחלקה בסיסית וירטואלית היה נקרא המפרק שלה לפני המפרק של אובייקט ימי, מפני שהיא מופיעה לימינו של השס האחרון ברשימת המחלקות הבסיסיות של רכב ימי. | 5.5 | המרות בפרק וה ראינו שהמהדר עושה המרות (פמסופע6/מסט), כדי להתאים בין סוגיס של משתנים לסוגיס מבוקשיס של משתניס. המרות אלו מתרחשות בקריאות לפונקציות, או בהשמה של משתנים. המרות שונות עשויות לגרוס לאובדן מידע, או שיכולה להתבצע פעילות לא צפויה. לכן, חשוב לדעת אילו המרות מתבצעות. ההמרות מתחלקות להמרות סטנדרטלות (5ת07%10ת60 51820870) המוגדרות בשפה, והמרות המוגדרות על ידי המשתמש (פמסופזס/ת 00 06ה6611 זס8ט). המרות של סוגים בסיסיים בהמרות של סוגיס בסיסיים מומריס ערכי משתניס בסיסיים לערכים בסיסיים אחריס. למשל, המרה משלס לתו היא המרה שעלולה לגרוס לאובדן מידע, כי מיגוון הערכיס של שלמים גדול יותר מתחוס הערכים של תו. באופן דומה, המרה של משתנה ממשי למשתנה שלם עלולה לגרוס גס היא לאובדן מידע. מ8610ת?ס+ת1 0% 1088 // ;ך = 6 מַ8ם60 5 --> [ - %0ם1 0% 1088 // ;א = [ פרק 5: ירושה ככלי לשימוש חוזר בקוד ‏ 157 בשתי ההמרות שעושה המהדר עלול להיות אובדן מידע. הערך של [ גדול מערך של תו, ולכן הוא אינו יכול להיכנס למשתנה מסוג ז348ת0. הערך של 6 אינו מוגדר לאחר ההשמה. הערך של [ לאחר ההשמה הוא 5. במקרה זה יש אובדן מידע. המרות כאלו נעשות גס כאשר יש קריאות לפונקציה עס ארגומנטיס לא מתאימים. לדוגמה, פונקציה המקבלת שלם: (8< %ם1)ע6חסק 6ם1 [ ;א * א םתעגמ66ת ] ;(2.5)ע6חסס = א 11086 הערך 2.5 מומר לערך שלס בעת הקריאה לפונקציה זסשסכ, והערך המתקבל במשתנה א הוא 4. במקריס כאלה יש מהדריסם המוציאיס הודעת אזהרה, ואילו אחריס ממיריס ללא כל הודעה. המרה מסוג ה היא המרה בסיס*ית (מס1פזסטםסס 08810) של השפה, או המרה סטנדרטית. המרות של מחלקות המרות אחרות הן בין מחלקות, כאשר אובייקט של מחלקה יורשת יכול להופיע בכל מקוס שיש בו התייחסות לאובייקט של מחלקה בסיסית. כשיש שימוש באובייקטיס יורשיס עבור קוד המטפל באובייקטים בסיסיים, יכולה להיות המרה המאבדת מידע שנקראת חיתוך אובייקטים (8110128 00[60%), או המרה שאינה מאבדת מידע. חיתוך אובייקטים חיתוך אובייקטים קורה, למשל, כאשר משימים אובייקט יורש לאובייקט בסיסי. במצב כזה האובייקט היורש מומר לאובייקט בסיסי והתכונות הנוספות שלו אובדות (מכאן המושג ייחיתוך'י). למשל: ] 2886 0188585 ;א %ם1 ;ן ] 2886 110סטק : 6ט1ע6כ 01885 ;ץ 6ם1 8 ++6 ו-009 למתכנת המקצועי 81101 007606 // 7 = ס עסעץ6 116%קחסס 8 // ;כ = 6 ההשמה של 4 ל-0 מעבירה לאובייקט הבסיסי רק את התכונות שקיימות בחלק של האובייקט הבסיסי באובייקט היורש 4. ההשמה ההפוכה מאובייקט בסיסי לאובייקט יורש אסורה, ותגרוס לשגיאת הידור. ההמרות יכולות להיות גם כתוצאה מקריאה לפונקציה. המרות מאובייקט יורש לאובייקט בסיסי הן המרות סטנדרטיות. המרות של מצביעים או ייחוס המרה של מצביעים (תסופזסטת00 זס)מוסק), או ייחוס ממחלקה יורשת למחלקה בסיסית, נחשבת להמרה סטנדרטית. המרה מסוג זה אינה מאבדת מידע. לדוגמה: 176ע6כק 2 = סס* 2886 (ע%קע* 5)285856 1סט ] (עפ6 6)2856 1%בסט עש6פת1סק 28886 0 מסנפעסטתסס 0826ת868 // ; (1)688 6 ס0ם 06ם6ע6169ע2 8 ₪0 תס1פע6טםתסס 0820ם368 // ; (9)08 המרת כתובת של מחלקה יורשת למצביע למחלקה בסיסית, נעשית באופן אוטומטי על ידי המהדר. גם המרה של ייחוס לאובייקט יורש לייחוס לאובייקט בסיסי, נעשית בצורה אוטומטית, לכן הקריאות לפונקציות + ו-₪ הן חוקיות. ההמרה ההפוכה, ממצביע למחלקה בסיסית למחלקה יורשת, אינה נעשית בצורה אוטומטית, והמתכנת צריך לדרוש אותה בפירוש. אס המתכנת אינו משתמש בהמרה מפורשת בקוד ממצביע בסיסי למצביע יורש, יסמן המהדר את שורת הקוד המתאימה כשגיאה. המרה נוספת, המתבצעת באופן אוטומטי על ידי המהדר, היא המרה ממצביע כלשהו למצביע מסוג 6וסצ. המרות המוגדרות על ידי המשתמש המוות מוגדרות על ידי המשתמש (פחהסופז6טחס6 06060 ז050), או המרות משתמש, מוגדרות על ידי המתכנת להמרה בין סוגי אובייקטים שונים, או בין אובייקטיס לסוגיס בסיסיים. המרות אלו אינן נחשבות להמרות סטנדרטיות של השפה. הן תוצאה של הפעלת בנאי, או אופרטור המרה. הנה דוגמה: פרק 5: ירושה ככלי לשימוש חוזר בקוד 159 5 + 018858 8% ) :טס א 50 6ם1 מסע+ תס1פפצסטתסס // ; (8 6ת1)א %ת1 60 א% מסע+ תס1פעפטתסס // ; () %ת1 860%ע6קס צ ס6 א% מסע+ םתס1פעפטםתסס // ; ()צ עססהַע6סס (ץצ צ)5 ב1בסט ] %7ך .1% ;א 8 .א = ץ (1) 7-5 ;א = ץ צ ;((ך)א)5 סם 6811 (2) // ;(ר)5 בדוגמה זו, ממיר המהדר את האובייקט א לאובייקט מסוג צ, לצורך שורת ההשמה הראשונה (1). ההמרה נעשית באופן אוטומטי, על ידי שימוש באופרטור ההמרה המתאיס של המחלקה א. בשורה השנייה (2) נעשית ההמרה של השלם לצורך התאמה לארגומנט של הפונקציה לאובייקט מסוג א, בשימוש בבנאי המתאיס של א. סדר ההמרות כדי למנוע אי ודאות, מוגדרות עדיפויות בין ההמרות השונות. המהדר רשאי לבצע מספר אינסופי של המרות סטנדרטיות והמרת משתמש זו המוגדרת על ידו. ההמרות נעשות כדי להתאים משתנים לארגומנטים של פונקציות, או בעת השמות בין משתנים, או ערכים המוחזרים מפונקציות. עדיפות ההמרות מוענקת להמרות סטנדרטיות, ולאחר מכן להמרות המוגדרות על ידי המשתמש. האלגוריתס המעשי להמרות הוא כזה: + אם המשתנים הס בסיסיים (אינם אובייקטים) ולא מתאימים, נסה להמירס לערך שלם. * המר מצביעים למצביע מסוג נסץ. * המר מצביעים, או ייחוס של מחלקות יורשות, למצביעים, או ייחוס, של מחלקות בסיסיות. 0 ++6 ו-009 למתכנת המקצועי > השתמש פעסם אחת ויחידה בהמרה שהוגדרה על ידי המשתמש. כאשר יש שתי פונקציות, או יותר, המתאימות לקריאה, מועדפות הפונקציות בהן יש פחות המרות ו/או עס המרות סטנדרטיות. לדוגמה: 61258 > ]) 2856 110סטס : % 01858 :טס [+ ()א צ 60 מס1נפעסטתסס // ;()+ ע860%ע6קס ;ו (1) // ; (ע65 1)2886 18סעש (2) // ;(ץ צ)5 16סעט ;א א ;(6 5)2886 ₪811 // ; (5)8 בדוגמה זו תקבל הפונקציה הראשונה עדיפות, ולכן תקרא הפונקציה המסומנת ב-(1). ההמרה ל-צ מ-%א נמצאת בעדיפות נמוכה יותר, ולכן לא תתבצע. סיכום בפרק זה למדנו על מושג הירושה ב-++6. ראינו שיש מספר סוגי ירושה ומספר רמות גישה בירושה. יש ירושה מרובה וירושה יחידה, כשלשני סוגי ירושה אלה יש מספר רמות גישה. רמת הגישה הפרטית שקולה להכלת אובייקטים. דהיינו, שקולה להכנסת האובייקטים הבסיסיים בחלקו הפרטי של האובייקט היורש. השדות הציבוריים הופכיס לשדות פרטייס, כך שלשדות אלה אין גישה למשתמשיס במחלקה היורשת. בירושה מוגנת הופכים השדות והפונקציות, המוגניס והציבוריים, למוגניס במחלקה היורשת. לכן, לא יכול המשתמש במחלקה היורשת לגשת לשדות והפונקציות הציבוריות במחלקה הבסיסית. הפונקציות והשדות הציבורייס של המחלקה הבסיסית בירושה ציבורית, ציבוריים גס במחלקה היורשת. לכן, יכול המשתמש במחלקה היורשת לגשת לפונקציות של המחלקה הבסיסית. בירושה מרובה, המחלקה יורשת ממספר מחלקות. הדבר גורס לכפילות של מחלקות בגרף הירושה, וכתוצאה מכך לבעיית הבחנה בין שדות והים של אותה מחלקה בסיסית המופיעים פעמיים. הפתרון לבעיות מעין אלו ב-++6 הוא להגדיר את המחלקה הבסיסית כמחלקה וירטואלית בסיסית, וכך דואג המהדר שהמחלקה הבסיסית תופיע פעס אחת ויחידה בגרף הירושה. פרק 5: ירושה ככלי לשימוש חוזר בקוד ‏ 161 - 7 | שאלות .10 הוסף מחלקה עובד (66ע10קותת) למחלקות ת80ז6ע, 10105501 ו-1מ50166. דאג לכך שמחלקה זו תירש מ-מספזסע. כמו כן, הכנס את המחלקה עובד כמחלקה בסיסית של פרופסור. הוסף למחלקה הבסיסית עובד שדה המתאר את מספר שעות העבודה החודשיות שלו. הוסף מחלקה נוספת, מזכירה, להיררכיה מהשאלה הראשונה, היכן תוסיף מחלקה זו בגרף הירושה: הוסף מחלקה, המייצגת מתרגל, שהיא גס סטודנט וגס עובד, האס יש בעיות של כפילויות בגרף הירושה? הגדר מחסנית בעזרת רשימה בשימוש בפונקציות| אחרות מ-561ם1 ו-1080 610/6ע. הגדר תור בעזרת פונקציות אחרות מ-6מסקקג ו-1080[ 6טסנמסז. הגדר תור דו-כיווני בעזרת הרשימה וירושה פרטית. הגדר רשימה מעגלית מקושרת יחידה. בשימוש ברשימה שהגדרת בשאלה הקודמת הגדר תור ומחסנית. האס השתמשת בירושה ציבורית, מוגנת או פרטית! הגדר איטרטור לרשימה המקושרת הקודמת. מה עליך לעשות כדי להכניס אובייקטים מסוג מ80ז6/ לרשימה זוז הגדר מחלקה 2001 המאפשרת לנהל זיכרון בגודל קבוע. למחלקה זו יש פונקציה של הקצאת בלוק, ופונקציה של שחרור בלוק. כשאין למחלקה זיכרון פנוי, היא מקצה מספר רב של בלוקים מהמערכת. מספר הבלוקיס המוקצה הוא פרמטר של המחלקה. 2 ++6 ו-002 למתכנת המקצועי פרק 6 פולימורפיזם בפרק וה נלמד על המושג פולימורפיוס. פולימורפיזם (ו8וםקזסנתץ1סק) פירושו רב-צורתיות, שמשמעותו: אובייקט מסוים יכול ללבוש צורות רבות. פולימורפיוס ממומש ב-++6 בעזרת פונקציות וירטואליות, ולכן מושגיס אלה הס שמות נרדפים ב-++6. המושג פולימורפיום, בצירוף ירושה ומחלקות, הוא למעשה, התמצית של תכנון ותכנות מוכווני אובייקטים. בשפות רבות נמצא שמחלקות, ירושה ופולימורפיוס הס מקניס להם את הי'יזכות'י להיות מוגדרות כשפות תכנות התומכות בתכנות מוכוון אובייקטים. ב-++6 יש מבניס נוספים, שאינס קשורים לתכנות מוכוון אובייקטים, אך הופכים את השפה לאטרקטיבית מאוד. נבחן נושאיס אלה לעומקס בהמשך. דוגמה - הדרך הישנה כדי להמחיש את התועלת והחשיבות של המושג פולימורפיזם, נפתח פרק זה בדוגמה שאינה משתמשת ביכולת זו. הדוגמאות לפולימורפיזס מופיעות בקבציס ק1.60ממץ001, קק2.6וץ1סכ, קק3.6מץ001. הקובץ הראשון הוא הדוגמה הראשונה והאחרים הס דוגמאות לשימוש בפונקציות וירטואליות, כפי שמוסבר בסעיפים הבאים. נכתוב תוכנית שתצייר צורות על המסך, ונעשה ואת כמובן בשפת ++6. נגדיר מחלקה ת50766 שתייצג את המסך ולתוכה נוכל לצייר נקודות. נסביר זאת בהמשך. נניח, שיש לנו שתי צורות, קו (סחו1) ונקודה (וםוסכ). פרט לציור הצורות על המסך נרצה לשמור את הצורות בקובצ, כדי שנוכל לחזור ולשנות אותן בעתיד. נחזיק את הנתוניס בקובץ במבנה רשימה. כשנרצה לפעול על הצורות, נעבור על הרשימה, נבחר את הצורה הרצויה ונבצע את הפעולות הדרושות. פרק 6: פולימורפיוס | 163 הגדרת המסך המחלקה 50766 תייצג את המסך. זו מחלקה פשוטה מאוד שמחזיקה מערך של תוויס המייצג את המסך. בחרתי אמצעי ציור פרימיטיבי כזה, משוס שהדגש אינו על הציור עצמו, אלא על הצגת עיקרון עבודה עס מספר צורות והקושי לעשות ואת ללא שימוש בפולימורפיזם. כאשר רוציס לצייר נקודה, שמה המחלקה 50766 תור '*יי, המייצג נקודה. בהגדרת המחלקה יש נתטות6 המייצג את גודל המסך. וזטמס, במקרה זה, מחליף קבועיס אותס יכולנו להגדיר בתחוס הגלובלי של הקובצ. החיסרון של הגדרה כזו היא בזיהוס של מרחב השמות הגלובלי. כאשר הקבועיס מוגדריס כ-מטמ6 בתוך המחלקה, לא קיימת סכנת התנגשויות בין שמות. ) ת502066 01858 ;[ 77 = 018סם ,21 = פחסעם + תגותס ; [0018ת] [פאספם] 08%68 םס :טס [ ;()01682 + ()ם50266 ; () 01682 ב1סט ;(ץ %ם1 ,א סםת6)1טס פנסט ; () 028% ה1סט לן המערך 08/8 מייצג את המסך כמערך כפול. הפונקציה 61681 ממלאת בתווים ריקים את המערך 68% שמייצג את המסך. כשמוגדר אובייקט מסוג 50260 נקראת פונקציה זו בבנאי האובייקט ומנקה את המסך. ()01082::ת50266 הנ1בסט (++2 ;פחסעם>2 ;2=0 %ם1) 1058 (++0 ;0015םת>0 ;0=0 מם1) ע0%ס1 ;' ' = [6] [%]38%8 ] הפונקציה )וטק מכניסה את הערך "*" למקוס 68%8, במקום שנתון על ידי הקואורדינטות (ע,א). קואורדינטות אלו הן הארגומנטים המועברים לפונקציה. לפני שינוי הערך בנקודה המתאימה במערך נבדק האינדקס, כדי לדעת אם הוא בתוך המערך. (ץ %ת1 ,א %6ם5)1טק::ת50260 %נ1בסט (0 =< ץ 66 פשסעם > ץ 66 0 =< א 88 018סם > א) 15 [ ;'*' > [א][ץ]0868 ] כדי לצייר את המסך עובריס על כל השורות ועל כל העמודות במערך ושולחיס אותס לפלט הסטנדרטי. 4 ++-+6 ו-009 למתכנת המקצועי () 0280::ת50266 ב1בסט ] (++ע ;פחסעם>ע2 ;2=0 6ם1) ע0+ (++0 ;0018ם>0 ;0=0 6ם1) 102 ;[0] [%]08%8 >> 6גו00 ; 0[1ת6 >> סגטסס ] הגדרת הצורות לצורך הגדרת הצורות נשתמש ברשימה הכפולה, מהפרקים הקודמים. עלינו לגזור את המחלקות שלנו מהצומת שברשימה. נגדיר מספר מחלקות, כדי לאפשר מספר צורות ברשימה. נגדיר את המחלקה 51406 כך שתאפשר לנו לגשת לשדה 06ע1 ולהפיק מכך את הצורה הנוכחית. אס אינך מבין גאת כעת, אל דאגה, הדוגמה תבהיר זאת. ;[ 6ת11 ,6תנ1ססק + 6סעץ6 6ק8ם5 תגותס ] אםת11 110סטס : סַכאם5 06גע56 ;6סץ5 6סץם סק8ם5 ;ו נגדיר שתי מחלקות (מוס2, 6ם11) שלהן יש את סוג הצורה בשדה הראשון. כל המחלקות שצריך לצייר, צריכות להגדיר את סוג הצורה בשדה הראשון. נשתמש בשדה זה כדי להבדיל בין סוגי הצורות השונות ברשימה. המחלקה +מוסע מייצגת נקודה. לכל נקודה יש קואורדינטות המתארות את מיקומה. כדי לצייר נקודה על המסך יש להשתמש בפונקציה +טק, לפי הקואורדינטות הנתונות שלה. ] אםת11 110סמטס : %םנסקע 01888 ;6סץ5 6סץם סס8ם5 ;ץ,א %ם1 :טס [ ;סץ=ץ ;סא =א + (6םנ1נסק)6סץם : (סץ 126 ,סא 6ם1)פ>םתנ1סק (ע6802 מם50266)א8428 ה1בסע [ ;(ץ,א)פטס.ת80 + ;ו המחלקה 1.186 מייצגת קו ישר. יש לה שתי נקודות קצה המייצגות את הקו. ] א%ם11 110סמטס : 6ם1ם 01855 ;6סץ5 6סץם 6ס8ם5 ;1ץ ,1א 6ם1 22 ,2א 6ם1 :טס פרק 6: פולימורפיום | 165 (02סץ פ%ת1 ,02א %ם1 ,1סץ סםת1 ,01א 6מם6)1םת1ת (6ם11) ססץ> [ ;2סץ = 2ץ ;02א = 2א ;1סץ = 1ץ ;01א = 1א + ; (8802 מם50266)א8428 ב1בסע ל ציור הקו מסובך יותר מציור נקודה, כי הוא מסתמך על המשוואה הבסיסית של קו במישור: 5+ א*8 = ע 8 מייצג את שיפוע הקו ו-5 מייצג את הקבוע שלו. כתוצאה מחישוביס אלה אנו עלוליס לקבל מספר שאינו שלם, ולכן הפונקציה +ת1 138%6 מעגלת עבורנו מספר ממשי למספר שלם. (3 6)8400016ם1 6אהת 6ת1 | ; (5. 8+0) %6ם1 תע660ץ ו כאשר נתון קו, ייתכן שערך א של שתי נקודות הקצה שלו זהה. במקרה זה, אין שיפוע לקו, ואז מצייריס את הקו על ה-א הקבוע בין שתי נקודות ץ שלו. הו החלק של 6186 פונקציית הציור של הקו. במקרה השני, מצייריס את הקו לפי משוואת הקו. (ע680 תם68ע502)ח028%::פת1ם בנ1נסע ָ ; (2א : 1א ? 2א > 1א) = מנתא %ם1 ;(1א : 2א ? 2א > 1א) = אהתא %ם1 ]) (2א =! 1א) +15 ספ + א * 8 = ץ // ; (1א - 2א)8600016 / (1ץ - 16)2כגסב 8 16סגוסף 2א* 8 - 1ץ = ס 400016 ] (++1א ;א8תא => בא ;תנתא = בא 6ם1) 0+ ;ם + 8 * 1א = ץ 400016 ;((ץ)6ם1 6א8%ת ,1א)ס6טס.502 ו ] 0186 ;אהחץ ,תנחתץ %6ם1 ) (2צ > 1ץ) 12 ;1 = מתנתץ ; 2ץ =אהחץ ] 1-6 2 = תנתץ ;1 = אהחץ 6 ++-+6 ו-009 למתכנת המקצועי (++ץ ;אאחץ =>ץ ;תנחתץ = ץ 6ם1) 0+ ;(ץצ ,1א)502.006 הגדרת הפונקציות והפעולות מספר פונקציות מטפלות בצורות השונות. הראשונה, היא וו העוברת על רשימת הצורות ומציירת אותן. היא עוברת על רשימת הצורות הנתונה לה, בוחרת את האובייקט לפי סוג הצורה הנתונה, ומבצעת המרה של המצביע לאובייקט המתאיסם. לאחר ההמרה לאובייקט המתאים, אפשר להשתמש בפונקציית הציור של האובייקט. פונקציה וו חייבת להכיר את כל סוגי הצורות הנמצאים ברשימה. כאשר מוסיפיס צורה חדשה, יש לשנות פונקציה וו בהתאם, כך שתטפל בצורה אחרת. (ע680 תם606ע502 ,689118% 118%)א328 ב1סע ז ;()ם601כ8118%.0 = 1 166% 1186 ; ()502.01682 + (()0ם81158%.6 =! 1) 16ג1תט ; ב* (*06ק8ת5) = ס5* סַקַם5 ;סק* %ם1סק ;ס1* 6םת1ת1 ) (6סץ5<-50) ב160שפ5 :1 08856 ;ספ (*פם1סע) = סס ; (502) א628%<-סס ;28% :מ 08856 ;2 (*6ם1ת) = ס1 ; (802) ש628<-10 ;68%עס :1 ;268% ] ; ב++ ] ; () 028₪. 502 ו בדומה לפונקציה א4:8, תהיינה לנו פונקציות שכותבות, או קוראות, אובייקטיס מקבציס. כל פונקציה כזו צריכה להכיר את כל סוגי האובייקטים, וצריכה להפעיל את הפונקציה המתאימה לאובייקט הנוכתי, לפי סוגו. הפונקציה הראשית מכניסה שני קוויס ושתי נקודות לרשימה, ולאחר מכן מציירת את הצורות הנמצאות בה. פרק 6: פולימורפיום | 167 ()מ1נהת %ם1 ו 7 סמְש1185 ב66₪ע0פ5 ;((11 ,19 ,6)10,1םת11 ) סמסקסף. 580065 ;((10 ,55 ,20 ,6)40ם11 ) סמסססה. 58065 ;((20 ,6)10ת1סק טסם)מססקק8. 5865 שסת שסת ;((10 ,15)%ת1סק טסם)מסקק8. 58065 ; (502 ,80065ם5)א028 7 תעגו6%ץ ניתוח חסרונות בשיטה זו יש מספר פונקציות שעוברות על הרשימה ובוחנות את סוג האובייקט הנוכתי. ציור האובייקט נעשה בדרך שונה על פי סוגו. כשמוסיפיס מחלקה חדשה, מלבן לדוגמה, יש לשנות את כל הפונקציות האלו ולהוסיף להן קטע קוד המטפל במחלקה החדשה. חיסרון זה דומה, במידת מה, להסתרת מידע. כשלא משתמשיםס במודוליס ובממשק, שינוי של מבנה הנתוניס גורר שינוי של התוכנית כולה. במקרה זה, אנו משתמשים במודוליס (שהס המחלקות). חיסרון אחר הוא, שעלינו לזכור לצייןו בשצדה הראשון בכל צורה את הסוג. כל תוכלנה הפונקציות המטפלות ברשימת הצורות לבצע את עבודתן. אס נשכת לציין זאת, תהיה התוצאה בלתי צפויה ובמקרה הטוב תפסיק התוכנית לעבוד. שני חסרונות אלה חשוביס מאוד מנקודת ראות של הנדסת תוכנה. הס מקשיס מאוד על פיתוח ספריית צורות על ידי גורס שלישי. בשינוי קטןו מאוד אפשר להתגבר על בעיות אלו ולשפר את איכות התוכנה. הפתרון לכך הוא פולימורפיזם, שימוש ברב-צורתיות של השפה. מהו פולימורפיזם היה טוב לו יכולנו בדוגמה הקודמת, לבצע פונקציה כלשהי לטיפול בצורה הרצויה, ללא צורך בהמרת הצורה לפי שדה מתאים. היה טוב עוד יותר אס לא היינו צריכיס לספק שדה כזה לכל צורה. טוב היה, לו התוכנה היתה מתעלמת מסוגי הצורות השונים. פולימורפיוס הוא רב-צורתיות, כלומר, מצביע או ייחוס לאובייקט יכול להיות מצביע למספר סוגים של אובייקטיס כאלה. כאשר המצביע מצביע לנקודה מסוימת ואנו מפעילים את הפונקציה 6:48, היא תופעל על נקודה, ואס המצביע מצביע לקו, היא תופעל על קו. כלומר, הפונקציה 8+ מזהה את האובייקט ומתאימה את עצמה לפעול עליו בצורה נכונה. 8 ++-+6 ו-009 למתכנת המקצועי פולימורפיוּס וירושה פועליס יחד. יש להגדיר פונקציות אלו במחלקה הבסיסית ואז להגדירס מחדש במחלקות היורשות. כשממלאים תנאיסם אלה אפשר להשתמש בהפעלה וירטואלית (פולימורפית) של פונקציות. הפעלה וירטואלית כדי שפונקציה תאפשר פולימורפיוס, יש להוסיף להגדרתה את מילת המפתח [₪8)ענץ. כלומר, מגדיריס מחלקה בסיסית שיש לה פונקציה וירטואלית. לכל המחלקות היורשות מהמחלקה הבסיסית קיימת אותה פונקציה וירטואלית, אשר יייודעת'י לפעול על פי סוג האובייקט. פונקציה וירטואלית מממשת את ההתנהגות הפולימורפית המבוקשת. כדי להבהיר נקודות אלו נחזור לדוגמה הקודמת, זו עס ציור הנקודה והקו. נגדיר את המחלקה 52826 כיורשת מהצומת הבסיסי של הרשימה. למחלקה זו נגדיר את הפונקציה 6:8 כפונקציה וירטואלית (מסגזסתג] [אג)זוט). ] א%ם11 110סמטס : 6ק80ם5 01858 :טס [+ ()סמם5 [+) (8 תם50266)א428% סנסט 81גמס2נ1ט ;ן את המחלקות 6מ201 ו-14156 נגזור כעת מהמחלקה 52806. הפונקציה 6:8% היא וירטואלית במחלקה הבסיסית 52806, לכן, פונקציה זו תהיה וירטואלית גס במחלקות )201 ו-6ם/,1. הפעלה של פונקציות אלו דרך מצביע למחלקה הבסיסית, תפעיל את הפונקציה המתאימה לאובייקט. ] 5806 110סמטק : 6םנ1סקע 01885 ;ץ,א %ם1 :טס [ ;סץ=ץ ;סא =א + (סץ %ם1 ,סא 6םת1)פ6ת1סק (6802 ם502066)א328% בנ1סט [ ;(ץ,א)5טס.ע802 ) ;ו ] 5806 110סטס : 6ם1ם 01858 12 ,1א 6ם1 2 ,2א 6ם1 :טס (02ץ %ףםת1 ,02א 1% ,1סץ סם1 ,1סא 6ם6)1תג1ת1 [ ;2סץ = 2ץ ;02א = 2א ;01ץ = 1ץ ;01א = 1א ] ;(8502 ת50266)א328 ב1ס ו פרק 6: פולימורפיוס | 169 השינוי הגדול הוא בפונקציה 8%ו4. במקרה וה, אין כל צורך לבדוק את סוג האובייקט, כי הפונקציה המתאימה לאובייקט תופעל, לפי סוגו, על ידי ++6. אם המצביע 80 מצביע לאובייקט מסוג זמוסק תבוצע פונקציית ציור המתאימה ל-)מוסק. מסקנה נוספת שאפשר להסיק מכך היא, שאם נוסיף סוגים של אובייקטים, כגון מלבן, אין כל צורך לשנות את הפונקציה א8ז0, או פונקציות אחרות שתלויות בסוג האובייקט. מכאן, שאפשר לספק ספרייה שמטפלת בציור של צורות היורשות מ-51806. כל מי שרוצה להוסיף אובייקט לספרייה, גוזר את האובייקט שלו מהאובייקט הבסיסי 5(0826, והספרייה תטפל באובייקט ללא צורך במידע מדויק מראש לגבי סוגו. (ע680 תם50266 ,689118% 118%)א328 ב1סע ָ ;()ם8118%.0601 = 1 166% 1186 ;()502.01082 + (()06ם8118%.6 =! 1) 118תט ; ב* (*806ם5) = ספ5* סַקַם5 ; (50₪) ש628<-50 ; ב++ ] ; () ש028.ע50% ו פונקציות הכותבות, או קוראות אובייקטיס, תהיינה קצרות יותר, ולא תהיינה תלויות בסוג האובייקטיס ברשימה. כיצד מיישמים פונקציות וירטואליות ? לאחר שהבנו את משמעות הפונקציות הווירטואליות (מסוסתט [8טזוצ), ואת היכולת הניתנת לנו כתוצאה מהן, נשאלת השאלה: מה המחיר! האם, כתוצאה מהפעלה של פונקציה וירטואלית, מבצעת המערכת חיפוש כלשהו של הפונקציה! האסם, הפעלה של פונקציה כזו דורשת יותר זמן ריצה: כדי לענות על שאלות אלו יש להבין כיצד מיישמים פונקציות וירטואליות ב-++6. עבור מחלקה בסיסית כמו 52806 עם פונקציה וירטואלית, מוסיף המהדר מצביע לטבלה של פונקציות, אשר מכילה מצביעיס אל פונקציות וירטואליות. כשמגדיריס מחלקה עס פונקציות וירטואליות מקבליס קוד הדומה לקוד זח: ] 806ם5 06גוע56 ;() ([]1מפסט*) בנ1בסט ;ו 0 ++-+6 ו-009 למתכנת המקצועי [צ הוא מצביע למערך של מצביעים לפונקציות. כשצריך להפעיל פונקציה וירטואלית, המהדר מפעיל את הפונקציה באמצעות המצביע לתחילת הטבלה של הפונקציות וההיסט בטבלה זו. כך, הפקודה ; (808) ש628<-50 שקולה לפקודה זו: ; (ע80 ,80) ([1]1ס6ץ*) תחילה מופעלת הפונקציה הראשונה בטבלה של הפונקציות הווירטואליות ומועבר אליה מצביע לאובייקט הנוכתי, ומצביע 118 לאובייקט מסוג ם50900. הפעלה כזו מהירה ואינה צורכת זמן רב. טבלת הפונקציות הווירטואלית מאותחלת עבור כל אובייקט. עבור המחלקה )מוסע יוצר המהדר טבלה שבה המצביע לפונקציה הראשונה המתאים ל-א8ז6 מצביע אל הפונקציה של המחלקה +מוסע. בדומה לכך, מאותחלת הטבלה להצביע לפונקציה המתאימה בשאר הכניסות שלה. למחלקה 16 יש טבלה דומה שמצביעה על הפונקציות של 6מ:.1. אתחול המצביע עס אובייקט לטבלה המתאימה נעשה בקוד שמוסיף המהדר בבנאי של האובייקט. אס מנסיס להפעיל פונקציה וירטואלית בבנאי של אובייקט בסיסי, תופעל הפונקציה של המחלקה הבסיסית, ולא של המחלקה האמיתית של האובייקט: 01889 2886 ] :טס [ ;()ש6ם1עס + ()6פַ8ם2 [ ;061ם6 >> "2886" >> סטסס + ()ס6תנפס טנסט 81ג126ט ןז ] 2886 110סמק : 6ט1ע6כ 01858 :טס [ ;()6ם1עס + ()68עט1ע6כ [ ;01ם6 >> "סטנבעסכ" >> סטסס + ()6םנ1עק בנסט 1הטסענט ו ;6 שט1עסכ התוכנית הזו תדפיס את השורות הבאות: 6 סטנעסק למרות שהאובייקט מסוג 686 מצוי בבנאי של 2856, תופעל הפונקציה >מוזק, השייכת למחלקה 2856. הסיבה היא, שהמצביע לטבלת הפונקציות הווירטואליות מצביע באותה עת לטבלה של 2886. רק לאחר שנבנה האובייקט במלואו (עד למחלקה היורשת ביותר) יכול המצביע לטבלה של הפונקציות הווירטואליות להצביע על הטבלה הנכונה. פרק 6: פולימורפיום | 171 אילו פונקציות יכולות להיות וירטואליות? כל הפונקציות יכולות להיות פונקציות וירטואליות פרט לבנאי המחלקה. מכאן נובע, שגם פונקציית הפירוק של המחלקה יכולה להיות פונקציה וירטואלית. המשמעות של מפרק וירטואלי היא, שכשמפעילים את האופרטור 66166 על מצביע של המחלקה הבסיסית, יופעל המפרק המתאים לאובייקט. דהיינו, יופעל המפרק של המחלקה שאליו שייך האובייקט. לדוגמה: 0185585 5806 ] :וס [+ () 5806 [+ () 806ם5> [+ (...)898ע3 ב1סט 81מ6ע2נט ;ן ] 5806 110סגמס : ך%600א76% 018585 ;52* ע8ם0 :טס (8* ע8ת0 85%ם600) [605א76% [ ;(5 ,802)ץק020ס8 ;[1 + (58)ם82]8%216ם0 טסם = מ₪5ם8 + [ ;552 [] 861666 + () כמ%600א76- [... + (...)3289 ב1סט ו במקרה זה, כאשר מפעילים את המפרק של 52406 באמצעות קריאה לאופרטור 661606 למחיקת מצביע מסוג 81806, לא יופעל המפרק של [%00א16, אלא המפרק של 50806 בלבד. נתבונן בדוגמה הבאה: ; ("665%") [ך600א716 שסם = ספ* סַקַַם5 061666 50; כאן נאבד ויכרוו שהוקצה בבנאי של [%09א16, כי המפרק של אובייקט זה לא יופעל. כדי להתגבר על בעיה זו עלינו להגדיר מפרק וירטואלי (605010007 ₪81זוצ) למחלקה 6 0185855 5806 ] (+ ()806ם5- 126081ט ל כאשר המפרק הוא וירטואלי, הפעלת אופרטור 86166 על מצביע ל-51806 תפעיל את המפרק המתאים לאותו אובייקט ולמעשה, את המפרק של האובייקט היורש. לאחר שיופעל המפרק של האובייקט היורש יופעל המפרק של האובייקט הבסיסי, ובעיית שחרור הזיכרון תיפתר. 2 ++6 ו-009 למתכנת המקצועי מחלקות מופשטות טהורות מחלקות מופשטות טהורות (01858 4030806 סזטע) הן מחלקות שיש להן פונקציה וירטואלית אחת או יותר ללא הגדרה. כלומר, אין גוף לפונקציה. פונקציה וירטואלית ללא הגדרה נקראת לעיתים: פונקציה וירטואלית טהורה (תסטסתטת [₪8זג/ 6עטע). פונקציה כזו מוגדרת כשווה לאפס : ] 5806 0185855 :טס [+ () 5806 ([+ ()806ם5- 81ט6ע1טש 7 = (8 ם50266)א428% ב1סט 81ט26נט ?ןז הפונקציה 4:8 היא פונקציה וירטואלית טהורה. מחלקה כזו, שהיא מחלקה מופשטת, אינה מאפשרת להגדיר אובייקטים ואין לה מופעים. הסיבה לכך היא, שחסרה לה פונקציה. המהדר אינו מאפשר להגדיר אובייקטים של מחלקה. אפשר להגדיר אובייקטים של מחלקות יורשות ממחלקה זו, בתנאי שהן אינן מופשטות בעצמן. מחלקה יורשת יכולה להיות מופשטת כאשר היא אינה מגדירה את הפונקציה הווירטואלית הטהורה של המחלקה הבסיסית כאשר היא מחלקה מופשטת, או שהיא בעצמה מגדירה פונקציה וירטואלית טהורה. אס כן, מדוע להגדיר מחלקות כאלו! קיימות מספר סיבות לכך וננתח אותן כעת. למחלקה 51806 יש פונקציה שו8ז0 עם גוף ריק מתוכן, כלומר גוף הפונקציה אינו קיים. הפונקציה מגדירה ממשק בו יש להשתמש כשרוצים לקרוא לפונקציות כאלו. מחלקה מופשטת מגדירה לנו ממשק לרמה היררכית, שכל המחלקות היורשות ממנה מקימות את הממשק הזה. סיבה נוספת להגדרה של מחלקה מופשטת טהורה היא, להכריח את המחלקה היורשת להגדיר את הפונקציות הנדרשות. המהדר לא יאפשר להגדיר אובייקטיס של מחלקות מופשטות טהורות ולכן המתכנת הכותב את המחלקה היורשת, יהיה חייב להגדיר את הפונקציות המתאימות, אס ברצונו להגדיר או ליצור אובייקטיס ממחלקה זו. מחלקה מופשטת טהורה מגדירה, אס כן, ממשק שבו משתמשת התוכנה כדי לבצע פעולות על סוגי אובייקטיס שאינס ידועיס מראש. קודס לכן ראינו שכשמפעילים פונקציה וירטואלית של אובייקט יורש בבנאי של אובייקט בסיסי, נקבל הפעלה של פונקציה וירטואלית של האובייקט הבסיסי, מכיון שהאובייקט בנוי חלקית, באותה עת. כאשר נפעיל פונקציה וירטואלית טהורה בבנאי של מחלקה בסיסית, נראה שבמקרה הטוב תופסק התוכנית ובמקרה הפחות טוב, ההתנהגות אינה מוגדרת ואינה צפויה. פרק 6: פולימורפיום | 173 נקודת התורפה של מערכת פולימורפית נקודת התורפה של מערכת פולימורפית היא הגדרת האובייקטים. פרט למקום בו אנו יוצריס את האובייקטים, איננו צריכיס לדעת את הסוג, או את המחלקה האמיתית של האובייקט. נקודות היצירה של האובייקטים הן הנקודות ש'ימקלקלותיי תוכנה הכתובה בדרך זו. נניח, למשל, שיש לנו ספריית אובייקטיס המטפלת בממשק למשתמש. ספרייה זו יכולה לעבוד במספר סביבות שונות, למשל בסביבת 0601 תחת פ8שסמנ/-8 או בסביבת 608ה1\ של מיקרוסופט. עוד נניח, שיש אובייקטים, כגון מסוטם ו-141%0. לחצן (ם60ט2) הוא אלמנט גרפי, שכשבוחריס בו בעזרת העכבר מבצעיס פעולה. רשימה (14%0) היא אלמנט גרפי המציג מספר אפשרויות, ומאפשר לבחור באחת מהן. ] מס0%%ם+0%1 01888 ; () 85861606 16סטע ) 615018%ס8 018588 ; () 85861606 16סטע ] תס66טם85 01858 ; ()586160%6 16סטע 018885 518% + ;()8586160%5 16סטע קז אובייקטים גרפיים אלה מספקיס פונקציונליות גהה בשתי סביבות העבודה. כאשר נבחר הלחצן נקראת הפונקציה 56160, ומכיון שהתוכנה שלנו פועלת בשתי סביבות אלו, עליה להשתמש בפונקציה כזו. אס בכל מקוס בתוכנה ניצור אובייקטיס גרפייס כאלה, יהיה קשה לתחזק את התוכנה בשתי סביבות העבודה ובסביבות אחרות יגרוס הדבר לבעיית תחזוקה קשה מאוד. לדוגמה: =סא +06 1+ ;(...)סת תסספטם+נ%סא 6+ ;(...)ספת מתסספטתפא +1סת6+ 4 ++-+6 ו-009 למתכנת המקצועי ייצור אובייקטים מופשטים (עזסס9: 0547901 ) קטעי הקוד שתוארו כאן תלויים בסוג האובייקטים. רצוי להסיר תלות זו. כיצד נתגבר על הבעיה! נעשה זאת על ידי הגדרה של מחלקות מופשטות עבור לחצניס ורשימות, כך: ) תסספסטם 01858 2 = ()56160% 16סט 8[1ט6ת1ט ו ] 18% 018855 2 = ()56160% 18סט 81ט6ת1ט ;ל מחלקות מופשטות אלו מגדירות את הפונקציות שהתוכנה מכירה. בכל מקוס בתוכנה שלנו נשתמש במצביעיס ללחצנים, או לרשימות גרפיות. ניצור את המחלקות הבאות: % ותה פתספפטס +1ססא // )+ םס660ט20 110עוסם : ם%660ט0%1+2 01855 ; ()856160%6 16סט ;ן ] 218% 110סטס : %0%111186 01855 ; ()856160%6 16סע ו % ₪0ם8 תסספסוס פחסבת1ט 1620801%א // ) םס66ט2 110סגמס : םס%6ט52 01855 ; ()856160%6 16סט 7 ] 218% 110סטס : 8521856 018585 ; () 861606 ב1סט ;ו אס כל התוכנה שלנו משתמשת במצביעים למחלקות המופשטות, אין צורך לשנות דבר כשעובריס מסביבת עבודה אחת לאחרת. כל זה נכון, פרט לנקודה של הגדרת האובייקטיס. כדי שמצביעים אלה יקבלו ערכיס נכוניס, יש לתת להס כתובת של אובייקטים. לכן יש להכיר את האובייקטיס של הסביבה המתאימה. פרק 6: פולימורפיום | 175 כדי למנוע הכרת סוג אובייקטיס בכל מקוס בסביבת העבודה, ניצור עוד מחלקה מופשטת היוצרת לחצניס ורשימות בצורה הבאה: 01888 0268602 ] 2 = ()ם6268%620%60* מסספטם 81ט6ץנ1נט 02 = ()6868218%ת602* 121856 81ט6ץנט ;ו לכל סביבה ניצור מחלקה, היורשת ממחלקה מופשטת זו, ויוצרת את האובייקטים המתאימיס לסביבת העבודה. המחלקה תוגדר כך: ] 0268002 110סטמק : ע0%11020800 01855 ()ם0268%620%%0* מתמסספטם 81ט6ץנט [ ;()ם₪0%1+20%%60 חפת מעט66? + [ ;()₪0%1+018% חפת מעט66? + ()0268%86215%* | 118% 81ג6ע1ט ו ]) 0268602 110סגמק : 50268602 01855 [ ;()םס520%6%0 טסםת מעגמ6%ע2 + ()ם0ס6108%620%%* מתסספגם 81ג%ת1נט [ ;()85118% חטסם םעט26% + ()0708606118%* %‏ 6081 נעט קז בכל מקוס בו נרצה ליצור אובייקטיס חדשים, נשתמש במצביע לאובייקט שיוצר אובייקטיס : ;68%07ע0* 0268608 ; () ם%%0ו0268%2<-0286%02 = מסס* מסספום כעת, נגדיר את סוג יוצר האובייקטיס במקוס אחד בתוכנה בלבד: ;0%1+0208%01 חטספם = 0268608 בדרך זו, חסינה כל המערכת לשינוי סביבת העבודה. אס רוציס לעבור לסביבת עבודה אחרת, נותר רק לשנות את יוצר האובייקטיס בדרך הבאה: 072 חשחשספם = 02686008 השימוש במחלקות מופשטות, יוצר אס כן, תוכנה באיכות גבוהה יותר וחסינה בפני שינוייס גדוליס, ואפילו שינוי בסביבת העבודה. 6 ++6 ו-009 למתכנת המקצועי סיכום בפרק זה למדנו את המונח פולימורפיזם. ב-++6 מאפשר מונח וה הפעלה וירטואלית של פונקציות. הפעלה וירטואלית של פונקציות נעשית באמצעות מצביעים, או משתנים, מסוג ייחוס לאובייקטים מסוג בסיסי. הפעלה וירטואלית של פונקציות פועלת בעזרת ירושה. כשיש מצביע למחלקה בסיסית, גורמת הפעלה של פונקציה וירטואלית דרך מצביע כזה, להפעלה של הפונקציה המתאימה לסוג האובייקט הנוכחי. פולימורפיּם מאפשר, אס כן, להגדיר פונקציות גנריות המטפלות במצביעים למחלקות בסיסיות בלבד. פונקציות אלו אינן מושפעות, למשל, כאשר מוסיפים סוגי אובייקטיס חדשיס למערכת. נקודת התורפה היחידה של מערכת פולימורפית היא במקוס יצירת האובייקטים. במקום זה יש לכתוב את סוג האובייקט האמיתי, ולא את סוג המחלקה הבסיסית. יש להימנע מפיזור יצירת אובייקטיס ולרכזס במקוס יחיד, למשל במחלקה אחת. מחלקה מופשטת טהורה היא מחלקה המגדירה ממשק בלבד, ויש לה פונקציה וירטואלית טהורה אחת או יותר. פונקציה וירטואלית טהורה היא פונקציה המסומנת כשווה לאפס בהגדרת המחלקה, ואין לה גוף. ₪ 7 | שאלות כתוב פונקציה הכותבת צורות ומחלקות היורשות מהמחלקה צורה לקוב. היעזר במנגנון הפולימורפי לשס כך. אילו פונקציות עליך להוסיף ל-5(806! האס אלו פונקציות וירטואליות טהורות: 2 כתוב את הפונקציות הקוראות אובייקטים היורשים מהמחלקה 51826 מקוב. מה ההבדל בין פונקציות כותבות לקוראות! כיצד תזהה את סוג האובייקטים שצריך ליצור! האס המערכת שלך עמידה בפני תוספת של מחלקות! 3 הרשימה 1% מכריחה את המשתמש בה לרשת מהצומת הבסיסי אםו[. האס יש דרך לתקן מצב זה! 4 כתוב ספרייה המאפשרת לקרוא ולכתוב אובייקטים כלשהס מקוב> (רמז: השתמש בפונקציות וירטואליות ומחלקות מופשטות כדי להגדיר את הממשק לאובייקט בסיסי של הספרייה. כל אובייקט שצריך להישמר לקוב צריך לרשת מהאובייקט הבסיסי של הספרייה). 5 כתוב מחלקה (או מספר מחלקות) אשר אי-אפשר לרשת ממנה (רמז: היעזר בירושה וירטואלית). פרק 6: פולימורפיום | 177 פרק 7 תבניות ב-++) בפרק וה נלמד את המונח תבניות ב-++6 (18)0קננ6)). תבניות מאפשרות תכנות גנרי (פחוותות8ץק סז 6110מ86) בדומה לירושה ופונקציות וירטואליות. ובכל ואת, קיימיס הבדליס בין ירושה ופולימורפיזם לבין תבניות. יש דבריס רביס שניתן לממש בעזרת כל אחד מכלים אלה. לעומת זאת, יש דבריס הניתניס לביצוע באחד מהס בלבד. נוסף לפונקציונליות שונה של ירושה ופולימורפיום לעומת תבניות, יש הבדל ביעילות של המערכת הממומשת בשיטות אלו. נבחן ענייניס אלה ואחרים בפרק וה. לשם מה תבניות לפני שנתחיל ללמוד את הסינטקס והסמנטיקה של תבניות (8009!קומטו), נבין מהן תבניות ומה השימוש שנעשה בהן. נניח, למשל, שיש לנו את המאקרו הבא, שדומה לפונקציה: (ץ : א ? ץ > א) (ץ ,א)תגת 6ם611+ כבר ראינו שיש בעיות העלולות להיגרס כתוצאה משימוש במאקרו. למשל: ;ץ,א %ם1 1 (3 > (ץ,++א)תנ1ת) +11 ] קטע קוד זה עלול להגדיל את % פעמיים, למרות שהמתכנת התכוון להגדילו פעס אחת בלבד. הצגנו את הפתרון הבא לבעיה זו: [ ;(ץ : א ? ץְ>א) תעטס6ע + (ץ 6םת1 ,א 12%)תגנת %ם1 6ם11ם1 ואכן, כאשר העברנו את המאקרו לפונקציה מסוג זה נפתרת הבעיה, ועתה א יוגדל פעס אחת בלבד. אבל יש לנו בעיה אחרת, למשל: 2ץ ,5.1=א 11086 ;(ץ ,א)םנת = 2 11086 פרק 7: תבניות ב-++6 179 הערך שיקבל 2 הוא 5. הסיבה לכך היא, שהמהדר ממיר את הפרמטרים של הפונקציה לשלמיס וכתוצאה מכך אובד הדיוק. במהדריס רביס נקבל על כך אוהרה, הקוד יעבור את שלב ההידור ונוכל להריץ את התוכנית. במהדרים אחרים, לעומת זאת, לא נקבל את האזהרה ותהיה לנו בעיה בזמן ריצה. כדי לפתור בעיה זו נצטרך להוסיף את הפונקציה הבאה: (ץצ 5108% ,א 1108%)םת1ת 51086 6ם11ם1 [ ;(ץ : א ? ץְ>א) םתעטססץ ) כעת, נפתרה הבעיה עבור משתניס מסוג +108, אך עבור משתנים מסוג 400916 הבעיה עדייו קיימת. האם עלינו ליצור פונקציה כזו עבור כל סוג משתנה? טוב היה לו יכולנו להגדיר את הפונקציה באופן כללי, ולהשאיר למהדר את יצירת הפונקציות המתאימות, כדי שיקרא לפי הצורך, כלומר, לפי סיווג הארגומנטיס בעת הקריאה לפונקציה. זה בדיוק מה שנשיג אס נשתמש בתבנית ב-++6. דוגמה אחרת לכך היא הגדרה של מחלקות. המחלקה 1186 מהפרקיס הקודמיס אינה צריכה יילדעת'י על האובייקטיס הנשמריס בצמתיס (האיבריםס) שלה, כדי לממש את הפונקציונליות שלה. היו לנו קטעי קוד כגון: (815% 7)115%ץ8315018 1%בסט ו ; (()ת1)18%.00601 1662 1186 + (()06ת1856.6 =! 1) 16נתט ;++806*(*1ם5) = ספ5* סַקַם5 ;(...) 28%<-50 ו כשרצינו להשתמש ברשימה, היה עלינו לגזור את האובייקטיס המבוקשיס מהצומת הבסיסי של הרשימה, ולבצע את המרות המצביעים. רצוי להימנע מפעולות מיותרות כאלו, והיה טוב אם המהדר היה עושה גה עבורנו, באופן אוטומטי ללא טעויות. תבניות ב-++6 כפי שראינו בסעיף הקודס, היו מצביס בהס היינו צריכיס תבניות עבור פונקציות ותבניות עבור מחלקות. ++6 מאפשרת ואת. בהמשך הפרק נתאר ואת. פונקציות תבנית ++6 מאפשרת לנו להגדיר פונקציות תבנית (5ת610םג 1866קננס?). פונקציית תבנית אחת מייצגת משפחה של פונקציות שהמהדר מייצר בעצמו על פי פונקציית התבנית. בסעיף הקודס ראינו מאקרו (או פונקציות) ששימשו למציאת המספר המינימלי בין 0 ++6 ו-009 למתכנת המקצועי שני מספריס נתונים. ראינו, שהיה עלינו להגדיר מספר רב של פונקציות לכל סוג של מספרים (שלמים, ממשיים וכוי). אפשר להגדיר פונקציית תבנית ב-++6 בצורה הבאה: <1? 01858> 66801866 (2א 7 ,1א ?9)תנגת ך ו ;(2א : 1א ? 2א > 1א) םעגמ6%ת ו הגדרה מעין זו עדיין לא ראינו. בהגדרה זו יש מילת מפתח חדשה - 01866ומ9), אשר מציינת שלפנינו פונקציית תבנית (מסגזסמט] 1816קות6+). לאחר מכן, מופיעים הסימניס 'י< >יי, שביניהס מופיעים הפרמטריס של התבנית. כל פרמטר מופיע בפורמט הבא : 018885 7 כלומר, מילת המפתח ולאחריה שס הפרמטר. במקרה זה יש רק פרמטר אחד. השמות ברשימת הפרמטרים חייביס להופיע לפחות פעס אחת ברשימת הפרמטריםס של הפונקציה שמשתמשת בהם. במקרה זה, השמות של הסוג 1 מופיעים פעמיים, כסוג של הארגומנטיס של הפונקציה 1א ו-2א. הפרמטריס ברשימת הפרמטרים של פונקציית התבנית משמשים כסוגים עבור הארגומנטיס של הפונקציה. הגדרת פונקציה כזו אינה יוצרת שוס קוד. ההגדרה יוצרת עבור המהדר תבנית שממנה הוא יוכל ליצור משפחה שלמה של פונקציות מוגות בהתאם לשימוש בהן. כאשר נקראת פונקציה זו עס משתניס מסוג שלם (₪0), ייצר המהדר פונקציה המתאימה לשלמים. כאשר ישתמשו בפונקציה עס פרמטריס מסוג 8086, ייצר המהדר פונקציה מתאימה לסוג זה. פונקציות אלו זהות לפונקציות שהיינו כותביס בנפרד לכל סוג משתנה, כפי שעשינו בסעיף הקודם. התבנית שכתבנו כאן עונה על שתי הבעיות שהצגנו בסעיף הקודס. ראשית, אין צורך לכתוב פונקציה כזו עבור כל סוג בסיסי. שנית, הסמנטיקה של פונקציית תבנית זהה לסמנטיקה של פונקציה רגילה. לכן, בקטעי קוד מהסוג - ;ץ,א ‏ 6ם1 ((ץ ,++א)םתנת) +1 ו תבוצע ההגדלה של המשתנה א פעס אחת בלבד, ללא כל תלות אס א גדול מ-ץ. 1 | שימוש במספר פרמטרים בתבנית למרות כל האמור לעיל, עדיין יש יתרון למאקרו על פונקציות כאלה (זכור, למאקרו יש גם מספר חסרונות). למשל: ((ץצ) : (א) ? (ץ) > (א)) (ץ ,א)םגת 6ת4611+ 7 16גוסף ;ץ 6ם1 ; (צ,א)ת1ת = 2 פרק 7: תבניות ב-+-+ 6‏ 181 שורות קוד כאלו יעברו הידור. לעומת ואת, אותה שורת קוד בשימוש בפונקציית התבנית, לא תעבור הידור ברוב המהדרים, מכיון שברשימת הפרמטריס של הפונקציה תוגג יש פרמטר אחד בלבד מסוג 1, ואנו מעביריס לפונקציה פרמטרים משני סוגים, שלמיסם וממשים. כדי להתגבר על כך, נוסיף עוד פרמטר לרשימת הפרמטרים: <712 01888 ,711 018859> 18%66קת66 (2א 72 ,1א 71)תנג1ת ?ך (2א < 1א) 15 ;1א תעגו66ץ 1-6 2 תעטספץ ו הבעיה כאן היא, שאין אנו יודעיסם מהו סוג הפרמטר שיש להתויר בקריאה מהפונקציה. לרוע המזל, ++6 אינה מאפשרת להכניס את הערך המוחזר של הפונקציה כפרמטר של תבנית. הסיבה לכך נעוצה בעובדה שהקוד הקורא לפונקציה אינו חייב להשתמש בערך המוחזר. לכן, אין אפשרות למהדר להבחין באיזו פונקציה מדובר. למשל: 661866 >018859 711, 01888 712< 72 5+)71 081( ו לי / ] <712 01888 ,711 018859> 18%66קת66 (081 5)72 71 7 ] ;ט %ם1 ? 00086 ₪0 תסנגפפסט םתס1מח //‏ ;(עצ)+ בדוגמה זו אין למהדר כל דרך לבחור את הפונקציה המתאימה. לכן, חייבים להוסיף פרמטר שמתאר את הערך המוחזר של הפונקציה בארגומנטיס של הפונקציה. לאחר הוספת הפרמטר תיראה הפונקציה פוגע כך: <360%081 01855 ,72 01888 ,01 01855> 1866קת66 (צע8 3266081 ,2ט 72 ,1ט 1ט)תג1נת ב1סעצ (2 > 1ש) 47 ;71 = טע 1-6 ;2 = טע 2 ++6 ו-009 למתכנת המקצועי בצורה זו מועבר הערך המוחזר בפונקציה כייחוס (00ת161076) לפונקציה. לפיכך, השימוש בפונקציה הוא כוה: ;א 106 ;צ ,ץ 000061 ;(ט ,ץ ,א)תנת התוצאה מניבה קוד פחות קריא מאשר הקוד עס פקודת מאקרו. לעומת זאת, השימוש במאקרו גורס למספר בעיות בתוכנית, כגון סמנטיקה שאינה מוגדרת. אין אפשרות לעבור עס 860008861 על מאקרו. המרות למשתניס של מאקרו גורמות לאבדן דיוק, או שגיאות ללא כל דיווח של המהדר. טכניקה אחרת לפונקציה כמו םגמ מציעה שימוש ריק של פרמטר ההחזרה של הפונקציה. בדרך זו: <360%081 01855 ,72 01888 ,711 01855> 1866קת66 (*78[1ט36% ,2ט 72 ,1ט 711)ת1ת 1ה8טס66ת2 ָ (2ט > 1ט) 15 ; (1ט) 81ע326%6 תעמ66ת ; (2ט) 8[1ע36% מע6%0ת ו במקרה זה אנו כולליס ברשימת הארגומנטיס של הפונקציה את המצביע לסוג האובייקט שרוציס להחזיר. השימוש ריק, כלומר אין לנו משתנה כזה, וכל תפקידו של הארגומנט לאפשר למהדר לבחור בפונקציה המתאימה. השימוש בפונקציה גגגת הוא כוח: ?א 16 ;ץ 11086 000016 7 ; (0 (*9800016) ,ץ ,א)תנגנת = 2 היתרון של גישה וו הוא, שכעת אפשר לקבוע סוג פרמטר מוחזר מהפונקציה שאינו קשור לשני הראשונים. מצב וה לא קורה במאקרו, כי סוג הערך המוחזר הוא אחד משני הפרמטריס המסופקים למאקרו. החיסרון העיקרי בפונקציות שראינו עד כה הוא שהשתמשנו באופרטור הבסיסי? '>יי של השפה. אס נשתמש בפונקציות אלה עבור *-004 לא נקבל סדר לקסיקוגרפי (אלפביתי), אלא לפי ערכי המצביעים, דבר שאינו רצוי במקריס אלה. כלומר: * ,"6סס" = 51* ,"ססה8" = 82* םס ;(82 ,81)ת1ת = 53 כלל לא מובטח ש-33 יצביע למחרוזת "סטג". אס מחרוזת זו ממוקמת בכתובת שאחרי המחרוזת השנייה, יצביע 53 למחרוזת השנייה (2). בהמשך נראה כיצד מתמודדיס עס בעיות מסוג זה. פרק 7: תבניות ב-+-+6 183 דוגמה אחרת של פונקציית תבנית היא הפונקציה ק4שף8. פונקציה זו מחליפה בין שני אובייקטים. זו פונקציה גנרית שיכולה להחליף כל שני אובייקטים. היא מקבלת שני ייחוסיס לאובייקטיס מסוג 1, שהס הפרמטריס של התבנית, ומחליפה את הערכיס ביניהס. 66801866 >01858 ?1< (02ט8 7 ,1ט60 1)ק8ח5 הנ1בסט ; (2ט) קת6 7 2 = 2ט ;קתם = 1ט הפונקציה קא/ו8 שימושית לאלגוריתמים נוספים שנלמד בפרק זה. תכנות גנרי תכנות גנר? (פתוותות8זפסעק 0110ת86) בפונקציות תבנית היא טכניקה המאפשרת לכתוב פונקציות גנריות הטובות למספר רב של יישומים. הפונקציה מוגו היא פונקציה כזו. בסעיף וה נראה דוגמה מורכבת יותר של תכנות גנרי, תוך שימוש בפונקציות תבנית. הדוגמאות הנתונות דומות מאוד לקוד שמומש בספריית האובייקטיס הסטנדרטית של ++6, שנסקור אותה בהמשך. בתכנות גנרי משתמשים בתבניות כדי להגדיר אלגוריתמיס שיהיו טובים ליישומיס רביס ולסוגיס רבים של משתנים ואובייקטים. סוג המשתנה, או האובייקט, מיוצג על ידי פרמטר של פונקציית התבנית (או של מחלקת התבנית). כשמשתמשים בפונקציה עבור אובייקטים מסוגיס שונים, או עבור משתנים שונים, יוצר המהדר את הפונקציות המתאימות לסוג שבו אנו עוסקים. בסעיף ה נראה מספר דוגמאות לפונקציות גנריות, ונלמד כיצד יש לתכנן אלגוריתמיס כאלה. נעמוד על איכות האלגוריתמיס ונסקור את משמעות סיבוכיות האלגוריתמים. 1. 7 סיבוכיות האלגוריתמים להערכת איכות של אלגוריתס נתון יש שני מדדים. >= סיבוכיות זמן (ץוואס]קנתסס 6ותט) - כמות הזמן שצורך אלגוריתס מסויס להפקת פלט בגודל נתון. > סיבוכיות מקום (עוא6!קנתסס 50806) - כמות הזיכרון שצורך האלגוריתס עבור פלט מסוים. סיבוכיות זמן סייבוכיות זמן (עזואס!קנמסס 6נתט) מציינת את משך הזמן לפתרון אלגוריתם, והיא נמדדת באופן יחסי למספר האובייקטים, או לגודל הפלט שמקבל האלגוריתם. 4 ++6 ו-009 למתכנת המקצועי לדוגמה, סיבוכיות הזמן של אלגוריתס מיון שמקבל 100 אובייקטים, למשל, נמדדת באופן יחסי למספר האובייקטים. נסמן את מספר האובייקטים בקלט של אלגוריתם באות ם. נשתמש באות 1 (מלשון 6מג'1) לציון סיבוכיות הזמן. במקרה של פונקציה שסורקת מערך ומדפיסה את האלמנטים הנמצאים בו, נאמר שסיבוכיות הזמן שלה יחסית למספר האובייקטים. כך אנו מגיעיס למונח 0 (אות ''אויי, ולכן אומריס : או גדול). המונח או גדול מציין יחסיות. ההגדרה המדויקת של המונח או גדול היא: עבור פונקציה 1 כזו אומריס שהיא או גדול של פולינוס אחר 8, אס קיימיס א ו-% כך שעבור א<ת מתקיים : ((ת)0)6 = (ם)6*א > (ם)1 פונקציה המדפיסה אלמנטים שנמצאיס במערך תעבוד בסיבוכיות זמן של (ם)0, כאשר מ הוא מספר האובייקטים במערך. ואת משוס שאנו יכולים למצוא קבוע % מספיק גדול, כך שבומן הפעולה של הפונקציה (מ)1 מקיימיס את המשוואה הבאה: פ + ם*5 => (ם)ך כש-9 הוא קבוע כלשהו. במקרה זה, סיבוכיות הזמן פרופורציונלית למספר האובייקטיס במערך. דוגמה אחרת, היא אלגוריתס הממיין מערך של אובייקטים. אס קייס אלגוריתס הממיין את המערך בצורה יחסית ל-ם בריבוע, הוא איטי בהרבה מאלגוריתס הממיין את המערך בסיבוכיות זמן (מפס[*ם)0. הסיבה לכך היא שהפונקציה ם8ס1 גדלה לאט יותר מ-ם. אלגוריתס הפועל בזמן קבוע (0)6, הוא אלגוריתס שזמן הביצוע שלו קבוע ואינו תלוי במספר האובייקטיס בקלט שלו. בדרך כלל, אין אלגוריתמים כאלה. אלגוריתם לחיפוש אובייקט באוסף כלשהו בצורה (ם)0, איטי יחסית לאלגוריתס שמוצא אובייקט בסיבוכיות זמן (ם0)108. אם, לדוגמה, יש באוסף 1000 אובייקטים, תעשינה באלגוריתם הראשון כ-1000 פעולות. באלגוריתס השני, לעומת ואת, תעשינה כ-10 פעולות, לכל היותר. אלגוריתמיס הצורכים זמן רב יותר הס מסדר גודל של (מ*ם)0. בהמשך נראה אלגוריתמיס בסדר גודל נמוך, בדרך כלל. נשתדל שלא לכתוב אלגוריתמים עס סיבוכיות זמן כזו, כלומר - (תם*ם)0. סיבוכיות מקום סיבוכיות מקום (עואס1קומסס 50806) תלויה גס היא במספר האובייקטים שבקלט. סיבוכיות המקוס היא כמות הזיכרון שהאלגוריתם צורך. במקרה זה, נסמן את סיבוכיות המקוס באות הפונקציונלית 5. כמו סיבוכיות הזמן, כך גס סיבוכיות המקוס ניתנת לתיאור בעזרת הפונקציה 0. האלגוריתמים שנתאר כאן יהיו בעלי סיבוכיות מקוס קבועה, בדרך כלל. כדי להדגיס עקרונות אלה, נראה עתה מספר פונקציות גנריות המממשות מספר אלגוריתמים, כמו גס תוכנית קטנה המשתמשת בהן. פרק 7: תבניות ב-+-+6 185 2. 7 דוגמה - אלגוריתם הפיכת סדר הדוגמאות בפרק זה נמצאות במספר קבצים שבדיסקט המצורף: * קוב ש39180.00 מכיל את האלגוריתמים הגנריס ; * קוב ש11.60ומ+ מציג שימוש באלגוריתס הגנרי; * קובץ מי.ץְ39זז 5816 מכיל מחלקת תבנית המייצגת מערך בטוח, אשר אינו מאפשר גלישה מתחומו; * קוב ג.6ו1עע3 מכיל את האפליקטוריס לסוגיהם. כדי להדגיס תכנות גנר? (פתגותות9זפסזק 0710ת86), נתחיל בפונקציה שאינה תבנית, אשר הופכת את סדר האיבריס במערך נתון. עוד נראה כיצד להפוך פונקציה זו לפונקציית תבנית גנרית. אכן, זו שיטה טובה לפיתוח פונקציות תבנית גנריות. כאשר אתה מתקשה לכתוב פונקציה כזו, אפשר להתחיל בגירסה ראשונה שתפעל על מערך של מצביעיס לשלמים, ולאחר מכן, כאשר האלגוריתס פועל לשביעות רצונך, להופכו לתבנית. (0ת6* %ףםת1 , ת61ס6ס* %6ם6256)1ע6ע2 הנ1בסט ָ ]1 (08םת6 =! מנחסס) 1בשט ;סתם-- (0ם6 == ת61ש6כ) 1% ;עס ; (0ם6* ,ם₪601*) 58 ;ם5601++ ו הגירסה הראשונה של האלגוריתס פועלת על תחוס מערך שלמים. התחום נתון על ידי מצביעיס לשלמיס המצייניסם את תחילתו וסופו של התחוס. בגישה זו אנו יכוליס להפוך את סדר האיבריס בתחוס כלשהו של המערך, ולאו דווקא בכל המערך. אפשר להפוך איברי תחוס, שהוא רשימה, המוגדר על ידי שני איטרטוריס. האלגוריתס הופך את הערכיס של תחילת התחוס וסופו של התחוס בלולאה, כשבכל שלב של הלולאה מזיזים את שני הקצוות של התחוס אחד כלפי השני. במיליס אחרות, המצביע להתחלת התחוס מוגדל והמצביע לסוף התחוס מוקטן. הלולאה מסתיימת כשהמצביע לתחילת התחום מגיע עד המצביע לסוף התחום. דבר חשוב באלגוריתם וה היא האפשרות להגדיל ולהקטין מצביעים. כלומר, האלגוריתס דורש שהמצביעים יהיו כאלה שעבורס קיימיס האופרטור "י++" והאופרטור *--יי, עובדה חשובה במיוחד עבור פונקציית תבנית. לאחר שהבנו היטב את האלגוריתס לפונקציה רגילה, נוכל להמיר את הפונקציה לפונקציית תבנית גנרית (מס1)סםט1 16101816 0110ב86). הואיל ופונקציה גנרית אינה תלויה בסוג המצביע שהיא מקבלת, עלינו להפוך את סוג המצביע לפרמטר של התבנית. לכן, תחילת התחוס וסופו הס מצביעים, או איטרטורים. נתייחס 6 ++6 ו-009 למתכנת המקצועי לאיטרטורים כמצביעים, ואם נספק להס אופרטורים כגון **י" ואופרטורי הגדלה והקטנה ('++", --'), יוכל האלגוריתם לפעול גם על אוספים. נראה זאת בהמשך. כתוצאה, נקבל שהפונקציה 16/6186 היא פונקציית תבנית שמקבלת סוג של איטרטור (מצביע מיוחד) והופכת את סדר האובייקטיס במערך, בדיוק כמו הפונקציה הרגילה. לאחר המרה זו נקבל את פונקציית התבנית הבאה: 66801866 >01858 1606%< (0תם6 1862 , ם661ס 6256)1662ט6ע2 הנ1בסט ָ ] (8ם6 =! מםבחסס) 1 7-- (0ם6 == ת1ש6כ) 15 ;68%ע2ס ; (9ם6* ,ם₪641*) 580 ; ת5601++ ו הפונקציה 160686 שהתקבלה כאן, יכולה כעת להפוך את סדר איברי מערך של אובייקטיס, או של סוגיס בסיסיים של ++6, כגון שלמיס או ממשיים. פונקציה זו יכולה גס לסרוק מחלקה, כגון רשימה, שמספקת איטרטור המאפשר לקדמו כמו מצביע, וגסם מאפשר לבצע פעולת **'י. 43. 7 דוגמה - אלגוריתם מיון נניח שמוטל עלינו לכתוב אלגוריתס למיון מערך. נבחר באלגוריתם מיון מהיר (סוטף אשר נוקט בשיטת החלוקה וטיפול בתת-בעיות קטנות יותר. ווהי שיטת 'הפרד ומשולי, ובלועזית : ז6טףת00 6ת8 619166. האלגוריתם מורכב מלולאה חיצונית ושתי לולאות פנימיות. הלולאה התיצונית מתבצעת כל עוד התחוסם (1, 1) אינו ריק. בלולאה החיצונית בוחר האלגוריתם אובייקט במערך כאובייקט אמצעי (במקרה שלנו נבחר האובייקט הראשון). לאחר מכן, מתחיל האלגוריתס לסרוק את המערך מתחילתו לכיוון סופו, עד שהוא מוצא אובייקט הגדול מהאובייקט האמצעי (לולאה פנימית ראשונה). לאחר מכן, מתחיל האלגוריתס מסוף המערך כלפי תחילת המערך (לולאה פנימית שנייה). הלולאה ממשיכה עד שנמצא אובייקט הקטן מהאובייקט האמצעי. בסיוס פעולתן של שתי הלולאות נמצאו שתי נקודות בתחוס המכילות אובייקטיס שמפרים את הסדר, יחסית לאובייקט האמצעי, ולכן יש להחליף ביניהם. פעולה וו מתבצעת עד שהסמנים (מצביעים או איטרטורים) של האיבריס במערך מצטלבים. לאחר כל זאת יש לנו שני תת-מערכים, שבאחד מהם נמצאיס אובייקטים הקטנים מן האובייקטיס שבאחר. זו הסיבה שאפשר להפעיל את האלגוריתס ברקורסיה על כל אחד מחלקי המערך, כדי לקבל את המערך הממוין באותה הצורה. פרק 7: תבניות ב-+-+6 187 כדי להמחיש את האלגוריתם, נפַתֶּח אותו תחילה עבור מערך של שלמים: (0ת6* 6ת1 ,ת601ס* 6ם6)1ע502 6010% בנסע מ₪>5ע11 18 ת6018ת // 2 = ם* ,םת681ס = 1* 6ם1 ) (0ם6 > ם61ש6כ) 15 + (1) 116תש סקאחפ 60 0016085 8מם1+ // ;++1 (ם>1 86 ם661ס* > 1*) 116תט ;--ם (ם>1 86 ם661ס* < ם*) 116תט ;68% (ם=<1) +1 ; (ם* ,1*) ק8פ ] ; (1* ,ם₪61*) 580 ;(1-1 ,ת502%)0601 016% ; (0ת6 ,502%)1+1 016% ו לאחר שראינו מיון בשיטת גרסת המצביעים, נעבור לגירסת מיון בשיטת פונקציות התבנית. נמיר את המצביעיס לאיטרטורים, כפי שעשינו עד כה. הפונקציות בדוגמה זו פועלות על תחוס הנתון על ידי שני איטרטורים, התחלה וסוף. ההתייחסות לאיטרטוריס כאן היא כמו למצביעים, ולכן אפשר להפעיל פונקציות אלו על אובייקטיס בסיסייס של השפה, כגון שלמים, או על אוספים כגון מערכיס. הפונקציה 8011 %סוטף תחיה פונקציית התבנית ליישוס אלגוריתם המיון. היא מקבלת איטרטור לתחילת המערך וסופו, ומבצעת את אלגוריתס המיון שתואר קודס לכן על התחום הנתון. גם פונקציה וו היא פונקציית תבנית. הפונקציה 50 אסוטף קוראת לפונקציה 92ש8, כדי להחליף בין שני אובייקטים. 59 מקבלת את סוג האובייקטים שיש להחליף כפרמטר של התבנית, אבל לפונקציה ₪ אסוטף אין סוג כזה. לאחר שראינו את האלגוריתס עבור תחוס מסויס במערך של שלמים (כאשר התתוס נתון על ידי שני מצביעיס), אפשר להפוך את הפונקציה לפונקציית תבנית גנרית. יש מצביעים לתחילת ולסוף התחוס הנתון למיון. כשרוציס פונקציה גנרית, צריך להפוך את סוג המצביעיס לפרמטר של התבנית. נקבל את הפונקציה הבאה: <1606% 01858> 66801866 (0ת6 1665 ,ת601ס 1665)%ע502 010% בנסעט 0% 5₪ע11 18 ת6018ת // 2 >= ם ,םמם601ק = 1 ע166 ] (0ם6 > ם61ש6כ) 15 + (1) 116תשט 8 ++6 ו-009 למתכנת המקצועי סאחפ 60 0016085 8מם1+ // ;++1 (םב>1 86 םת661ס* > 1*) 116תט ;--ם (ם>1 86 ם6681ס* < ם*) 116תט ;68%תס (ם=<1) +1 ; (ם* ,1*) ק8שא5 ] ; (1* ,ם₪61*) 580 ;(1-1 ,ת502%)0661 016% ; (0ת6 ,502%)1+1 016% ו ההנחה שבהפעלת פונקציה זו היא שקיים אופרטור **יי שמחזיר אובייקט כשהוא מופעל על האיטרטור. דבר זה נגזר מפעולת הערך (*) על מצביע שהיה לנו בפונקציה הראשונה שהגדרנו (הגירסה הראשונה של האלגוריתס) שפעלה על המצביעיס. ההנחה שקיים אופרטור ''*יי מאפשרת שני דברים. האחד, חיסכון במספר הפרמטרים של פונקציית התבנית 80 אסוטף. אחרת, היה עלינו לספק גם פרמטר המתאר את סוג האובייקט שהאיטרטור מצביע עליו. כאן מסיק המהדר את סוג האובייקט, ומייצר בעת הצורך את פונקציית התבנית (טְגאו8) שמתאימה לסוג האובייקט. והדבר השני, פונקציית המיון יכולה לסרוק גם מערך של מצביעים וגם מחלקות עם איטרטורים, שיש בהס אופרטור ''*י' ואופרטור המאפשר סדר גדול (<) או קטן (>), בין אובייקטיס שהאיטרטורים (או מצביעיס) מתייחסים אליהס. 4. 7 דוגמה - פונקציית הדפסה הפונקציה ומאק אף היא פונקציית תבנית שהפרמטר שלה הוא איטרטור. הפונקציה מקבלת איטרטוריס לתחילת וסוף המערך בהתאמה, ומדפיסה את איברי המערך לפלט הסטנדרטי. הפונקציה מתחילה באיבר הראשון ומקדמת את האיטרטור עד שהיא מגיעה לסוף המערך. האיטרטור 6מ6 מצביע לאלמנט אחד אחרי סוף אוסף האובייקטים להדפסה. הפונקציה אינה מניחה שקייםס אופטור ">" או "<" ולכן אפשר להשתמש בה לאיטרטוריס הדומיס לאלה של הרשימה מהפרקיס הקודמיס. כמו בפונקציית המיון, כך גם פונקציית ההדפסה משתמשת באופרטור יי*יי כדי לקבל את תוכן האיטרטור. לכן, אפשר להשתמש בפונקציה זו כדי להדפיס מערכים, או כל אוסף שיש לו איטרטור, אס אופרטור יי*יי מתאים. גם זו פונקציה גנרית שיכולה לפעול על כל מערך או אוסף מתאים. 66801866 >01858 1606%< (0תם6 1862 ,ת601ס מ6)166%ת1עס הנ1בסט ] (08םת6 =! מנשסס) 1בשט ;" " >> םת681ס* >> סגוסס פרק 7: תבניות ב-+-+6 189 ;++ת6%1ס ] ;ק01ם6 >> 00806 5. 7 דוגמה - שימוש בפונקציות התבנית הפונקציה הראשית (קובצ קטש.301), מדגימה את השימוש בפונקציות אלו. מוגדר מערך של שלמים. המערך מודפס ולאחר מכן, ממוין ומודפס שנית. המצביע 6806 מצביע לאלמנט אחד אחרי סוף המערך. לפיכך, כשמוסרים מצביע זה לפונקציית המיון, יש להפחית אחד. הממשק לשתי הפונקציות שונה, אך ניתן לתקן בעיה זו (תרגיל 1). ()מנאת 6ם1 ן 2[ 726090 020,272 297 5 ,8 397 ,1,5,3 +34= [] מחםב. 36 ; (%ם812601)1 / (עע5812601)82 + ע82 = 6םת6* %6ם1 ; (0ם6 ,5ע6)82ם1עס ; (0-1ת6 ,502%6)822 16%ג ; (0ם6 ,עע6)8ת1עס 2606256 )822, 6ת0(‎ ; ; (0ם6 ,5ע82)%ם1עס ;0 תעגס6ע ו פונקציית המיון שראינו, משתמשת באופרטור "> ולכן לא נקבל את המיון הלקסיקוגרפי הנדרש עבור מצביעיס למחרוזות. לצורך כך יש להעביר לפונקציה פונקציית השוואה להשוואה בין האובייקטיס השונים. נראה דוגמה בהמשך הפרק. מומלצ לקורא לבחון את ההבדל בממשק של הפונקציה 4ס8 אסוטף לפונקציית המערכת 0501 של 6. נוסיף לפונקציה שיפוריס בהמשך, כשנלמד על מחלקות תבנית (0185568 01840בת0)). הפונקציה 58011 016% יעילה מבחינת זמן הריצה לפחות כמו פונקציית הספרייה +זספף, משוס שאינה משתמשת במנגנון הפולימורפי ב-++6. לעומת זאת, לכל סוג של משתנה מייצר המהדר פונקציה כזו מחדש, דבר הגורס ליצירה מרובה של קוד. עס ואת, השימוש בפונקציה זו נעשה בצורה טבעית, ללא צורך לבצע המרות מסוג לסוג. מחלקות תבנית מחלקות תבנית מכילות פרמטר עבור סוג האובייקטיס שהן מטפלות בהס. למשל, המחלקה 11% שפיתחנו בפרק קודם, אינה תלויה בסוג האובייקטיס ברשימה. לכן, אפשר לכתוב את המחלקה באופן גנרי, כך שנקבל רשימה עבור כל סוג של אובייקט או משתנה (למשל שלמים או תוויס), ללא כל צורך לבצע המרות של מצביעים, וללא צורך לרשת מהצומת הבסיסי של הרשימה. 0 ++0 ו-009 למתכנת המקצועי מחלקות המכילות אובייקטיס אחריס ומבצעות פעולות של הכנסת אובייקטים או ביטולס, ומעבר על אוסף האובייקטיס במחלקה, נקראות מכולות (פזסחו4)תסס), אוסָפִים, או מיכלים. מחלקות אלו מאופיינות בכך שיש להן פונקציונליות שאינה תלויה בסוג האובייקטיס בהן הן מטפלות. על כן הן מועמדות טבעיות להפוך למחלקת תבנית. הצורה להגדרת מחלקת תבנית, דומה לצורה בה מגדיריס פונקציית תבנית. למשל: <6קץ71 01858> 661866 ) 8% 01858 ו כמו במקרה של פונקציית תבנית, גס כאן אנו משתמשיס במילת המפתח 6₪801866+ ולאחריה רשימת פרמטריס של התבנית המופיעים בין הסימנים "< >". מספר הפרמטריס שאפשר להציב ברשימה אינו מוגבל. כל משתנה מופיע בתוספת המילה השמורה 613888. כשיש מחלקת תבנית כזו, חייב להיות לכל אחד מהפרמטריםס של התבנית שימוש במחלקה לפחות פעם אחת. בסעיף הקודס הגדרנו פונקציית מיוו שהסתמכה על קיוס אופרטור '>" שבדק את הסדר בין שני אובייקטיס. כעת ניתן להגדיר מחלקת תבנית המבצעת תפקיד זה. המחלקה 1658 יכולה לעשות זאת. <1? 01858> 66801866 ] 1688 0188585 :טס %‏ (72 7 ,1ט 6₪0%)7ם6 %ם1 [ ;(2ט > 1ט) מעט660? + ;ן למחלקה 1688 אין כל שדות בחלק הפרטי, והיא משתמשת באופרטור "> לכל שני אובייקטיס מסוג 1, שהוא פרמטר התבנית. אפשר להגדיר מחלקה זו כ-060ו5, כך: <1? 01858> 66801866 ] 1685 ססגוע56 0% (72 7 ,1ט 6₪0%)7ם6 %ם1 [ ;(2ט > 1ט) םמעט6%ע + ו קיבלנו מחלקת תבנית הבודקת את הסדר של שני אובייקטים כלשהם. הפונקציה 0% מחצירה ערך אמת (פטש) אם האובייקט הראשון קטן מהשני. כעת אנו יכוליס להשתמש במחלקה זו באופן הבא : 22 ,1 106 2 6ת11 // 2 <ס6ת1688>1 ו 2 = 2א ((2א ,1א)6₪0%ם11.0) +1 פרק 7: תבניות ב-++6 191 12 >> "2א > 1א" >> סגוסס 1-6 ;1 >> "6ס6מתסססהת 066םת85%28 צשעסט סם661תספ5" >> 6טס0 השורה השנייה מגדירה אובייקט של המחלקה 1668. כשמוגדר אובייקט של מחלקת תבנית, יש לספק את הפרמטרים של התבנית למחלקה. הפרמטריס האלה מסופקיס לאובייקט בתוך ה-"<>'י, שזו רשימת הפרמטרים. דבר זה קורה בשורה השנייה של קטע הקוד שלמלעלה, שבה מסופק למחלקת התבנית הסוג )+םו. השורה השנייה גורמת למהדר לייצר את הקוד המתאיס לאובייקט ו[. ההצהרה על מחלקת התבנית אינה יוצרת קוד, אך השימוש בה יוצר קוד: הגדרת אובייקט השייך למחלקת התבנית. הגדרת אובייקט נקראת בלועזית ת118)10מ18518. | 1 | אובייקטי פונקציות אובייקטי פונקציות (00[608 מסטסמט1) מתנהגים כפונקציות לכל דבר. הם אינס חייבים להיות מחלקות תבנית. יחד עס זאת, יש יתרון לאובייקטי פונקציות השייכים למחלקת תבנית. למשל, נגדיר אופרטור *''י()י למחלקה 1688, ונקבל מחלקה שהאובייקטים שלה מתנהגיס כמו פונקציות. היתרון הוא בכך שנוכל לספק אובייקט מסוג זה לפונקציות תבנית שמצפות לקבל מצביע לפונקציה, או פונקציה שבודקת את הסדר בין אובייקטים. <1? 01858> 66801866 ] 1688 0₪גוע56 % ((2 7 ,1ט 628602)()72קס %6ם1 [ ;(2ט > 1ט) מעט660ץ? + ;ן עתה ייראה כך הקוד הבוחן את היחס בין שני אובייקטיס שוניס : 2 ,1א 6מד 2 <םש6ת1655>1 2 = 1א = 2 ((2א ,1א)11) +1 12 >> "2א > 1א" >> 0006 1-6 ;61תס >> "66תסססהת 066םת5%28 שעסט טם661תספ5" >> ס6טסס 1, האובייקט של מחלקת התבנית, מתנהג בדיוק כמו פונקציה. כשמספקים לו שני פרמטרים, מפעיל המהדר את אופרטור הקריאה לפונקציה, אשר שייך לאובייקט הנוכחי. היתרון של אובייקט המתנהג כפונקציה הוא בכך שאפשר להעביר אותו לפונקציה שמצפה לקבל פונקציה אחרת. 2 ++6 ו-009 למתכנת המקצועי לדוגמה, אפשר לשנות את הגדרת פונקציית המיון כך שזו תקבל פונקציה, או אובייקט המתנהג כפונקציה, כדי לבדוק אס האובייקט הראשון קטן מהשני. נוסיף לפונקציית המיון פרמטר תבנית נוסף, המייצג את פונקציית ההשוואה בין האובייקטים. כעת אפשר להעביר לפונקציה זו אובייקט המתנהג כפונקציה, או פונקציית השוואה. <קתס60 01888 ,1002 01858> 66801866 (קתס קת00 ,0ת6 18662 ,ם1ססס %1)1062ע58502 010% בנסעט ן ₪ְ5%ע11 18 ת6018ת // 2 >= ם ,םמם601ק = 1 ע166 ) (0ם6 > ם61ש6כ) 15 + (1) 116תש (מם>1 86 (םת1ש6ס* ,1*)קתס) 116תט ;-- (ם>1 86 (ם* ,תנ1ססס*)קתס) 116תט %7 (מם=<1) 15 ; (ם* ,1*) ק8שא5 ] ; (1* ,תם₪61*) 580 ; (קחס ,1-1 ,ם601) 50261 016% ; (קעחס ,0ת6 ,50261)1+1 16%ג6 ו כפי שראינו קודס, להגדרת האובייקט 168 דמוי הפונקציה השתמשנו באופרטור ">", ולכן אובייקט וה אינו מתאים עבור מצביעים לתוויס (מחרוזות). כעת אפשר להעביר את הפונקציה טגוסעו% לפונקציית המיון. דרך שנייה היא להגדיר מחלקה נוספת. 2 | שימוש בפרמטר קבוע למחלקת תבנית ראינו כבר שיש בעיה כשמשתמשיס במחלקה 8 עבור מחרוזות, כי השימוש באופרטור ">" אינו תקף עבור מצביעים לתוויסם. ++6 מאפשרת להגדיר מופע של מחלקת תבנית. בצורה זו אפשר להגדיר מופע של המחלקה 1658 המתאים למצביעיס לתוויס : ) <* ע8ת1685>0 6סגוע56 %פתסס (82* ע8%ם0 ,51* עַַת6) ()628602קס %6ם1 [ ;(0 > (82 ,81)קת0ע5%2) םתעט66ע + ;ן כשמגדירים מופע מיוחד של מחלקת תבנית, אין המהדר יוצר את הקוד למופע ה אס הוא מגלה שנעשה כבר שימוש בפרמטר התבנית הנתון. כאשר המהדר מגלה שימוש במחלקת התבנית עבור *ז49ת6 למשל, הוא ישתמש במה שהגדרנו, ולא ייצר מחלקה נוספת עבור מצביע לתוויס. פרק 7: תבניות ב-++6 193 עס ההגדרות שלנו אנו יכוליס כעת להשתמש בפונקציית המיון בדרך הבאה: ()מ1נהת %ם1 ָ ;]0 7,690 22 ,20 257 57 ,8 397 ,1,5,3 + = [] מחב.: 36 ; (9ת81260%)1 / (ע812601)82% + 822 = 86ם6* 6ם1 ,"1%%תת1ת" ,"16028" ,"תסתנםפ5" ] > []%ע882* כַהַת0ס ;| "152861" ,"האסטנ1ע" ,"118הץ" ,"16ם2ס" ; (*81ת812601)0 / (2ע812601)58 + עע88 = 0םת56** מַהבםת6 ; (0ם6 ,עע6)8ת1עס ;(()<%6ם1688>1 ,6-1ם6 ,50201)822 16%ט ; (0ם6 ,5ע8)%םתנ1עס ; (0ם86 ,85822)%ם1עס ; (()<*85ת1685>0 ,6-1ם806 ,50201)5822 16%ט ; (0ם86 ,85822)%ם1עס 7 תעגו6%ץ ו הגדרנו כאן שני מערכים. המערך הראשון מכיל שלמיס והמערך השני הוא של מצביעים לתווים. כעת, כשקוראים לפונקציית המיון יש לספק אובייקט המבצע את ההשוואה. במקרה של מערך השלמים, מסופק אובייקט המבצע השוואה בין שלמים. הביטוי ()<+1035>12 מספק אובייקט כזה, ולעומתו הביטוי <םנ>1658 הוא סוג (סטעו) של אובייקט (כמו ש-)תו הוא סוג של משתנה). כאשר יש למיין את מערך המצביעיס לתווים, מוסרים לפונקציית המיון את אובייקט ההשוואה ()<*1955>0091. במקרה זה המהדר אינו יוצר קוד למחלקה זו, משוס שהגדרנו קוד ה באופן מפורש. 3 | דוגמה - רשימה מקושרת בפרקיס הקודמיס הגדרנו רשימה מקושרת 180 %06מ11). בסעיף וה נראה כיצד ניתן להשתמש בתבניות ברשימה המקושרת, כדי לתמוך בכל סוג של אובייקט ברשימה. כמו כן, נראה שפונקציות כגון ווק תפעלנה גס עבור הרשימה המקושרת. 22 יק רשימת תבנית - ניסיון ראשון כדי להגדיר רשימה כפולה בכל צומת ברשימה, דרושיס לנו מצביעיס לתחילת וסוף הרשימה, וערך שיש לשמור בצומת. לפיכך, צומת ברשימה כזו ייראה כך: <1? 01858> 66801866 ] 006 118% 56206 ;%אסם* <66>1סם 1186 ;טסעק* <06>1סם 1186 ; 6גו1 אע 7 4 ++6 ו-009 למתכנת המקצועי ההגדרה של מצביעיס לצומת הקודס ולצומת הנוכחי נעשית באמצעות פרמטר התבנית 1. מכיון שבהגדרת המחלקה אין אנו יודעיס את סוג פרמטר התבנית, עלינו להשתמש בשס שלו בתוך "<>". הרשימה עצמה מכילה מספר לא קבוע של צמתים כאלה, ומוגדרת כך: <1? 01858> 66801866 ] 118% 01858 2+ <00>67סם 1186 :טס ] (8081 71 8%ם6)00ת6סק8 18בסע ;<006>1ם 118% שסם = ס* <086>1ם 115856 ;81 = 6ו1ה8ט<-ס לן בכל פעס שנשתמש במחלקה 118% עבור סוגים שוניס, ייצר המהדר את הקוד מחדש עבור כל סוג. לכן ייצר קטע הקוד הבא ארבע מחלקות שונות, שהקוד שלהן משוכפל. 2 <%ת11585%>1 <016ו115%6>00 1156>11086< 2 115%>65%00< 2 אפילו התוכנית הקטנה ביותר תהיה בעלת נפח גדול. מכאן ברור, שגישה זו אינה יעילה ועלינו לנקוט בדרך פעולה שונה. 02-52 7/2 שימוש בירושה ממחלקה שאינה תבנית ראינו שמנגנון התבנית מייצר מחלקה ואת כל הקוד שלה בכל שימוש בתבנית עס סוג שלא השתמשו בו עדיין בתוכנית הנוכחית. תכונה זו גורמת לייצור קוד רב. הדרך הטובה להתגבר על בעיה זו היא להגדיר מחלקה בסיסית שמבצעת את השירותיס הבסיסיים של הרשימה. כשיש לנו מחלקה בסיסית כזו, נגזור ממנה מחלקה ליישוס השירותיס המסוימיס של הרשימה, על פי סוג התבנית. כאשר גוזריס מחלקת תבנלת (01855 101816מ16) ממחלקה אחרת (שאף היא יכולה להיות מחלקת תבנית), מתקיימים כל חוקי הגזירה לגבי המחלקות המעורבות ביחס הירושה (או הגזירה). בהתאם לכך, תהיינה לנו מחלקות בסיס'ות (0185809 0886) שיספקו את שירותי הרשימה והמעבר על הרשימה. מחלקות התבנית ירשו מהמחלקות האחרונות וישתמשו בשירותים אלה. לכן, משלביס ירושה ותבניות כדי לקבל מחלקה חדשה. פרק 7: תבניות ב-++6 195 בצורה זו אנו מטפליס בבעיית ייצור הקוד על ידי המהדר, אשר אינו צריך עוד לייצר קוד עבור המחלקות הבסיסיות שאינן מחלקות תבנית. בפרקיס הקודמיס כבר הגדרנו רשימה. נשתמש ברשימה שיצרנו בפרקיס הקודמיס אך נשנה את השמות בצורה הבאת: >= +18 - ייקרא מעתה +18 0886. > ז1)6 118% - ייקרא מעתה 1067 118% 0886. >= אמ - ייקרא מעתה 1118 886ס. שינוי השמות נעשה רק למען נוחות המשתמש במחלקה זו ואינו מחויב. בספריות שונות נמצא ששס מחלקת תבנית היורשת ממחלקה שאינה כזו, הוא 61%6, כלומר תוספת של + לפני השם. המחלקות הקודמות מומרות בצורה הבאה לשמות החדשים שלהן (המחלקות נמצאות בקבציס 110.8, 115.00 : ) %ם11 0886 01858 // 88 6 ;ן 01885 0886 1186 16062 ) // 88 6 :טס 6 88 // ()ףת6עעטס 666* %ם11 85856 [] ;%תסעעטס םעט66ע + // 88 6 ;ו למחלקה 166 1180 0886 הוספנו פונקציה אחת בלבד, המאפשרת לקבל את הצומת הנוכחי. פונקציה גו התוספה רק מטעמי נוחות (במקוס להפעיל את האופרטור **י). ) 118% 0886 018588 68 8ה // :טס 68 8ב // [ ;60%68רססם מעט%שע + 00286 ()5126 6ם1 ;ו למחלקה )18 9886 הוספנו פונקציה שמחוירה את מספר האלמנטים שנמצאים ברשימה. כל שאר הפונקציות נשארו כשחהיו. נירש את המחלקה החדשה מהמחלקה של הרשימה שהיתה לנו בפרקים הקודמים. נעשה ואת כך: <1? 01858> 66801866 ] 118% 08886 110סטס : 1186 01858 6 ++0 ו-009 למתכנת המקצועי 7 מ118₪ 01888 6₪מם16ש1 ] אםת11 0886 110סטק : 66סםת 1186 562006 יח 7 81 ; [+ (ט)81ט : (ט6 7 86ם6)00סם 115856 ;ו :טס ;6סץ 66סם 66סםת 11585%>71<::1186 66661 55200%0%ת60 צץ6026 // ()118% נ [ ;()811 8361666 + ()1186- 06 םתס 0068ם 811 8616668 // ()811 661666 16סט (0 < ()8126) 116םש ) [ ;()680ם 6ט00ת1185%::20 886כ(*6סץ6 6סם) 061666 (81ט8 71 8%מ0)00םת6סק8 ב1בסטע [ ;((6)081סץ% 06סם טסםת)0ם6סק11585%::8 085856 ] (6081 71 8%ת562%)00ת1 ב1סט [ ;((6)081סץ6 06סם חאסם)8626םת11856::1 08856 ] (8081 7 8%ת00 ,6208 1862 1186 62%)08586פ8פת1 ש1נסט [ ;((1הט)6סץ6 66סת טסם ,08ק*)862%םת118%::1 08856 ] 0 ₪6 6608 // () 680 7 ;()680ם::118% 886כ(*6סץ6 606סם) = ם* 6סעץ6 6סם ) [ ;81ט<-6ם ם%גמ6₪%ע2 1 66 66608 // ()6811 ך ;()118%::6811 886כ(*6סץ6 66סם) = 61* 6סעץ6 6סם ) [ ;81ט<-%1 מעגו6%ץ ] ()680ם 6טסת26 ך ; ()680 00076ת6ע::1186 856ס(*6קץ6 66סם) = ₪1* 6סץ6 6ססת ; (81ט<-61) 81טםע ץ 2 061606 ; [8טע מעגו26% 1 ()6811 6טס260 ך ;() 6811 6ט118%::2000 8586כ(*6סץ6 66סם) ‏ = 61* 6סץ6 6ססת ; (81ט<-61) 81טםע ץ 2 061666 ; 8[1טע מע60ת2 ] 1 015 068תע0006 811 סשטסת6ץ81(;//2ט6 7 ספתסס) פטסתפע 16סט // 15628%0% 1186 // // ] 1662 118% 0886 110סגמק : 1062 1186 01885 :פטס פרק 7: תבניות ב-++6 197 (1ם)1062 118% 0886 : (1מ* %ם11 1661)0886 1186 1 ()++8006028%02 1665 115856>71<::1186 [ ;18ת%* 26009 ;()6א6ת + (6ם1)++ע8%0ע2סקס 166% 1186>7<::1186 ; (18ת%*)88615 1662 1185%>7<::1186 ; () 6א6ת 2 תעג6שץ 11856>1<::1186 16065 800628602--)( [ ;15םת6* מעטס6שע ;()טסעס + 1 (%6ם1)--0028%02 1665 11856>71<::1186 ; (18ת%*)88615 1662 1185%>7<::1186 ; () טסעס 2 תעטססע ] ) ()*עסם8עססס 7 ; () >תסעעגוס 6*(86%קץ6 066סם) = ת1* 6סץ6 6סת ; [8ט<-0ת1 תעט660ץ ;ו 2 100 1668 1185%>71<::1186 6661קץ6 מ2ע2600 + ()ם601ס 6סץ6 1665 [ ;(()680ם::115%6 6)08586סץ6 1665 םעט26% ) ()0ם6 6סץ6 1665 [ ;(()11ם(*אםת11 6))886סץ6 1665 ו מחלקות מקוננות בפנים הרשימה בתוך מחלקת הרשימה (18) מוגדרות שתי מחלקות מקוננות (01885809 08000ם): 6 +1154 ו-1607 +118. כשיש מחלקות מקוננות, אין גישה אליהן פרט למחלקה המכילה אותן. גם למחלקה המכילה אין גישה מיוחדת לשדות של המחלקות המקוננות, או המוכלות. המחלקה ₪066 +18 מייצגת את הצומת ברשימה. המחלקה ז6וג 184 מייצגת את סורק הרשימה. המחלקה 1061 11% מוגדרת בחלק הציבורי של המחלקה 11, לכן יש גישה לאיטרטור לפונקציות, או אובייקטיס מחוצ לרשימה. לעומת ואת, אס מחלקה מקוננת מוגדרת בחלק הפרטי (כמו 066 11%6) של מחלקה אחרת, אין לאף פונקציה, או מחלקה אחרת, גישה למחלקה זו פרט לפונקציות של המחלקה המכילה, או של חבריס של המחלקה המכילה. 8 ++0 ו-009 למתכנת המקצועי מחלקות מקוננות המוגדרות בחלק השמור של המחלקה המכילה, נועדו לאפשר למחלקות היורשות מהמחלקה המכילה גישה אל השדות הציבורייס שלהן בלבד. מחלקות מקוננות שמוגדרות בחלק הציבורי של המחלקה המקוננת, נועדו לאפשר גישה לכל פונקציה ולכל מחלקה אחרת, לשדות הציבורייס שלהן בלבד. בכל מקרה, מוגבלת הגישה רק לחלקיס הציבורייס של המחלקה המקוננת, או המכילה. כדי לאפשר רמת גישה גבוהה יותר יש להשתמש במנגנון החבר, דבר שאינו מומלץ, פרט למקרים מיוחדים (כמו, איטרטוריס). היתרון של הגדרת מחלקה מקוננת בכך שאנו לא מזהמיס את מרחב השמות הגלובלי של התוכנית. דבר וה חשוב מאוד בתוכניות גדולות המשתמשות במספר גדול של ספריות, עס סבירות גבוהה להתנגשויות בין שמות של ספריות. ב-++6 יש כלי אחר המטפל במקרה זה והוא ס6סִַּסִפסוַמגּת. נלמד אודות כלי זה בפרקים הבאים. בכל מקרה, יש לדעת שבעת כתיבת שורות אלו אין מהדריס התומכיס באפשרות זו. צומת ברשימה צומת ברשימה (0066ם) הוא מחלקת תבנית המכילה אובייקט מסוג 1 שהוא הפרמטר של התבנית. לפיכך, הצומת ברשימה תלוי בסוג האובייקט שיהיה ברשימה. לכן, הצומת ברשימה משתמש בפרמטר של התבנית 1, כדי לייצג את הערך שנשמר בצומת הנוכחי. הואיל והצומת ברשימה מצוי בחלק הפרטי שלה, הגדרנו מחלקה זו כרשומה (89011000). שדות המחלקה הזו פתוחים בפני כל הפונקציות של המחלקה רשימה. הבנאי של מחלקה זו מאתחל את האובייקט בצומת (1צי) בעורת בנאי ההעתקה של האובייקט בצומת. לכל אובייקט ב-++6 מובטח שיהיה בנאי כזה, ולכן הגדרנו את הבנאי של הצומת בצורה זו. הגדרה אחרת לבנאי יכולה להיות : [ ;ט= 081 + (ט6 7 86םס6)0סם 115856 הבעיה בהגדרה זו היא שאנו מניחיס שקייס בנאי ברירת מחדל (ע507-0010ת60 06191111) לאובייקט שבצומת, וכמובן שלא מובטח לנו קיומו של בנאי כזה. בעיה אחרת היא, שאפילו אס בנאי זה אמנס קיים, תתבצע תחילה קריאה לבנאי ברירת המחדל, ורק לאחר מכן קריאה לאופרטור ההשמה של האובייקט בגוף הבנאי של הצומת ברשימה. דבר וה אינו יעיל, כי הוא מחייב קריאה נוספת לפונקציה (בנאי ברירת המחדל). האיטרטור גם האיטרטור זטוו :18 הוא מחלקה מקוננת, אשר יורשת מהאיטרטור הבסיסי. גם היא מחלקת תבנית המשתמשת בפרמטר 1 של מחלקת התבנית המכילה אותה, +1:8. כמו באיטרטור הבסיסי, גם כאן מוגדריס האופרטוריס לקידוס האיטרטור, או חזרה לאובייקט קודם. שני סוגי פעולות אלה מוגדריס בשתי הסמנטיקות של פעולות א661זם ו-צ:/5₪1. בסוג הראשון מקדמיס תחילה את האיטרטור, ולאחר מכן מחזירים ייחוס אליו. בסוג השני מחזירים ייחוס לאיטרטור, לפני פעולת הקידוס. פרק 7: תבניות ב-++6 199 כזכור, פועל האיטרטור כמצביע, כדי לאפשר לאלגוריתמים גנריס לפעול על רשימות. לפיכך, קיים אופרטור **יי שמחזיר את תוכן הצומת הנוכחי באיטרציה, כשהסוג המוחזר הוא מסוג פרמטר התבנית. רשימה הרשימה עצמה יורשת מהרשימה הבסיסית. אבל כשרוצים להכניס ערך כלשהו לרשימה, מוקצה צומת חדש שמחזיק את הערך הנדרש, והוא זה שמוכנס לרשימה. הטיפול בזיכרון מוטל עתה על הרשימה, ולא על המשתמש בה. לכן, הקוד של המשתמש ברשימה פשוט הרבה יותר. כאשר הרשימה יוצאת מתחוס ההגדרה, נקרא המפרק שלה ואו היא משחררת את כל הויכרון שהקצתה במהלך חייה. שחרור הזיכרון מתרחש גס כשמבטלים צומת כלשהו ברשימה. פונקציות המבטלות את האיבר הראשון, או האחרון, צריכות לשחרר את הוזיכרון שאיחסן את הצומת הזה. השינוי הגדול הוא כאשר רוציס לבטל אובייקט ברשימה. הערך שרוצים לבטל נמסר לפונקציה 6טסמסע. היא מגדירה איטרטור, סורקת את הרשימה ומבטלת את האובייקטיס הזהים לאובייקט הנתון לה. מכיון שהמפרק של הצומת הבסיסי אםו! 0886 אינו וירטואלי, כשמפעיליסם את אופרטור 46166 יש להמיר את הכתובת לכתובת המתאימה לצומת ברשימה שיורש מהצומת הבסיסי. פעולה זו נעשית תמיד כשמבטלים אובייקט מהרשימה. 66801866 >01858 ?1< (צ6%6 71 56ת00) סטסת1156>1<::26 ב1בסט ; (()86ם16)6 ,(()ם601כ)15 6סץ6 1665 ] (16 =! 18) 116תט ]) (צץ%6 == 18*) 15 5% 66 120 6טסת6? 6םתטס+ // ;()6תסע2טס 18.66% = ס1ס* %ם11 85856 8+ ; (ק1ם) סטסת6ע: :118% 886 ;2 (*ס6סץ6 66סם) 061666 ++15; ו כאשר מגדירים פונקציית מחלקת תבנית מחוץ למחלקה עצמה, יש להגדיר את הפונקציה בתוספת הפרמטריסם של התבנית. למשל, עבור רשימה היה לנו פרמטר אחד של תבנית 1, ולכן עלינו להגדיר את הפרמטר הזה גס בהגדרת הפונקציה. בנוסף לזה, שס הרשימה הוא <1>+18, כאשר 1 הוא הפרמטר של התבנית. למשל, אם היו שני פרמטרים, היינו צריכיס לכתוב: <72 , 1156>11. 0 ++0 ו-009 למתכנת המקצועי ברשימה יש שתי הגדרות סוגיס המתבצעות בעזרת 106661. דבר וה נעשה כדי לחסוך בכל פעס את הכתיבה מחדש של סוג הצומת ברשימה, או של האיטרטור, כי הגדרה מורכבת כזו עלולה לגרוס לשגיאות. אס נרצה לשנות את סוג הצומת, או האיטרטור, נשנה רק את 100661. כמות הקוד שהיינו צריכיס לכתוב, לו היינו כותביס את הרשימה ואת האיטרטוריס מהתחלה כתבניות, היתה גדולה מאוד, ולכן גס הקוד שהיה המהדר יוצר היה גדול. אנו חוסכים כאן קוד רב. מומלצ להשתמש במידת האפשר במחלקה בסיסית שאינה תבנית, ולעשות במחלקה הבסיסית את רוב העבודה. המחלקות היורשות צריכות להיות קצרות, וכך לחסוך קוד המיוצר עבור כל שימוש במחלקה. נוסף לכך, יצירת קוד גורמת לזמן הידור ארוך יותר, כי המהדר צריך ליצור את הקוד. בנוסף, לא הגדרנו פונקציות וירטואליות ולכן הטיפול ברשימה יעיל ומהיר מאוד. אכן, בעזרת תבניות בצורה מבוקרת אפשר להגיע לתוכנה יעילה ובאיכות גבוהה מאוד. כשאנו מנצליס את אפשרות לרשת את מחלקת התבנית ממחלקה בסיסית שאינה מחלקת תבנית, אנו מונעיס ייצור קוד מיותר על ידי המהדר. פונקציית מיון לרשימה הפונקציה הגנרית 501% א₪16%ף אינה יכולה לפעול על רשימה, מכיון שהיא משתמשת באופרטוריס שדורשיס סדר בין מצביעיס. נשתמש באלגוריתם גנרי המאפשר למייןו את הרשימה בשיטת 8014 560600ם1. האלגוריתס עצמו פועל בשתי לולאות, חיצונית ופנימית. ראינו שהאלגוריתס מקבל תחוס למיון ופונקציה או אובייקט-פונקציה, לצורך השוואות. בכל שלב של הלולאה החיצונית מוקטן התחוס הכללי באובייקט אחד. דבר זה נעשה על ידי קידוס התחלת התחוס, האיטרטור 5811 בכל שלב של האלגוריתס מועבר האובייקט הנוסף (המסומן על ידי 581) למקומו בתחוס. הלולאה הפנימית מתחילה עס האובייקט הראשון והשני, ובכל שלב כוללת תחוס גדול יותר. בשלב השני, של הלולאה הפנימית, מטופליס שלושת האובייקטיס הראשוניס. בשלב השלישי מטופליסם ארבעת האובייקטיס הראשונים. בכל שלב של הלולאה הפנימית, התחוס הקודם כבר ממוין, לכן מכניסיסם את האובייקט הנוסף למקוס המתאים לו. <ת160 01858 ,02080 01888 ,1002 01858> 01866ת66 ,0 1060 ,םת601ק 802%)166%2 םת0ס261ספת1 ב1סעט (מ1%668 ת166 ,62% 02686 ; (ם601) 5%82% 166% +; ] (0ם6 =! 6ע568) 16נ1תט ; (8%82%)%ם00228 , (5%82%6)%א6םת 166% %2 + = 160 ?6 פרק 7: תבניות ב-++6 201 + ((ת166 ,%א6ם*)42%) 116תט ;%אסם* = סתסעעגוס* ;%ת6עעטס-- %2 (םת601 == סמסַעעטס) 15 ;6אסם-- ] ;1 = סת6עעטס* 2+ ו אלגוריתם מיון וה הוא ברמת סיבוכיות (ם*ם)0 (האם תוכל להוכיח זאת!), לכן הוא פחות יעיל מהאלגוריתם 8011 אסוטף. אלגוריתס ה אינו מחייב השוואה בין כתובות, לכן הוא מתאים לרשימה. כמו 804 אסוטף גם אלגוריתס זה פועל על אזור הזיכרון הנתון לו על ידי התחוס, ואינו מעתיק את הנתונים לאזור זיכרון חדש. כמו האלגוריתס הקודם, כך גם אלגוריתם זה יכול למיין מערכיס בסיסיים, או מכולות. 3 שימוש ברשימה כשנתונה רשימה, אפשר להשתמש בה בשני אופנים. בצורה הפשוטה נכלול בה ערכים כלשהם, שאנו מעתיקיס אותס לצמתים שוניס ברשימה. השימוש השני הוא לכלול בה מצביעים, ולא ערכים. כשיש לנו רשימת מצביעים, ייתכנו מצביעיס המשותפיס למספר רשימות. במקרה זה, עלינו לנהל את הזיכרון בעצמנו, משוס שהרשימה אינה מטפלת בזיכרון שהוקצה על ידי המשתמש בה. במקרה זה, קיים יתרון שאנו יכוליס עדיין להשתמש ברשימה בצורה פולימורפית (למרות שהרשימה חסרת פונקציות וירטואליות). שימוש ברשימה על ידי העתקה כאשר משתמשיס ברשימה על ידי העתקה, מגליס שכל ערך המוכנס בה מועתק אליה וברשימה יש רק העתק של הערך. לכן, היא אחראית להקצאה ושחרור של הציכרון לכל צומת כזה. כמו כן, אין ערכיס המשותפיס למספר רשימות כאלו. כאשר הרשימה מחזיקה סוג מסוים ויחיד של אובייקטים, היא נקראת רשימה הומוגנית (1181 8606088סותסו). הרשימה שהגדרנו בצירוף האיטרטור יכולה להיות מועברת לאלגוריתמים שונים כמו זמוזק, מכיון שאיטרטור הרשימה מתנהג כמו מצביע רגיל של ++06. אפשר גס להפעיל את האלגוריתמיס הגנריס האלה על כל מערך ב-++6. לדוגמה, הקוד הבא הוא חוקי: ;סמ ,1,601 07 70 2-05 12 + = []עע8 6ת1 ;(5ת812601)1/ (22ע812601)8 + מעע8 = 6ם8226* 6ם1 2 <6ם1158%6>1 ; (1) סתסססה. 11 ; (2) סתססס8. 11 ; (0)5ת6סס8. 11 2 ++6 ו-009 למתכנת המקצועי ; (6) 562%ם11.1 2 >> "8000 ת86%%10ת1 061026 ם" >> סגוסס ;(()86ם11.6 ,()ם661כ6)11.2םנ1נעס ; (קתף ,()<%ת8268%>1 ,()0םת11.6 ,()ם8026)11.0601 תסנסעס6פת1 2 >> "0ע80% ת810ע56%ת1 81665 ת" >> סוסס ;(()86ם11.6 ,()ם661כ.6)11םנ1נעס 2 >> "8ע80 מ610ע6פת1 261026 צץ8ע822 ת" >> סגטסס ; (0מ82206 ,עע6)8םתנ1עק ; (קתסף ,()<%6םת9268%>1 ,06ם8220 ,5ע802%)8 ת%10ל6פת1 ; (0ם8226 ,6)852םנ1עס למעשה, במערך זג יש סדרה של ערכיס הוהה לערכים ברשימה. תחילה מודפסת הרשימה המקורית. אחר כך מפעיליס עליה אלגוריתס של מיון, ולבסוף היא מודפסת שנית לפלט הסטנדרטי. תהליך דומה עובר על המערך. שים לב לכך שממיינים הן את המערך והן את הרשימה על ידי אותה פונקציית תבנית! שימוש ברשימת מצביעים שימוש ברשימת מצביעיס קשור בדרך כלל לשימוש פולימורפי ברשימה. בפרק הקודם בו למדנו על פולימורפיזם (ותפוחסףסומץ!סק), ראינו דוגמה המציירת צורות על המסך. בדוגמה ההיא היתה רשימה של צורות מסוג שונה, כלומר, היו אובייקטיס מסוג שונה. רשימה כזו נקראת רשימה הטרוגנית (1180 1616708660058). כדי לצייר את הצורות, סרקנו את הרשימה והפעלנו את הפונקציה 8 לכל צורה בנפרד. מכיון שהפעלנו את הפונקציה הזו דרך מצביע נחשבה הפעלה גו פולימורפית. כלומר, הפונקציה שהופעלה על ידי המערכת הפולימורפית היא זו שהתאימה את הפונקציה לסוג האובייקט. אפשר להשתמש ברשימה שלנו כרשימה של מצביעים, אך אז עלינו לשחרר אותס בעצמנו בעת הצורך. נראה כיצד אותה הדוגמה, העוסקת בצורות וציורן, נראית בעזרת רשימת התבנית. נציג רק את קטעי הקוד המתאימים ואת אלה שישתנו בעת כתיבה בדרך זו. שאר הקוד והה לדוגמה הקודמת. הקוד לתוכנית הנוכחית נמצא בקובצ .מס המחלקה 53406 אינה יורשת מהצומת הבסיסי של הרשימה. רשימת התבנית מוגדרת כרשימת מצביעים ל-58806, ולכן אין בצורך בירושה הקודמת. )+ 806םת5 01855 :טס [+ ())סס8ם5 [+ (8 תם50266)א428 ב1סט 81ט26נט ;ו כמו בדוגמה הקודמת, גם כאן יורשות המחלקות המייצגות צורות שונות מהמחלקה 0, שיש לציירן על המסך. מחלקות אלו מגדירות מחדש את פונקציית הציור. פרק 7: תבניות ב-++6 203 ] 5806 110סמטק : %םנ1סקע 018858 ;ץ,א %ם1 :טס [ ;סץ=ץ ;0א =א + (סץ %ם1 ,סא 6ת5)1ת1סק (ע680 מם50266)א8428 ב1סע [ ;(ץ,א)פטס.ת80 ) ;ו ] 5806 110סטס : 6ם1ם 018588 ;1 ,1א 6ם1 22 ,2א 6ם1 :טס (2סץ פ%ת1 ,02א %ם1 ,1סץ סםת1 ,01א 6מם6)1םת1ת [ ;2סץ = 2ץ ;02א = 2א ;1סץ = 1ץ ;01א = 1א + ; (8502 ת50266)א028 ב1סע ;ו האלגוריתס של פונקציית הציור של המחלקה 6מו.1 לא השתנה, ולכן אינו מפורט כאן. האלגוריתס המצייר את כל הצורות על המסך מקבל רשימת צורות אפשריות. הפונקציה מגדירה איטרטור שמאותחל לתחילת הרשימה ומשתמשת בו כדי לסרוק את הצורות ברשימה כדי לצייר אותן זו אחר זו. כשמשתמשיס ברשימת הצורות בדרך זו, אין כל צורך להמיר כתובות. (ע850 תם50266 ,6511856 <*6ק8מם115%>92)א328 הנ1בסט ו ;()ת8118%.0001 = 1 1662 826*<::1186םת1185%6>5 ;()502.01682 ]1 (()6ם8115%.6 =! 1) 16נ1תט ;1* = ס5* סַקַם5 ; (502) 0287<-50 ; ב++ ]) ; () 028.ע502 ו הפונקציה הראשית מגדירה את רשימת הצורות, יוצרת אותן, ואחר כך מכניסה אותן לרשימה. הצורות שנוצרו יכולות להופיע בשתי רשימות, או יותר. בדרך הזו של שימוש ברשימה אנו רואיסם כי המשתמש ברשימה היקצה את הזיכרון עבור הצורות שברשימה, ולכן מוטל עליו לשחרר את הזיכרון שנתפס. דבר זה אינו נעשה בקטע הקוד, ואני משאיר לקורא לעשות זאת כתרגיל. הרשימה רק מבטלת את הצמתיס שהיא הקצתה. ()מנאת 6ם1 ו ;880068 <*806ם118%6>9 4 ++6 ו-009 למתכנת המקצועי 50266 22 ;((11 ,19 ,6)10,1ת11 )סתסססה. פססהם5 ;((10 ,55 ,20 ,6)6)40ם1 ) סמסססה. 58065 ;((20 ,6)10םת1סקע טחטסם)מת6סקה65.8ק8ם5 ;((10 ,6)15םת1סקע טחטסם)מססקה. 65ַק8ם5 ; (502 ,8008ם5)ש028 שסת שסת 02 תמגו6%ת ו מכיון שהרשימה אינה משחררת את המצביעים שהוכנסו לצמתיס שלה, היינו רוציס לאפשר פונקציונליות זו בצורה מרוכזת, כדי שהדבר לא יידרש מכל משתמש ברשימה, שייאלצ לפתוח אותה מחדש. השאלה היא האס לפתח פונקציה שמשחררת מצביעיס ברשימה, או האס ניתן לפתח מנגנון המאפשר להפעיל פונקציות על הרשימה! אפליקטורים ראינו שיש בעיה של שחרור זיכרון כשמשתמשיס ברשימת מצביעים. אפליקטורים (8011081018) הס אובייקטיס המאפשריס להפעיל פונקציה כלשהי על האובייקטיס שנמצאיס ברשימה. לכן, אפליקטור הוא פתרון כללי לבעיית השחרור. במידה שקייס אפליקטור כזה, אפשר להפעיל על הרשימה פונקציה שמשחררת אובייקט (ולמעשה, מפעילה אופרטור 061606). האפליקטור שנגדיר כאן הוא מחלקת תבנית הפועלת בתחוס מסוים, כמו כל האלגוריתמיס הגנריס שהגדרנו. האפליקטור נראה כך: <סתטת 01888 ,1002 01858> 66801866 ) 1108%02סק8 01855 מע6210ק 60 תס1פסתט+ 6ם6 // ;6+ סתגות :טס (60)10%תט5 : (610%6 סתגטת 5%6ת1108%602)00סק8 0 ; (0ם6 1062 ,ם6081ס ע1662)ץ1סק8 פנסט (0ם6 166% ,ת601ס 166%2) ()628602קס %ם1 [;1 תעטס6ע ;(0ם6 ,ם601כ)ץ1ססה 1 ;ו האפליקטור הוא מחלקת תבנית שמקבלת שני פרמטרי תבנית. הראשון, איטרטור שמתנהג כמצביע והשני, סוג הפונקציה שיש להפעיל. לאפליקטור יש שדה יחיד שהוא הפונקציה שתופעל על תחוס נתון. הפונקציה יכולה להיות פונקציה אמיתית, או אובייקט המתפקד כפונקציה. הפונקציה צְ1סְק8 עוברת על תחוס נתון ומבצעת את הפונקציה הנתונה לה, כל עוד הפונקציה הנתונה מחזירה ערך השונה מאפס. היתרון של הגדרה כצו לפונקציה ע1מק8 הוא שאפשר להפעיל את האפליקטור על תחוס נתון, ולא על כל המערך, או כל הרשימה. בכל הפעלה של האפליקטור נבחר תחוס חדש. פרק 7: תבניות ב-++6 205 <סתטת 01888 ,1002 018558> 66801866 (0ת6 1662 ,םת601כ 166%2)ץ1קק8::<סתטץ ,1108602>1%62קק8 בנ1בסט ] (8ם6 =! מםבחסס) 1ש ( (מ601ס*)סםט5!) +1 2%; ; ת5601++ ו בנוסף, לאפליקטור יש אופרטור קריאה לפונקציה - () ז0001960 - המאפשר להשתמש באפליקטור כזה כפונקציה לאפליקטור אחר. כשהאפליקטור נתון לנו, אנחנו יכוליס לנצל אותו כבר עתה, לשני השימושיס שלמדנו. אנו יכולים, למשל, להשתמש באפליקטור למטרת הדפסת אובייקטיס ברשימה, או בכל מערך אחר. 1 | הדפסה בעזרת האפליקטור כדי להשתמש באפליקטור צריך להגדיר פונקציה, השולחת אובייקטיס כלשהס לפלט הסטנדרטי. אפשר גס להגדיר אובייקט שמתנהג כפונקציה, בדרך הבאה: <1? 01858> 66801866 ] עססתנ1עס 06גע56 (81ט8 7 5%ם00) ()628602ק0ס 6ם1 [ ;1 תע6%0? ;" " >> 81ט >> סטסס + ו ע)מעק היא מחלקת תבנית שמדפיסה כל אובייקט לפלט הסטנדרטי. המחלקה מגדירה את אופרטור הקריאה לפונקציה ומשתמשת באופרטור הסטנדרטי (>>) לניתוב אובייקטים לזרס כלשהו. אופרטור הקריאה לפונקציה מחזיר ערך 1, כדי שהמעבר על האובייקטיס בתחוס הנתון יכלול את כל האובייקטים, ולא ייפסק לאחר האובייקט הראשון. עבור מחלקה כלשהי 1 צריך האופרטור ''י>>:' להיות מוגדר עבור מחלקה זו, כדי שאובייקט הפונקציה ז6)מוזן יוכל לפעול על המחלקה. ;7( ,6 ,5 ,4 ,3 ,1,2) =[]81 6מ1 ;(()<6ףם62>1סת1עק)6ע2ק < <6ם65>1סת1עק ,*%םת1>ע1168602סס8 ; ((5ם812601)1 / (812601)81 + 81 ,6)81עס קטע קוד וה מגדיר מערך של 7 שלמים. לאחר מכן, מוגדר אפליקטור המתאים למערך של שלמיס (הפרמטר הראשון של התבנית מקבל מצביע לשלמים) ומקבל אובייקט מסוג 6)מוזק. לבסוף, נעשה שימוש באפליקטור, כדי להדפיס את המערך לפלט הסטנדרטי. אס כן, האפליקטור יכול לחסוך לנו את כל הפונקציות העוברות על תחוס המוגבל בין שני איטרטוריס, ומבצע פעולה על כל אובייקט בתחוס. 6 ++6 ו-009 למתכנת המקצועי 2 | פירוק בעזרת האפליקטור באופן דומה להדפסה בעזרת האפליקטור, אפשר גס לפרק אובייקטים, הנמצאיס ברשימת המצביעים. כאן נראה רק את קטעי הקוד שישתנו בתוכנית המציירת צורות, כדי לא לחזור על דבריס ידועיסם. הקוד המלא נמצא בקוב מט3.6וץ001. כדי לפרק את האובייקטיס ברשימת הצביעים, נגדיר אובייקט-פונקציה (09[60 מסג0סםט)) שכולל את אופרטור הקריאה לפונקציה. אופרטור וה מקבל מצביע לצורה ומפעיל את המפרק שלה. האופרטור מחזיר 1 כדי שהאפליקטור יסרוק את כל האובייקטיס בתחוס הנתון. 1 ץ0ע60685% 6ק80ם8 6סגטע56 ]) (ק5* 806ם9) ()628602ק0ס %6ם1 ; () 52876=: : 806ת5<-50 ;1 תעו66ץ ל בפונקציה הראשית נגדיר אפליקטור שהפרמטר הראשון שלו הוא איטרטור של הרשימה, והפרמטר השני הוא אובייקט הפונקציה שמפרק אובייקטיס מסוג 51400. בנוסף, נעביר אובייקט המבצע את הפירוק לבנאי של האפליקטור. ()ת1נא8ת %6ם1 ו ;880068 <*806ם118%6>59 7 ת50200 ,1667 6*<::1186ק8ת1168602>1158%6>5ס80 ; (()ץ3658%20 806ם80116)58<ץ668%20 סִכהם5 ;((11 ,19 ,6)10,1ת21 חסם)םססקה.פסקם5 ;((10 ,0 ,6)0,0םת21 חסם)םססקה.פ65ַק8ם5 ;((0 ,10 ,6)0,0ת21 חסם)מםססקה.פסקם5 ;((10 ,10 ,6)10,0ת21 חסם)םססקה.פסקם5 ;((10 ,10 ,10 ,6)0םת21 חטסם)מססקה.פסקאם5 ;((10 ,55 ,20 ,6)40ת21 חסם)מםססקה8.פ6ק8ם5 ;((20 ,6)10םת1סקע טחסם)מ6סקה. 65ק8ם5 ;((10 ,6)15ת1סקע טחסם)מ6סקה.65ק8ם5 ; (502 ,8008ם5)א028 ; (()06םת80268.6ם8 , ()ם601כ.65ק116)528סקה8 7 תעגו66ע ו כשמפעילים את האפליקטור קובעיס לו תחוס. במקרה וה, התחוס הוא מתחילת הרשימה ועד סופה. פרק 7: תבניות ב-++6 207 דוגמה - מערך דינמי בסעיף זה נציג דוגמה נוספת למחלקת תבנית - מערך דינמל (ע8118 סותתאתץ4). מערך דינמי דומה למערך בסיסי של ++6 ויעיל כמו מערך רגיל, אך מספק את יכולת ההגדלה באופן אוטומטי, ללא כל צורך בהתערבות המשתמש להקצאת ציכרון נוסף. הקצאת הזיכרון נעשית במחלקה עצמה, בעת הצורך. המערך (ע414) הוא מחלקת תבנית שמקבלת פרמטר אחד, סוג האובייקט בתבנית. למערך יש איטרטור המאפשר לסרוק את המערך. מבנה המערך למערך יש מצביע (54911) לתחילת אזור הזיכרון של המערך. בחלק מהמערך כבר מאוחסנים ערכים והמצביע 18% מצביע למקוס אחד מעבר לאזור התפוס (ראה ציור). לכן, הערך ‏ 50% 18% הוא מספר האובייקטים הקיימים במערך. המצביע 86 01 66 מצביע לסוף האזור שהוקצה עבור המערך. כשהמערך מקצה זיכרון, הוא מקצה מספיק מקוס לאובייקטים הקיימים במערך ובנוסף, אותה כמות זיכרון לאובייקטיס שאינס מאותחלים. שיטת עבודה זו נועדה לחסוך במספר הפעמים בהן יש להקצות זיכרון. 6 0% 600 וב + 0% 6 הקצאת זיכרון אינה נעשית בעזרת האופרטור שט6ם, משוס הוא גורס להפעלת בנאי האובייקטיס שנמצאיס במערך. דבר ה אינו מחויב המציאות, מכיון שייתכן שאין צורך בכל האובייקטיס במערך. במקרה ואין צורך בכל האובייקטיס, אזּי הקריאה לבנאי של אובייקטיס אלה היא מיותרת ותגרוס לחוסר יעילות. 1. 7 יצירת אובייקטים במקום מסוים במערך כשמוסיפים אובייקטים למערך יש לבנות אותס באזור הזיכרון שאינו מאותחל באובייקטיס. כזכור, כשיש אובייקטים עס פונקציות וירטואליות, מכניס המהדר מצביע לטבלה של מצביעיס לפונקציות וירטואליות. לכן, יש לטפל באתחול האובייקטיס בחלק הריק של המערך, כדי לאתחל מצביעים לטבלת פונקציות, עבור אובייקטיס פולימורפים. 8 ++6 ו-009 למתכנת המקצועי הבנאי הוא המקוס בו מאותחל המצביע לטבלת המצביעיס של הפונקציות הווירטואליות. בכל בנאי מוסיף המהדר קוד שמאתחל את המצביע לפי סוג האובייקט הנוכחי. המתכנת אינו יכול לקרוא לבנאי של אובייקט באופן ישיר. כדי לעשות ואת, אפשר לנצל את העובדה, שכשקוראיס לאופרטור א6ם מוסיף המהדר קריאה לבנאי של האובייקט, עס הכתובת המוחזרת על ידי האופרטור או6ח. ב-++6 אפשר להגדיר אופרטור סמ שמחליף את אופרטור המערכת. אופרטור כזה, המקבל את כתובת ההקצאה ומחזיר את אותה הכתובת, יאפשר להפעיל את בנאי האובייקט על אותו אזור ויכרון. בכך נגרוס ליצירה אוטומטית של אובייקט חדש באוור הזיכרון המבוקש. בדרך וו המהדר מעדכן את המצביע לטבלת הפונקציות בצורה אוטומטית. שיטה זו תפעל בכל מהדר ++6, ובכל פלטפורמה. נגדיר אופרטור הקצאת זיכרון שסת בדרך הבאת: [ ;סק מעטססע + (סם* בנסט ,%ם1 60ת10פםתט)טחסם 2סס628קס* בנסע האופרטור מחזיר את הכתובת המועברת לו. עבור מחלקה כלשהי א אנו יכוליס כעת להשתמש באופרטור באופן הבא: ; [ (%) +260 51 ] מפחא עַהַםתס ;א (תסתא) חטסת קטע קוד וה יוצר אובייקט מסוג א באזור הזיכרון נוסנצא. באופן דומה ובעת הצורך, ניתן להפוך את הזיכרון בתחוס (18980, 5)01986 01 6ם6) שאינו מאותחל, לאובייקטיס מסוג נתון. 2 | הממשק של עגזזה ממשק המערך מגדיר את האיטרטור כמצביע לאובייקט שנמצא בו. מכך נובע, שסריקת מערך זה יעילה כמו סריקה של כל מערך רגיל של ++6. הגדרת האיטרטור נעשית בחלקו הציבורי של המערך, וכך שאפשר להשתמש בו גס מחוץ למחלקה. הפונקציה 600501004 מאפשרת ליצור אובייקט במקוס כלשהו במערך. היא מקבלת את המיקוס והערך בהס יש לאתחל את האובייקט. הפונקציה מנצלת את האופרטור סמ שהגדרנו, ומשתמשת בבנאי העתקה של האובייקט כדי לאתחל אותו בערך הנתון. <6קץ71 01858> 661866 ] לעפת 01855 :טס 7 *ס6סץ71 66061 ;[ 512 = 8126 806 + תגותס :טנס 1602800 2 10628000 %2 2 05 6ם6 16028608 (81צ68 6סץ71 008% ,פסק ע0%)16628%02ג0ע5%2ת00 בנ1נסט [ ;(81ט)6סץ71 (פ8סק)חסם ]1 פרק 7: תבניות ב-++6 209 ;(12 180628602 ,11 ע7)1662860ץ0ע836562 בנ1נסט :טס ;(82 מ%םת65126)1ע2 1סט (85126 8006ק=82 ס6ם1)צֶ228ת (58%602806)0 05 6ם6 ,(1886)0 ,(56826)0 [ ;(268126)582 ] [ ק;(5266)5850826 ;(1886 ,₪656207)5082% + ()22287- [ ;(1+5682%)* תעטסשע + (1 6ם1)[]ע800628602 6קץך [ ;(6ע558 - 1886) מעטס6ע + 86םת00 ()58126 שם1 ; (8%6820 - 8602806 05 6ת6) מעטססע + ס6פתסס ()ץ0808016 6םת1 ; (8081 | ססעץ7 58%ת80%)00 פטס בנסע [ ;8%82% מעטס6ע + ()ם681ס ע1₪62860% ] 2 תמסשטססשע + ()0ם6 ע1₪62860% ;ו הפונקציה /ץ66880 מפרקת אובייקטיס בתחוס כלשהו במערך. התחוס מוגדר לפונקציה על ידי שני איטרטורים, כלומר שני מצביעים. הפונקציה מפעילה באופן ישיר את המפרק של כל אובייקט בתחוס הנתון. כבר ראינו שפונקציות כאלו יכולות להיות ממומשות בעזרת אפליקטור (ראה תרגילים). <6סץ71 01855> 66001866 (12 ע18628%0 ,11 7)1₪628%0%2ץ0ע6<::065%2קץ7>1ץ228ת בנבסט ו ] (12 =! 11) 16נ1תחט ; () 06ץ2=: : 6סץ1<-11 ; 11 ו הפונקציה 168126 משמשת להקצאת זיכרון. הקצאת זיכרון יכולה להתרחש בשני מקרים: כשיש צורך לאתחל את גודל המערך באופן ראשוני, או כשיש צורך להכניס אובייקט נוסף למערך, ואז יש להגדיל את מימדי המערך. בשני המקריס מבצעת הקריאה לפונקציית המערכת 1641106 את ההקצאה הנדרשת. כשפונקציה זו נקראת מהבנאי מאופסיס המצביעים של המערך, ולכן היא תקצה את המערך. אחרת, היא תגדיל (1081106) את מימדיו. <6סץ71 01855> 01866ח66 (82 %ת6<::268126)1ק7ץ1>ץ228ת בנסט ָ ; ()5126 ם %ם1 וו ;ת + 808256 = 18586 2 + 808260 = 58602806 05 6ם6 ; ( (706ץ81260%)1 * 582 ,2681100)8%682% (166028602) 0 ++0 ו-009 למתכנת המקצועי האופרטור [] מחזיר ייחוס לאלמנט של המערך. אופרטור וה מאפשר להשתמש במחלקה מערך, כמו במערך בסיסי של השפה. למשל: ;(81)1 <סם1>צְ28?ת 0 81]5[ = 72 באופרטור [] איו אפשרות להשתמש מייד לאחר שהמערך מוגדר, משוס שבתחילה מוגדר מערך עס הקצאה מספקת (10 שלמים בדוגמה), אבל זיכרון וה אינו מאותחל לאובייקטים. לפיכך, יש תחילה להשתמש בפונקציה 580% גפטק. בתרגילים, אנחנו מוספיס פונקציות המאפשרות להגדיר ערכיס התחלתיים במערך. האופרטור [] אינו בודק חריגה מתחוס המערך, ולכן כל חריגה כזו יכולה לגרוס לתופעות ולתוצאות שאינן מוגדרות, או צפויות. לו היינו בודקיס חריגה בכל שימוש באופרטור, היה השימוש בו גורס להפחתת היעילות בצורה משמעותית. בהמשך, נראה פתרונות אחריס לבעיה. הפונקציה 980% 1פטק כותבת אובייקט לסוף המערך. אס יש צורך (לדוגמה, במקרה שאין מספיק מקוס במערך) מוכפל גודלו של המערך. לאחר מכן, מאותחל האובייקט בכתובת של )185 ומצביע גה מוגדל בהתאס. <6קץ71 01858> 661866 (81ט8 6סץ7 586ת80%)00 מפטס::<6סץ7>1ץ2228 בנסט ו (8%602806 05 060ת6 =< 1886) 15 ;(1 + 2 * ()ץ268126)08028016 ; (781 ,006)185%5ע85%2ת00 ;++1886 43. 7 שימוש במערך עד כה ראינו את המחלקה עצמה וכעת נראה כיצד אפשר להשתמש בה. כדי לבחון את המערך ולבנות אובייקטיסם במקוס בו יש זיכרון לא מאותחל, נגדיר אובייקט עס פונקציה וירטואלית. אובייקט זה מייצג שלסם, ולכן נוסיף לו פונקציה וירטואלית שתחזיר את ערך השלס שהוא מכיל. סת+ 01855 2 סם1 :טס [ ;ט = 81ט + (ט 6ם1)%םך [+ ()%ם1> 81ט6תנ1נט [ ;81ט תע00ס6ע + ספתסס ()665 %ם1 1ה8טסענט ;ן פרק 7: תבניות ב-++ 6‏ 211 כדי לאפשר מיון של המערך נוסיף שני אובייקטי פונקציות. הראשון, מופע של מחלקת התבנית 168% עבור אובייקטים מסוג +ם1. באותו אופן, נגדיר גס אובייקט- פונקציה שהוא מופע של מחלקת התבנית 81091. האובייקט הראשון הוא לטובת אלגוריתם המיון 50 אסוטף, והשני לטובת האלגוריתם 50 ת0ו867ם1. ] <%ת16585>1 06וע56 % (812 סםת1 586ת00 ,811 סם1 6פםסס) ()628602ק0ס 6ם1 [ ;(()12.06%8 > ()11.86%) םמעט66ת ) ;ן ] <שףת82686>1 06וע56 % (812 סם1 856ת00 ,811 6ם1 6פםסס) ()628602ק0ס 6ם1 [ ;(()12.06%8 < ()11.86%) םמעט66ת ]1 ;ן כדי להשתמש באפליקטור ולהדפיס את המערך נגדיר אובייקט-פונקציה עס אופרטור קריאה לפונקציה, המדפיס אובייקט לפלט הסטנדרטי תוך שימוש באופרטור ">>/. כדי להדפיס אובייקטיס מסוג +18 נגדיר אופרטור ה עבור אובייקטיםס מתאימים. <1? 01858> 66801866 ] עססתנ1עס 06גע56 (81ט8 7 5%8ם00) ()628602ק0ס 6ם1 12 יתת סט 2 7 > ,1ב >> סטסס 1 ;ו (81 %ם1 85%ת00 ,800% ת(602628%602>>)089%208 ת(05%6268 [ ;()1.06% >> סגס מעט6סע + נגדיר שתי פונקציות שימלאו מערכים המכילים אובייקטיס מסוג +מו ואובייקטיס מסוג +10. פונקציות אלו משתמשות בפונקציה 080% \פטק, הכותבת אובייקט בסוף המערך, ובעת הצורך מקצה למערך זיכרון נוסף. (ם %ת1 ,68 <%ת1>ץ228ה)ץ8228 5111 בנסט ; (2/ם)8.268126 (--1 ;1<0 ;ם=1 6ם1) 08ס+ ; (1) 080% מפטק.8 (ם %ת1 ,68 <%ת1>צ228ת)ץ8228 5111 בנסט ; (2/ם)8.168126 ] (--1 ;1<0 ;ם=1 %ם1) 05ס+ ;(1)א% 6םמך ; (0806%)8 תפגוק.8 2 ++6 ו-009 למתכנת המקצועי הפונקציה הראשית משתמשת בפונקציות שלמדנו בפרק צה, כדי למלא שני מערכים. הראשון מביניהס הוא מערך של שלמים והשני, מערך של אובייקטים מסוג +18. המערך הראשון ממוין בעזרת קריאה לפונקציה 8011 אסנטף. לאחר מכן מודפס המערך בעזרת קריאה לאלגוריתס הגנרי )פוזק. קריאה לפונקציה 1606186 הופכת את סדר האובייקטים במערך. לאחר הפעלת הפונקציה האחרונה מסודריס האובייקטיםס מאובייקט גדול לקטן. את אפקט סידור האובייקטיס בסדר יורד יכולנו להשיג אס היינו מעביריס לפונקציית המיון 801 אסוטף אובייקט פונקציה מסוג /8109, המתאים לסוג האובייקטים במערך. דבר זה יעיל יותר, שכן היינו חוסכים מעבר אחד על המערך. פעולות דומות מופעלות גם על המערך השני. הפלט של התוכנית הבאה, קובצ הוא שתי הדפסות של המערך הראשון ושתי הדפסות של המערך השני . ()תנאת %ם1 ו 12 <סשת1>ץ8עעת 12 <םם1>צְ28ת < <%ם1>ע6סת1עק ,*6ת1108602>1סק8 ;(()<%ם1>ע662ת1עק)6עס ;(30 ,81)ץ8228 1111 ; (()086ת81.6 ,()ם681כ.6)81תנ1נעס ;(()<6ם1688>1 ,()6ם 81.6‏ ,()ם1ש6ע.502%)81 16%ט ; (()086ם81.6 ,()ם681כ.6)81תנ1נעס ;(()0ם81.6 ,()ם81.681) 206256 ;1 >> ":86ע02ט00ת ע160ה" >> סגוסס ;(()86ם81.6 ,()ם601כ.6)81ע,ס 012ת6 >> " מכ הת ו ו ו ו ו ב ו ב 1111 8228)81, 30(; ; (()086ם81.6 ,()ם6081כ.6)81ת1עס ; (0) קתף סמך ; (קתם, () <%ם6268%>1, ()8ם81.6, ()ם1ש6ס.5802%)81 םמ610ע56ת1 ;(()86םת81.6 ,()ם681כ.6%)81םת1עס 2 מעגו6%ע2 ו בדוגמה זו ראינו כיצד מפעילים אלגוריתמים גנרים על מבני אלגוריתמיס שוניס, ללא כל צורך בשכתוב מחדש של האלגוריתמים. ירושה ותבניות בפרק זה ראינו שאפשר להשתמש במנגנון הירושה עבור מחלקות תבנית. המחלקה 118 ירשה ממחלקה אחרת (118 0886) שביצעה את מירב העבודה, כדי למנוע ניפוח של הקוד. יש אפשרות מורכבת אף יותר לרשת מחלקת תבנית ממחלקת תבנית אחרת. פרק 7: תבניות ב-++6 213 עובדה וו מקנה מימד חדש ועוצמה רבה למחלקות תבנית. מחלקות תבנית אינן מאקרו, והן מאפשרות להשתמש בירושה ופולימורפיום כדי להשיג גמישות גדולה יותר. ירושה מהמחלקה עגּזזה המחלקה ,1189 שראינו בסעיף הקודס אפשרה לגשת לאובייקטיסם במערך בעזרת אופרטור []. לכן, השימוש באובייקטים של מחלקה זו דומה מאוד לאופן השימוש במערכים בסיסיים של השפה. כמו במערכיס בסיסיים של השפה, גם כאן אין הגנה מפניות אל מחוצ לגבולות המערך. כדי לטפל בנושא זה ניצור מחלקת תבנית חדשה, היורשת ממחלקת התבנית הקודמת, ומבצעת בדיקות חוקיות על פניות לאינדקסיס במערך. המחלקה 58161184 היא מחלקת תבנית היורשת מהמחלקה 4118 ומגדירה בדיקת תחום בכל פנייה לאופרטור []. מאחר והמחלקה 581618 היא מחלקת תבנית עם פרמטר 1, הרי שהמחלקה הבסיסית שלה היא המחלקה <1>צ114, כלומר, מחלקת תבנית עם אותו הפרמטר. הקוד של מחלקה זו נמצא בקוב 11.ץ5916/14. כדי להחזיר ערך כלשהו עבור פניה לאינדקס שמחו למערך מוסיפים שדה [ום. שדה זה הוא סטטל (61800), כלומר, קייס רק פעם אחת עבור המחלקה ומשותף לכל האובייקטיס שלה. כשיש הגדרה כזו עבור מחלקה רגילה, אנו מביניס את משמעותה. משמעות ההגדרה שונה במקרה של מחלקת תבנית. כשיש לנו הגדרה של שדה סטטי במחלקת תבנית, משותף שדה זה לכל האובייקטיס של המחלקה עבור אותם פרמטרים של התבנית. עבור פרמטר תבנית מסוג )ג יש אובייקט אחד בלבד המייצג את השדה [וּם. עבור פרמטר אחר, מסוג 400916, יחיה אובייקט סטטי אחר, מסוג 400016, המייצג את השדה הסטטי. כלומר: ; (582)10 ,(581)5 <7>600016ץ58102128 ; (584)12 ,(583)4 <%ם7>1ץ58162228 לאובייקטיס 881 ו-382 יש שדות משותפיסם עבור המשתנה הסטטי, השונה מהמשתנה הסטטי של האובייקטים 583 ו-884. לשנייס האחרוניס יש את אותו אובייקט [ות. <1? 01858> 66801866 ] <1>ל8עעת 110מטסק : ץ228ת580 01858 2 7 568610 :טס (7>1<)82ץ228ת : (8126 806 = 82 6ת1) 58562228 0 ;(1ב %ם1)[]ע800628602 7 ()11ת 606% 7 6פםתסס 568610 [ ;11ם םמעט66ע + 4 ++6 ו-009 למתכנת המקצועי האופרטור [] מוגדר מחדש עבור המחלקה /5816118. אופרטור זה, במחלקה זו, מבצע בדיקה על האינדקס הנתון לו. אם האינדקס נמצא בתחוס הנוכחי של המערך, מוחזר אובייקט מתאים, בעורת קריאה לאופרטור [] של המחלקה הבסיסית. אחרת, האינדקס מחוץ לתחוס התקין של המערך, ומוחזר ייחוס לאובייקט הסטטי. 1 808610 0+ 7 01 ע0ס60%סטע5%ת60 0618016 6פט // 2: :5810222871 7 <71 018595> 661866 <1? 01858> 66801866 (ב %ם2][)1ע628602ק0ס::<7>1ץ8658102228 7 (()1>8126 68 1<=0) 15 ;(2][)1ע628602ק7>1<::0ץ2228 תעג6%ץ? ;[נגת תעט6%ץ ו יש שני חסרונות בגישה זו. ראשית, הגדרת אובייקט סטטי וו₪ המשתמש בבנאי של ברירת המחדל שלו. דבר זה דורש שאובייקטים מסוג 1 יכללו בנאי של ברירת המחדל. חיסרון שני הוא טיפול במצב שגיאה בעזרת החזרת ייחוס לאובייקט מסויס. למשתמש בקוד וה אין דרך לדעת שהוחזר אובייקט סטטי כזה. בהמשך נראה שיטות טובות יותר לטיפול במצבי שגיאה. שימוש באובייקט מסוג מערך בטוח השימוש במערך בטוח כזה דומה לשימוש במערך רגיל, ונראה כך: <60םת581622287>61 ; (10) 265126 . 58 (++-1 ;1>10 ;1=0 6ם1) 10% ;(80%)1+1ס ם58טק.58 (+1+4 ;1>15 ;1=0) ע10% ;" " >> [88]1 >> סגוסס ;081ת6 >> סגטסס קטע קוד זה מגדיר מערך בטוח בגודל של 10 אובייקטים ומכניס 10 אובייקטים לתוכו. לאחר מכן מוסיפיס 15 אובייקטים. הפלט של קטע הקוד הבא הוא : 1 23 4 5 6 7 8 9 10 0 0 0 0 0 כלומר, עבור האובייקטיס החורגים מהמערך, מודפס ערך של השדה [וח, שהוא אפס. 1-1 | פונקציות וירטואליות הגדרת האופרטור [] במחלקה 4119 כפונקציה וירטואלית היתה מאפשרת לכתוב פונקציות המנצלות זאת, באופן הבא: פרק 7: תבניות ב-++6 215 (ע680 ת50206 ,8822 <*806ם7>65ץ2228) 528068 א428 בנסע 7 = 1 סם1 ] (()1>822.8126 88 [22]1ע82) 116תט ; (8502) ש8ע6<- [1]עטע8 ;++1 ו כשהשימוש באופרטור [] הוא פולימורפי, בהתאם לסוג האובייקט האמיתי של המערך. אכן, דבר וה מקנה גמישות נוספת למחלקה זו, אך עבור גמישות יש לשלס. התשלוס במקרה זה, הוא הפעלה פולימורפית של אופרטור זה, שהיא פחות יעילה מהפעלה רגילה. המחיר אינו גדול, אבל אס הפנייה לאופרטור זה נעשית בלולאה הפנימית ביותר, הופך התשלוס להיות משמעותי יותר. מתאמים מתאמלם (008ק808) הס מחלקות המשתמשות במחלקות אחרות לצורך מימוש פונקציונליות מסוימת. המחלקה המתאמת משתמשת במחלקה אחרת למימוש הפונקציונליות שלה, והפונקציות שלה קוראות לפונקציות של המחלקה בה משתמש המתאם. כדי להדגים מושג זה נפתח שתי מחלקות, המייצגות תור (סטסטף) ומחסנית (848086) בעזרת המחלקה רשימה (118). תור (סט6טף) הוא מבנה נתוניס המכיל אובייקטים אחרים וגורס לסדר מסוים ביניהס. התור פועל בשיטת 1190 (קיצור ל-006 186 1 זות). כלומר, האלמנט הראשון שמוכנס לתור הוא גס האלמנט הראשון שיוצא ממנו. 2 ב 8 8 / באיור רואיס שהאובייקט הראשון שנכנס כבר קרוב ליציאה, והאחרון יהיה גס האחרון שיובא מהתור. 6 ++0 ו-009 למתכנת המקצועי כדי ליצור תור, נגזור בצורה פרטית את המחלקה פטוטגוף מהמחלקה 118% : <1? 01858> 66801866 ]) <118%>71 866ט1עק : 60606 01855 :טס [+ () 0606 [ ;(81ט562%)0ת1 + (8081 7 ספתסס)פטס פנסט [ ;()6811 סטסת26 מעט66ע + ()466 ך [ ;()1186>1<::8126 מעטססע + ס8םתסס ()8126 %6ם1 לז מתאמיס מבצעיםס תיאוס של ממשק מחלקה אחת לממשק אחר. במקרה זה, התיאוס המתבצע הוא של הרשימה לתור. במחלקה 6טסטף נפרשות כל הפונקציות על ידי המהדר, ולכן, הוא לא מייצר קוד כלשהו. הירושה הפרטית ששימשה אותנו במקרה זה גורמת לכך שהמשתמש במחלקה זו אינו יכול לגשת לפונקציות המחלקה הבסיסית. אס היינו משתמשים בירושה ציבורית, יכול היה המשתמש במחלקה לגשת לפונקציות אחרות של הרשימה, ובכך להפר את תנאי התור. בצורה שקולה לירושה פרטית, יכולנו להגדיר את הרשימה כשדה בתור. השימוש במחלקה זו נראה בצורה הבאה: ;1 <6ת6>1:ו0ג0 (++1 ;1>10 ;1=0 6ם1) 102 ; (1) פטס 1 (0 < ()41.8126) 16נ1תשט ;" " >> ()71.865 >> סגוסס קטע קוד זה גורס לפלט הבא : 9 8 7 6 5 4 3 2 1 0 מחסנית (5%90%) היא מבנה נתוניס המכיל אובייקטיס אחרים. המחסנית מאפשרת הכנסה והוצאה של אובייקטיס תוך שמירה על סדר מסויס ביניהם. האובייקט שמוכנס ראשון למחסנית הוא גס זה היוצא ממנה ראשון, כלומר, היא פועלת בשיטת 1.190 (כמו מחסנית של רובה). 8 0 18 כדי לממש את המחסנית נגדיר מחלקת תבנית שמכילה רשימה ומתאמת את ממשק הרשימה לממשק המבוקש של מחסנית. פרק 7: תבניות ב-++6 217 66801866 >01858 ?1< 018585585 5680% )] ם%8%10ת602680ע2 // - ;60ע <1186>1 :טס [ ()5680% (8081 7 6פ5םתסס)םפטס בנסט [ ;(81ט)562%6םת260.1 ] ()ססס 7 [ ;()680ם 6טסת60.260ע2 מעגוס6ץ ) [ ;()60.8126ע2 מעגטסשע + 00286 ()8126 6ם1 ו במקרה זה יכולנו להשתמש גס בירושה פרטית (השקולה להכלה) אבל, כדי להדגיס את האפשרות השנייה מימשנו את המחסנית בעזרת הכלה. אפשר לראות שהמחסנית מגדירה פונקציה אחת (נפטק) להכנסה של אובייקט לתוך המחסנית ופונקציה נוספת (קסק) להוצאת אובייקט מהמחסנית. השימוש במחלקה מחסנית הוא בדרך הבאה: 12 <6ת5680%>1 (++1 ;1>10 ;1=0 6ם1) 10% ; (1) םפגו. 51 (0 < ()51.85126) 16נ1תט ;" " >> ()00ק.81 >> סגוסס קטע הקוד הבא ידפיס את הפלט הבא לפלט הסטנדרטי: 0 1 2 3 4 5 6 7 8 9 מתאמים גנרים עד כה, ראינו מתאמיס המשתמשיס במחלקה מסוימת כדי לממש תור, או מחסנית. פתרון גנרי טוב יותר הוא לאפשר תור, או מחסנית, כשהמימוש נקבע על ידי המשתמש, בעת הגדרת המחלקה. לדוגמה: <%ע6ם%81ת00 01855> 18%66קת66 ]) 606 018585 ;תסס 6%8ם6081ת00 :טס 0606 )( +[ (טצ8 6קץ6 6ט10הט 86ם6)00טס ב1סע [ ;(ט)562%ת1.%ם00 + ()86%6 6קץ6 6ו1ט [ ;()680ם 6טסת6ע2.%תסס מעגוס6ץ 1 ;ו 8 ++6 ו-009 למתכנת המקצועי בקטע קוד זה מקבלים, כפרמטר של תבנית, את סוג המכולה (6תו9ת600) בה יש להשתמש כדי לממש את התור. השימוש במחלקה זו נראה כך: 2 < <מ6ת00606>115%6>1 ; (1) סגו 61 ;()671.80%6 = 1 6ם1 הבעיה בקטע קוד וה היא שאין לנו את סוג האובייקטיס המוכנסים ומוצאיס מהתור בהגדרת מחלקת התבנית. קטע קוד וה לא יעבור את שלב ההידור. אפשרות אחת היא להוסיף סוג אה כפרמטר של התבנית : <1 018858 ,02ם%681ת00 01885> 1866קת66 ]+ 6גו6ו 018855 ;ו 12 <סם1 ,<%6ת6>61185%6>1:גו0ג0 גישה זו אמנס פותרת את הבעיה, אך פחות נוחה למשתמש, שצריך להגדיר פעמייס את סוג האובייקטיס במכולה. כדי לפתור בעיה זו אפשר להגדיר את סוג האובייקטיס במכולות בדרך הבאה: <1? 01858> 66801866 ] 118% 01858 :טס ;6סץ 6ט1אט 7 6061סץ6 ;ו לאחר שהגדרנו את סוג האובייקטיס במכולה, אפשר להגדיר את המתאם בדרך זו: <%ע6ם%81ת00 01855> 661866 ]) 606 01855 ;סע 8106ט 6סץ6 6ט810ט::עסת%81ת60 6061קץ6 ;מסס 6%8ם681ת00 0606 )( +[ (ט8 6קץ6 8106ט 6פתסס)6טס ש1נסט [ ;(ט)%ע562םת1.%ם00 + ()06%6 6קץ6 6ו1אט [ ;()680ם 6טסת6ע.%תסס מעגוס6ע 1 נן 2 < <6ת1186>1 >6שוסגו0 כעת, השימוש הרבה יותר נוח למשתמש. הוא יכול להחליט מה סוג האובייקט והמכולה שתשמש למימוש התור, ללא כל צורך בחזרות על סוג האובייקט. בגישה זו, על כל המכולות להגדיר את סוג האובייקט, כך שאפשר יהיה להשתמש בהס עבור מתאמים. פרק 7: תבניות ב-++6 219 סיכום בפרק וה הכרנו את המושג תבנית ב-++0. יש שני סוגי תבניות: סוג אחד הוא פונקציות תבנית והסוג השני הוא מחלקת תבנית. קיימת אפשרות לשילוב בין פונקציות תבנית גנריות לאובייקטיס השייכים למחלקות תבנית. פונקציות תבנית פועלות על סוגי הנתוניס כפרמטר של התבנית. היכולת להגדיר פונקציות כאלו, המסוגלות לפעול על סוגיס שוניס של פרמטרים, מאפשרת לפתח פונקציות גנריות הטובות למספר רב של סוגי אובייקטים. פיתוח פונקציה גנרית כזו הוא קל. ראשית, מפתחיס פונקציה רגילה, שאינה פונקציית תבנית, ופועלת על סוג מסויס. לאחר שהפונקציה פועלת כשורה, אפשר להפוך אותה לפונקציית תבנית גנרית. מחלקות תבנית דרושות כשיש מחלקה המבצעת פונקציונליות שאינה תלויה בסוג האובייקטיס בהס היא מטפלת. דוגמה לכך היא אוספים, או מכולות. מחלקות מסוג זה מכילות אובייקטיס אחרים, במבנה נתוניס מסויס. מחלקות אלו מאפשרות לסרוק את המכולה, להוסיף או לבטל בה אובייקטיס בכל עת. אפשר להשתמש בירושה ובפונקציות וירטואליות כשמשתמשיס במחלקות תבנית. בכך שונות מחלקות תבנית ממאקרוס פשוטים של השפה. השימוש בירושה ובפונקציות וירטואליות, מקנה מימד חדש ועוצמה רבה ל-++6. (ו 5 | שאלות כיצד אפשר לסדר שהפונקציות זמוזק ו-5801 אסוטוף יהיו בעלות אותו ממשק:ז האס יש דרך לבטל את הפרמטר קמ (האחרון) המועבר לאלגוריתס 560ת1? 3 האס אפשר להפעיל את האלגוריתם +80 אסוטף על הרשימה! ואס לא, מה יש לעשות כדי לאפשר זאת! 4. הגדר רשימה של מצביעים גנריס (*6וסצ) בעזרת רשימת התבנית. גזור מחלקת תבנית חדשה מרשימת המצביעים הגנריס. ממש את דוגמת הצורות בעזרת רשימה זו. 5 שנה את המחלקה ז6)םוזק כך שאפשר יהיה לשלות כל אובייקט לכל קובצ נתון. הוסף פונקציה 6טסגת6ז למערך (ע418). על הפונקציה לבטל אובייקט במערך. כיצד מפרקים אובייקט כזה! 7. הוסף פונקציה שמכניסה אובייקטיס לאמצע המערך (ע4119). מהי הסיבוכיות של פונקציה זו 8 הוסף פונקציה המכניסה מספר אובייקטים לכל מקוס במערך בצורה רצופה. מהי סיבוכיות פונקציה זו האס עליך להשתמש בפונקציה הקודמת! האם זה יעיל להשתמש בפונקציה הקודמת! 9. שנה את הפונקציה ץ86%800 של המחלקה 4118 כך שתשתמש באפליקטור. 0. הוסף בנאי המאפשר לאתחל מערך ממערך אחר בסיסי של ++6, שנראה כך: ;(ם %ףם1 ,צע8* 7 8%ם00)צ28לת כאשר ם הוא מספר האלמנטיס הנמצאים במערך זזג. 0 ++6 ו-009 למתכנת המקצועי פרק 8 טיפול בשגיאות ועוד בפרק זה נלמד על הדרך בה מטפליסם בשגיאות ב-++6. טיפול בשגיאות נתמך בשפת התכנות על ידי מבניס כגון: ץ7), 0זם), 64661. התמיכה למבניס אלה בשפת ++6 מוסיפה לה מורכבות מיותרת, במיוחד כשמשתמשים בתבניות. נלמד כיצד לגלות בעיות אלו וכיצד לפתור אותן. בפרק זה פפתֶח כליס ומחלקות שיעזרו לנו להתמודד עס מצביס חריגים. מרבית המהדרים אינס תומכים במצבים חריגים, וגם אלה שתומכים בהם, עדיין אינס תומכים בכל האפשרויות שמאפשר התקן של שפת ++6. כדי להריץ את הדוגמאות בפרק זּה, עליך להשתמש במהדר התומך במצבים חריגים. מדוע צריך לטפל בשגיאות מה החשיבות של טיפול בשגיאות! האם אי אפשר להסתפק בהחזרת הודעה, או התרעה על שגיאה כתוצאה מקריאה לפונקציה, למשל! הנה דוגמה: שסעץס תס 1- עס ע0סספק1ע8680 1116 8 מעטססץ // (6תהת* ע8ת0 8%6ת2116)00 מתס6קס 6ת1 ו 7 ] אכן, בשיטה זו נוהגיס ומן רב: המשתמש בפונקציה צריך לבדוק בעצמו את הערך המוחזר על ידי הפונקציה. לכן, התוכנה של המשתמש בפונקציה זו, תּיראה כך: ; ("0מ116)"8 מתססס = 58 6ת1 1% )16 == -1( שסעע6 סִנַָפתא1 ... // ולמרות וּאת, יש בכך חיסרון. קוד המשתמש משוב> בבדיקות שגיאה בכל מקום, דבר שמתאפשר בכליסם התקנייס והמקובליס בשפת 6, ובוודאי שב-++6. פרק 8: טיפול בשגיאות ועוד ‏ 221 ל-++6 יש מחלקות ואופרטוריס המדמיס מחלקה לאובייקטיס בסיסיים של השפה. לדוגמה: ] 8ם1ע56 018588 ;* ע8ם0 :טס ;(8* 82ם0 8%םת6)00ם1ע562 ל ;(1 %ףם602628%02][)1 עַַאַם0 7 [ ;(0 == מ855%) מעטפפע + 59%ם00 ()80ס %ם1 ;ן בנאי אובייקט זה מקצה זיכרון ומעתיק לתוך אזור הויכרון החדש את המחרוזת הנתונה לו. (8* 0282 58%ת6)00ם8::5%21מם5621 ;[1 + (58)ם16ע82]862ם0 שס6ם = מ65פ5 ?7 1859 ץצְפסתפת סם +1 ס8םח // (ע8%2) 15 ;(8 ,862)צץ56200 ] מה קורה אם אופרטור ההקצאה אינו מצליח להקצות זיכרון כנדרש! במקרה כזה האובייקט לא יכול להקצות זיכרון, ולכן נווצר מצב לא תקין. הבנאי אינו יכול להחזיר ערך שמראה על בעיה. לשס כך, יש להוסיף פונקציה שמחזירה ערך אס האובייקט תקין, ואז קוד המשתמש ייראה כך: ; ("6ת1ע5% 8ם10 8 18 18ם5)"1 8מם1ע56 ]1 (()8.0886) 11 ...סת11תהם ע50ע6 // ו בעיה אחרת היא השימוש באופרטור []. אם פוניס לאזור שנמצא מחו למחרוות, מה עלינו לעשות! האס להחציר תו מיוחד! במקרה כזה, איך נבדיל בין התו המיוחד לשאר התוויס! בעיה זו יכולה להיות בעבודה עס כל אופרטור, כמו אופרטור השמה, למשל. (8ת62 8ם1ע5%2 8%6ם628%02=)002ק0::0ם69%21 8מם1ע56 461666 ][ 2 2[ + (ע5.88%םע2)ם82]5%216ם0 חסם = 562 מ 1 ? 008ע6 סִנִַָתא1 // ] ; (ע5.8%62ת2 ,ע560) 56200 2+ תעג66ע 2 ++6 ו-009 למתכנת המקצועי גם באופרטור זה, אין לנו אפשרות להחזיר ערך המסמן שגיאה. לכן, חייב קוד המשתמש לבדוק את האובייקט לאחר השמה, כך: ; ("52)"52 ,("81)"51 8ם1ע56 7 = 51 1 (()81.088) +1 שסעצ6 שנָתהם ... // לסיכום, קיימות מספר בעיות : * | ב-++6 יש פונקציות, כגון בנאיסם או אופרטורים, שאינס מחזירים הודעות שגיאה. * כשמקבלים הודעות כאלו, יש לבדוק בכל מקוס בנפרד, מה הסיבה. פונקציות טיפול בשגיאות אפשר להעביר לתוכנית פונקציה שתיקרא במקרה שגיאה. למשל, לאופרטור שסם היתה אפשרות לקרוא לפונקצית טיפול בשגיאה, כשאין די ויכרון להקצות. במקריס כאלה גישה זו יעילה, ובמיוחד כשיש אפשרות להתגבר על בעיה זו. למשל: ;()(עפס ע16%תהת טחטסם*) 16סט (82 6 8126)ח6ת עססהעסקס* ב1סט זָ ;(811006)582ת = ק* בנ1נסט (ע6 מַסֶַַָם8םת שסם 68 0 == ס) 15 ; () (ע%6ק 16%שתהת חספם*) ; (811006)52 = סש ] ;ק מעמ66ע ו בדוגמה זו של האופרטור אסם, מוקצה ויכרון באמצעות פונקציית המערכת 41106חז. האופרטור קורא לפונקצייה המטפלת במצב שבו אין מספיק זיכרון פנוי להקצאה. במצב זה ניתנת האפשרות לשחרר זיכרון ולכן, לאחר הקריאה לפונקציית השגיאה, נעשה ניסיון נוסף להקצאת הזיכרון. אס שגרת הטיפול במצב של חוסר גיכרון מצליחה לשחרר מספיק זיכרון, תחויר הקריאה הבאה ל-1081106 מצביע לאזור ה ולא תיכשל שנית. כאן יש ניסיוו להתגבר על הבעיה ולהקצות זיכרון בכל ואת. אך, כשאין זיכרון לאחר הניסיון השני, חוזרים למצב הקודם, שיש לבדוק שוב את המצביע המותזר מהאופרטור אסם. פרק 8: טיפול בשגיאות ועוד 223 טיפול בסיסי בעזרת מבני ++6 ב-++6 יש תמיכה לטיפול בשגיאות. תמיכה זו מורכבת ממספר מבניס חדשים שהתוספו לשפה. ב-++6 ניתן להעביר מידע מנקודת השגיאה אל פונקציה כלשהי המטפלת בשגיאה. מידע זה אינו מוגבל, ויכול גס להיות אובייקט שלסם. יש שלושה היבטים לטיפול בשגיאות ב-++6: צע), אוסזם) ו-63001. בסעיף זה נראה את הבסיס והתחביר של מבניס אלה. לעורר שגיאה (0צז/ תג שחואוסזתד) כשמתרחשת שגיאה יש להעביר את המידע אודותיה אל התוכנית המטפלת במצב החדש שנוצר. הפעולה של זיהוי השגיאה והעברתה כמצב חריג לתוכנית המטפלת בכך נקרא עירור מצב שגיאה (סזת םג סעם1). עושיס ואת בעזרת מילת המפתח אוסיום+ אשר השימוש בה גורס להעברת השליטה מהתוכנית אל הפונקציה שמטפלת במצבי שגיאה. (82 %ת811006)1* ב1סע ; (81100)82ת = ע6ס* בנסט (ע%ס!) 15 ; ("118016ה8ט3 שעסתסת סא") חטסעם6 ;62 תעגמ6ס6ע ו בדוגמה זו, הפונקציה 81106 מעוררת שגיאה, על ידי משפט ש0צם) ומעבירה מחרוזת לפונקציה המטפלת בשגיאות. פונקציה זו צריכה לשחרר ציכרון (מכיון שזו הבעיה שדווחה) ולהחזיר את השליטה לתוכנית כדי שתנסה שוב להקצות את הזיכרון הדרוש לה. לאחר מכן, נראה כיצד מגדיריס שגרת טיפול בשגיאה, וכיצד מגדיריס בלוק טיפול בשגיאות. הפונקציה המעוררת שגיאה יכולה להעביר כל מידע בשעה שהיא מעוררת שגיאה. למשל, אפשר להעביר אובייקט שלס מנקודת השגיאה ונקודת העירור אל נקודת הטיפול. (82 %ם81100)1* ב1סט ;(81100)582ת = ע6ס* סנסט (עףסם!) +15 ; ("118016ט8 שעסתפת סא")8ם5%21 חאסעם6 ;62 תעגמ6ס6ע ו מכיון שאפשר להעביר אובייקטיס לנקודת הטיפול בשגיאה, הרי שאפשר להעביר יותר מידע לשגרת הטיפול בשגיאה, בתקווה שהמידע יסייע לפתור את הכעיה. 4 ++6 ו-009 למתכנת המקצועי אופן הטיפול בשגיאה הטיפול בשגיאה מורכב משני חלקים. ראשית, יש להשתמש במילת המפתח צזו. כשמשתמשיס במילת מפתת זו, אנו מודיעיס למהדר שאנו מוכניס לטפל בשגיאות, ואז גם מספקים קטעי קוד המטפלים בשגיאות. למשל: ()5 ב1סט ן + ץעם 8 ע6ם00 ₪0 68118 // ] ] (88 86ם1ע56) ת0860 מסעץם 0% ע16בתהת .. // ו הפונקציה + משתמשת בפונקציות רבות אחרות, שאף הן עשויות להשתמש בפונקציות נוספות. פונקציות אלו יכולות לעורר מצבי שגיאה, או שפונקציות הנקראות על ידן יכולות לעורר מצבי שגיאה. מילת המפתח צָע% מראה שפונקציה זו תספק קטע קוד שמוכו לטפל במצבי שגיאה. קטעי קוד אלה נמצאים בקבוצות קוד (בלוקיס) שמופיעיס לאחר מכן ונפתחיס במילת המפתח 680668. יכולים להיות מספר קטעי קוד המטפלים בשגיאה, כשכל אחד מהס מטפל בסוג שגיאה אחר. כל קטע קוד מגדיר שגרת טיפול שגיאה (016ם14 זסצו6), אשר עוסקת בסוג שגיאה מסויס. המונח (המקוצר) יישגרת טיפוליי (או פונקציית טיפול) מתייחס, למעשה, לבלוק תכנות שמטפל בשגיאות ודומה במבנה שלו לפונקציה, אך אין זו פונקציה רגילה ב-++6. כשקורית שגיאה באחת הפונקציות שנקראו על ידי הפונקציה 1 (ובתנאי שהפונקציה נקראת מתוך בלוק צש) מנסה המערכת למצוא שגרת טיפול מתאימה במסגרת הפונקציה הנוכחית. אם נמצאת שגרת טיפול כזו, מועברת בקרת התוכנית אליה. אחרת, מנסה המערכת למצוא שגרת טיפול, בפונקציה שקראה לפונקציה הנוכחית (ובתנאי שזה היה מתוך בלוק עזזו). ()5 ה1סט + עץעם ; (1)0ת ;()12 // ] ] (8 01ת00) 08602 // ] ) (8 02ם00) 08602 // פרק 8: טיפול בשגיאות ועוד | 225 6סם 268006 ...(1) // ו כאשר נמצאת שגרת טיפול במצב חריג, מבוצע קטע הקוד המתאים והבקרה מועברת לאחר כל שגרות הטיפול שבגוף הפונקציה. בקטע קוד וה תעבור הבקרה לשורה המסומנת ב-(1). כלומר, אס התעורר מצב שגיאה 005641 בפונקציה 11, לא תבוצע הפונקציה 12. יתר על כן, פונקציה 11 תעביר את הבקרה לשגרת הטיפול (הראשונה) שמטפלת ב-605061, לאחר ביצוע קטע קוד וה תועבר הבקרה לשורה (1). שגרת הטיפול בשגיאה מקבלת פרמטר בדומה לכל פונקציה אחרת. הפרמטר המועבר לשגרת הטיפול יכול להיות מצביע, ייחוס או כל סוג אחר הנתמך בפונקציות רגילות. נחזור לנושא מאוחר יותר בפרק זה. במהלך העברת הבקרה מפונקציה לבלוק טיפול בשגיאה, דואגת המערכת לפירוק כל האובייקטים בבלוקיס המופסקים. הדבר נעשה בדרך דומה לזו המתבצעת אס התוכנית היתה מגיעה לסוף הבלוק. עובדה וו חשובה במיוחד למערכות המטפלות באובייקטים, משוס שיש לבצע את המפרקים של האובייקטים, שבדרך כלל משחרריס משאביס כמו ויכרון, או סוגריס קבציס. בכל מקרה שלא מבצעיס את המפרקים, עלולה להיות זליגת ויכרון. כלומר, זיכרון שהוקצה ולא שוחרר למערכת, וכך הוא ייאובדיי, כי אי אפשר לנצל אותו. דוגמה - מערך בטוח כדי להמחיש את שלמדנו עד כה, נראה דוגמה של מערך בטוח. מערך בטוח (58810 ץג) הוא מחלקה ב-++6 המספקת את הגישה לאברי המערך כמו במערך בסיסי של השפה. מערך בטוח מוסיף את בדיקת הפנייה לאינדקס המערך - בדיקת טוות (80ת18 %). בעת פנייה לאינדקס מחוץ לתחוס הנוכחי של המערך, יעורר המערך מצב שגיאה המורה על שגיאה זו. <1? 01858> 66801866 ] ץ58562228 018585 ;צעה* ך 7 ס>םב :טס ) עסעעמססתהת 6סטעמ56 7 סת1 ;אססת1 086 6ת1 (108 %ם1 ,82 6ם1)עסעעמססתהת (108)א068ם1 086 ,(5126)52 0 ;ו [ ;[1]58126=582 חטסם = עע8 + (82 6ם1) 585622287 [ ;עעה8 [] 361666 + ()7ץ58102228- 6 ++6 ו-009 למתכנת המקצועי (ב %ם8600628%02][)1 7 ;(1 ,2202)8126ע6טת28 חסעם> (1>0 || 1<=5126) 11 ) ;[1]עע8 מע26%0 לן המחלקה ,58164118 היא מחלקת תבנית שהפרמטר שלה הוא סוג האובייקט במערך. המחלקה שומרת מצביע לתחילת המערך של האובייקטים בזיכרון, ואת גודלו הנוכתי של המערך. בחלקו הציבורי של המערך מוגדרת רשומה (5₪000) המכילה את המידע המורה על שגיאה בפנייה לאינדקס המערך. הרשומה מכילה גס את גודלו הנוכחי של המערך וגם את האינדקס שגרס לשגיאה. הגדרת הרשומה בחלק הציבורי נועדה למנוע זיהום של מרחב השמות הגלובלי של התוכנית. חלק אחר של התוכנית יכול להגדיר ז0ז86ת38 ובצורה זו לא תהיה התנגשות של השמות. הפונקציה שמעוררת שגיאה היא האופרטור של אינדקס במערך []. אופרטור זה מחזיר ייחוס לאובייקט מסוג 1. אפשר להשתמש באופרטור גס לצורך השמת ערכיסם למערך. מכיון שלאובייקט מוחזר ייחוס מסוג 1, אין כל צורה להורות על שגיאה. אופרטור וה מעורר מצב שגיאה מסוג סי 88286. במצב השגיאה מוגדריס כל הפרמטרים של השגיאה שהתרחשה. אופן השימוש בקטעי הקוד הקודמים הוא כזה: (888 <%6ת7>1ץ82287)58102228 1111 בנ1סט ן (++1 ;1>20 ;1=0 סם1) 108 2 = [58]1 ()תנאת %ם1 ו ; (58)10 <%ת7>1ץ28ת5816 1 צץעם ; (88) צ8228 1111 ] ]) (826 שסעעמססםא2::<%ת7>1ץ58162228) ב0860 86 %6>> ":8120 0%2ע62 06ת8ע2 6ם6ט080" >> סגוסס 2 >> א00ם1 26.086 >> ":א06ם1 086 ," >> ] ;0 תעגו26% ו הפונקציה הראשית מגדירה מערך בטוח מסוג שלם. לאחר מכן, מופיע בלוק השימוש בפונקציה שממלאת את המערך (ע318 611) ב-20 ערכים. צמוד לבלוק השימוש (ע00) מופיע בלוק הטיפול בשגיאה אפשרית. בלוק הטיפול (ם6900) מטפל בשגיאות חריגה מתחוס המערך. פרק 8: טיפול בשגיאות ועוד | 227 מכיון שגודל המערך הוא 10 והפונקציה עזג 1411 מנסה להכניס עשריס ערכיס לתוכו, יש חריגה מתחום המערך. האופרטור [] מעורר מצב שגיאה כשהפונקציה עזג 811 פונה לאינדקס 10. הפונקציה 38 1811 מופסקת והבקרה מועברת לבלוק הטיפול במצב שגיאה זה. פלט תוכנית זו ייראה כך : 0 8₪6 ,8126:10 508ע6 םע 080026 חריגים וירושה שפת התכנות ++6 תומכת בירושה גם בעת הטיפול במצביס חריגים. המשמעות של ירושה במקרה גה היא ששגרת הטיפול במצב חריג יכולה לקבל מצביע, או ייחוס לאובייקט. על משתנים אלה פועלים החוקיס הרגילים של ++6. אם יש פונקציות וירטואליות, אזי הפעלה של פונקציה כזו תפעיל את הפונקציה המתאימה לאובייקט הנוכתי, שעליו מצביע המצביע. ירושה ללא פונקציות וירטואליות ניתן להשתמש בירושה עס פונקציות וירטואליות וללא פונקציות וירטואליות. בסעיף זה נראה כיצד משתמשים במנגנון השגיאות ללא פונקציות וירטואליות. בדוגמה הקודמת ראינו רשומה שהכילה מידע על סוג השגיאה. אם נגדיר מחלקה בסיסית למצבי שגיאה, שתחזיק תיאור (במחרוזת) של הבעיה שהתרחשה, וממנה נגזור את כל המחלקות המתארות מצבי שגיאה, נקבל את הקוד הבא : ) ם060%10א2886₪ 01855 2 * ש8ם0 ;(8* 082 8%ת00)צ000 הנ1נסט :טס (802)0 : (5* ע8םת0 56ם0ס0)מסנבסְספסאמספַ8ם2 [ ;(000)8 ) 1 (806 ת610ק06א28800 8%ם00)מםסנססססאמ56ם2 2 = 862 ; (6.562) צססס ] (806 ת060%10א288968 5%ת00ס)=602628%02 מסנסְספסאמספַהם2 (806 =! 18ם6) 15 ; (6.562ס) צק0ס ;15ם6* תעג66ע ] [ ;862 [] 361686 (ע8%2) 11 + ()ם%10ק06א28502- 81ט26נט ספתסס ()06850* ע8ם0 ספמסס [ ;862 מעטססץ 1 ;ן 8 ++-+6 ו-009 למתכנת המקצועי (8* 0282 8%6םת0007)00::ם%10ק06א28560 בנ1בסט ָ (ע8%2) 1% 2 [] 061666 2 + (58)ם16ע0282]8%2 אסם = ע56 ;(5 ,7)562ץ56200 ] המחלקה מ0006₪0א38860 מייצגת את מצב השגיאה הבסיסי, כשהמצביע 5% מצביע למחרוזת המתארת את הבעיה. מכיון שיש למחלקה מצביע לתוויסם שמוקצה בעזרת האופרטור א6ה, יש להגדיר בנאי העתקה ואופרטור השמה. אס לא נבצע הגדרות אלו, נימָצא במצב בו יש מצביעים משותפים בין אובייקטים לאותו אזור זיכרון (עובדה שיכולה לגרוס לבעיות רבות, כמו, שחרור כפול של אותו אזור זיכרון). המחלקה 54608 יורשת מההמחלקה 0600000א23560 (שגיאה בסיסית). בנאי השגיאה 88286101 מעביר מחרוזת קבועה לבנאי השגיאה הבסיסית מ0:גזק00א294860. אופרטור האינדקס [] מעורר שגיאה מסוג 860701ת₪98 כשיש פנייה לאינדקס מחוצ לתחוס של המערך. <1? 01858> 66801866 ] ץ58562228 018585 לפעב- ץק 7 ס>םב :טס ] ת%10ק060א2885600 110סגמוק : עסעעפסטםתאת 06סגוע56 7 סת1 ;106% 86 6ת1 (108 %ם1 ,52 שת1)עסעטמססְתהַת , ("6220% 86ם8ע2 7ץ228ת5816")תסנססססאמ56הם2 ] (108)א068ם1 086 ,(5126)52 כ לו ;[1]8126=52 חטסם = עע8 + (82 6ם1) 585622287 (ב %ם8600628%02][)1 7 (1>0 || 1<=8126) 15 ) ;(1 ,5126)עסעעמססתהת2 חסעם6 ;[1]עע8 מע26%0 ו (888 <%6ת7>1ץ7)58162228ץ8228 1111 בנ1סט זָ (++ב ק1>20 ;1=0 סםת1) 108 ] 58]1[ = 12 פרק 8: טיפול בשגיאות ועוד | 229 הפונקציה הראשית, מוגגות, לוכדת כעת שני מצבי שגיאה. מצב השגיאה הראשון הוא המצב המסוים יותר, מצב השגיאה היורש. מצב השגיאה הבסיסי תופס את השגיאה 0 א 5ת. אס היינו משניס את סדר פונקציות הטיפול, הרי שלעולס לא היתה מתבצעת שגרת הטיפול עבור סמ 6פַתִג8, מכיון שכל אובייקט מסוג 88286101 הוא גם אובייקט מסוג מ110ק00א2486. לכן, שגרת הטיפול הראשונה מתאימה גס לשגיאות טווח. מאחר והמערכת בודקת פונקציות טיפול מהראשונה והלאה, הרי ששגרת הטיפול הראשונה תימצא מתאימה ותופעל. ()מ1נהת %ם1 ; (58)10 <%ת7>1ץ28ת5816 + צעם ; (88) צ8228 1111 ] ) (6ע2 עַסעעמסחֶַםַת2::<%ת7>1ץ228ת5816) ב0860 86 %6>> ":8120 ע0%עע62 066ת8ע2 080626" >> סגטסס 2 >> א00ת1 20.286 >> ":א06%ם1 080 ," >> ] (806 ת060%10א2886₪) 08602 12 6>> ()6.0680 >> סגוסס 02 םעגו26% שימוש בפונקציות וירטואליות אס היינו משניס את הפונקציה 6686 לפונקציה וירטואלית, היינו יכוליס להשתמש במצבי שגיאה בצורה פולימורפית, בדרך הבאה: ) ם006%10א28860 01855 % ((8006₪ ת68ע0650)085% ב1סט 81ט6ץנט [ ;8%2 >> סטס + ;ן <1? 01858> 66801866 ]) ץ58562228 018585 :טס ]+ ם060%10א2886₪ 110מטק : עשסעעתססםתאַת 06גע56 8 ]1 5%ת00 (800%6 מת3650)05%208 בנסט ()0680::ת610ק06א288560 >> סגוס 0 ++6 ו-009 למתכנת המקצועי 6 |>>> "=8126 " >> ;601 >> א06%ם1 086 >> "=א66ת1 088 ," >> ] ;ו 7 ;ו כלומר, במקוס להחזיר מצביע לתווים, מדפיסה הפונקציה 6656 את המחרוזת לפלט הסטנדרטי. בנוסף לזה, הפונקציה היא פונקציה וירטואלית, ולכן השימוש בה דרך מצביע או ייחוס לאובייקט, יפעיל את הפונקציה המתאימה לאובייקט. לאחר שהשתמשנו בפונקציה וירטואלית המציגה את הבעיה למשתמש, נוכל לשנות את הפונקציה הראשית בדרך הבאה: ()ת1נהת %ם1 ו ; (58)10 <%ת7>1ץ228ת5816 + צעם ; (88) צ8228 1111 ] ]) (806 ת060%10א2856₪) ב0860 12 >6>> ()06.0080 >> מגוסס 26600 02 ו כעת מפעילה שגרת הטיפול את הפונקציה הווירטואלית 6686 דרך ייחוס. הפונקציה הווירטואלית של אובייקט מסוג 882801101 תופעל באמצעות ייחוס, כי אובייקט השגיאה גס הוא מסוג זה. כדי שנוכל לתקן את מצב השגיאה, צריכיס לדעת את סוג השגיאה המסוים. הגישה הווירטואלית פועלת כשלא רוצים, או לא יכוליס, להתגבר על השגיאה. השימוש בגישה הפולימורפית יעיל במיוחד לפונקציות ברמה גבוהה, שמפעילות פונקציות רבות אחרות, ולמעשה היא מטפלת רק בשגיאות מסוג זה. לכידת כל השגיאות ברמה גבוהה במיוחד, כמו הפונקציה הראשית למשל, יש היגיוו ללכוד את כל השגיאות. ++6 תומכת בלכידה של כל השגיאות. הדרך בה לוכדים את כל השגיאות מוצגת בשגרת טיפול הנראית כך: (טףסעע8** ע8םת0 ,8260 סםת1)תג1את 6םת1 ןָ + ץעם // פרק 8: טיפול בשגיאות ועוד 231 ] 0 .. .ת8060610א6 צְתב סִנַָבַּתאם // ו שגרת טיפול עס ארגומנט יי...'י תופסת את כל השגיאות האפשריות. במצב כזה יכולה הפונקציה לצאת מהתוכנית, תוך כדי הודעה מתאימה. מצב כזה עדיף על מצב בו התוכנית נכשלת ומפסיקה ללא כל מידע המתאר את הבעיה. 4 | לעורר מחדש את השגיאה ++6 תומכת בעירור מחדש שגיאה. מעורריס מחדש מצב שגיאה במקרה שאובייקט הלוכד מצב שגיאה, מתקן את מצבו הפנימי. אבל האובייקט אינו יכול לתקן את מצב השגיאה עצמו, לכן הוא מעביר את מצב השגיאה לפונקציה הנמצאת מעליו בשרשרת הקריאות. עירור מצב שגיאה מחדש - פעולה זו מושגת על ידי הפעלה של האופרטור אס+ג) ללא כל פרמטרים. כך נעשה זאת : ()5 16סטע / + ץעם 6 פםס1ססתט+ 6%ם06 80086 6811 ... // ] 4+ (4) תססהס 6 2680020 ...0// ם660610א6% מ08006 חסעם66? // ;אסשת ו הפונקציה 1 תופסת כל מצב חריג המתעורר כתוצאה מפעילות של פונקציות אחרות שנקראות בתוך הבלוק של צש. כשמווהה מצב שכזה, מחזיר יבלוק הטיפול במצב החריגיי את המצב לקדמותו, ואז, בעזרת הפעלה של האופרטור אסזגו) ללא כל ארגומנטיס, מעורר את המצב החריג שנתפס שוב. סימון מצבים חריגים פונקציה יכולה לסמן את המצביס החריגיס שהיא מעוררת. הדבר מסייע לפונקציות הקוראות לפונקציה זו לזהות את סוגי המצביםס החריגיס שמעוררת הפונקציה הנקראת, ולאפשר לפונקציה הקוראת להיערך לקראת מצבים כגון אלה. סימון המצביס החריגיס נעשה במקוס ההצהרה של הפונקציה, באופן הבא: ו 5 72) %2 006ע56 2 ++6 ו-009 למתכנת המקצועי ;(1א) חסעםם ()6 18בסט ; (%2 ,1א)חטסעםף ()5 ב1סע הפונקציה 1 מצהירה, שרק מצביס חריגים מסוימיס יכולים להתעורר במהלך הפעלתה. בדוגמה הקודמת מכריוה הפונקציה שרק מצבי 1א או 82 יכולים להתעורר כתוצאה מהפעלתה של1. (1א)חטסעםף ()6 18%בסט %אמסט 8006 60 ...5 // ; 81 שסעםם (%2א ,1א) טסעם%ף ()5 ב1סע ;60 אפסח ע6%ת06 8006 ...// ;2 שסעםת6 ו הפונקציה 1 קוראת לפונקציה 6 שמעוררת מצב חריג 1א, ולכן היא מגדירה גם מצב חריג ּה. אם הפונקציה 1 לא תגדיר את 1א כאחד מהמצבים החריגים שהיא מעוררת (אפילו אס לא באופן ישיר), תסתייס התוכנית בצורה בלתי צפויה. למשל: ל ]) 1אם 06גוע5% ;ן ] ₪%2 562606 3 ] כאם 66גת562 ; (₪%2) טספםף ()4 16סע (כאם ,1אםע) טסעם> ()5 ב1סע 8012 >> "6 61026 5 םת1" >> סטסס ; (ף 12 >> "6 81662 5 ם1" >> סטס0 ; () 1אם שסעם> (2אמ) שטסעםף ()4 168סע | ;61ת6 >> "6 ם1" >> שגוסס ; () ₪%2 שסעם6 ()ת1נהת %ם1 פרק 8: טיפול בשגיאות ועוד ‏ 233 + ץע ;50 ] (1א ₪%1) ם0860 ;1 >> "1א 06סש" >> סגוסס 1 (...) 08002 12 >> "מ6060610א6 ... 60%" >> סגוסס 26600 0; ו הדוגמה מציגה מקרה בו פונקציה מגדירה את 1אם ו-3א8 כמצביס חריגיס שהיא מעוררת באופן ישיר ובלתי ישיר. הפונקציה 1 קוראת לפונקציה ₪ שמעוררת מצב חריג מסוג 5%2. מכאן נובע, שהפונקציה + מעוררת מצב חריג 52 בצורה בלתי ישירה, בניגוד להכרותה. בעת ההפעלה של הפונקציה 1 תיקרא פונקציית המערכת 48 שתסיים את התוכנית. המשפט האחרון נכון, למרות שהפונקציה הראשית ג81ג לוכדת את כל המצביס החריגיס במשפט ג68%0 האחרון. כשהפונקציה אינה מגדירה רשימת חריגיס שהיא עשויה לעורר, היא עלולה לעורר כל מצב חריג. לעומת ואת, אס הפונקציה מגדירה רשימה ריקה של חריגים, היא מתחייבת שלא לעורר כל חריג. זוסעםף ססם 60 // ; () אסעםת6 ()5 18סט ם060%10א6 צְם8 שסעם> ם68 // ;()6 16סט בדוגמה זו + אינה מעוררת מצב חריג כלשהו, ואילו הפונקציה 8 יכולה לעורר כל מצב חריג. מומלצ להגדיר לכל פונקציה את המצביס החריגים שהיא עלולה לעורר. 6 | טיפול בחריגים שאינם צפויים ראינו בסעיף קודס, שיש מצבים בהס נקראת פונקציית המערכת 6%0660)66ח₪. במקרים רבים לא מקובל לסיים תוכנית בצורה זו, ולכן אפשר לגרוס לפונקציית המערכת 6%066666ח₪ לקרוא לפונקציה אחרת של המשתמש, במקוס לסיים את התוכנית. דבר זה ניתן לביצוע בעזרת פונקציית המערכת 6%066066ת₪ 866. ; () (צעק*) ב1סט 6661סץ6 מס61סתט+ 6ם1תעטססץ? 18סט 8 0ם עפסת1סק 8 34601826 // ; (%%ק)60660סא6תט 866 עטעק הפונקציה 60)0646קא6תט 56 מקבלת מצביע לפונקציה לה היא קוראת, במידה והפונקציה 600606קא6פט נקראת, כלומר קרה מצב חריג שלא נלכד, או פונקציה עוררה מצב חריג שלא הוגדר על ידה. הפונקציה 060666א6תט 56% מחזירה מצביע לפונקציה הקודמת שהיתה רשומה למערכת. מצב כזה מאפשר ליצור מחלקה המטפלת ברישוס של פונקציות כאלו: 4 ++-+6 ו-009 למתכנת המקצועי ) סתטת 60660קאפתט 86% 018558 ;סתגטת עטעק :טס (< טעק)6םג1 60660קא6תט 566 [ ;(60660)5קא6תט 886% = 6סםט5 + () סתגות ‏ 60660קא6תט 58566- [ ; (סםט60660)5קא6תט 866 ] ;ו מחלקה זו מאפשרת לרשום פונקציה המטפלת במקרים חריגים שאינס מטופלים. בבנאי של המחלקה נרשמת שגרת טיפול למצביס כאלה. במפרק של המחלקה מבוטלת הפונקציה הזו והמצב חוזר לקדמותו. כלומר, כשאובייקט של מחלקה זו מוגדר, הוא רושם שגרת טיפול במצבים בלתי צפויים, וכשהוא יוצא מתחוס ההגדרה, מבוטלת הפונקציה שנרשמה בבנאי. כעת אנו יכוליס להשתמש באובייקטים כאלה בדרך הבאה: ()ת000610א6 66ם6%1בתג 1סעט ו 12 >> "מסאעםם ת66ס 88ם מתס1סקפסא6 606ת611םתט" >> סגוסס ; (6%1%6)0 ()ת1נהת %ם1 ָ ; (ם0ס060%1א6% 60ם611בםט)505 סםגו1 606606קא6םתט 566 ;(50 2 תעג66ע שימוש וטכניקות טיפול במצבים חריגים עד עתה ראינו את מכניוס הטיפול במצבים חריגים. לאחר שלמדנו את התחביר והמינוח של טיפול בחריגיסם, הגענו למצב בו ניתן ללמוד טכניקות שונות לטיפול במצביס חריגים. נפַתָח גס מספר כלים לטיפול במצביס אלה. מצביס חריגיס המתעורריס בעזרת האופרטור שו0+ם) נראים, במבט ראשון, כדבר קל לשימוש, אולס לא כך הדבר. שימוש לא מבוקר במצביס חריגיס עלול לגרוס לתקלות חמורות. לכן, יש להשתמש באמצעים אלה (עירור מצביס חריגיס) בתשומת לב רבה. זכור, קל מאוד לעורר מצביס חריגיס, אך קשה ללכוד אותס ולטפל בהס כיאות! פרק 8: טיפול בשגיאות ועוד | 235 טיפול בזיכרון כשמקצים זיכרון בעזרת קריאה לאופרטור אסמ, ומתעורר מצב חריג במהלך קריאה לפונקציה, לא ישוחרר הויכרון שהוקצה, באופן אוטומטי. למשל: ;(1א) חסעםם ()6 18בסט (1א) טסעם% ()5 ב1סע ;[0282]5 חאסם = מעסס* ע8ם0 %אמסט 8086 ...0 // ק 60 ;+6סס [] 361666 ו במצב שתואר קודס לכן מקצה הפונקציה + זיכרון לצורך עבודתה, ולאחר מכן קוראת לפונקציה 8; לסיוס, הפונקציה 1 משחררת את הזיכרון שהקצתה. נראה פשוט! אבל מצב העניינים אינו כזה, כפי שנראה מייד. אס 8 אכן מעוררת מצב חריג, אז הבקרה של התוכנית כלל אינה חוזרת לפונקציה 1, ולפיכך הויכרון שהוקצה ב+ אינו משוחרר. כלומר, לפנינו זליגת זיכרון (עזסותסות %, קטע זיכרון שאובד למערכת מכיון שאין משחרריס אותו). תוכניות שאינן משחררות זיכרון נראות תקינות בתחילה, אבל לאחר זמן מה מפסיקה התוכנית לתפקד באופן בלתי צפוי. לו היינו מבצעיס את הקצאת הציכרון באובייקט ומשחרריס את הויכרון במפרק של האובייקט, היינו נמנעיס מבעיה וו. הסיבה לכך היא, שמצב חריג שמתעורר גורס לניקוי מחסנית (180%) התוכנית, וכל מפרקי האובייקטיס שמוגדריס במחסנית מבוצעיס. ) עסק 0185858 ;ק* שַַםס :טס [+ (0ס)ס : (60ס* 82ם62)60 [ ;עס [] 461606 + ()62)6<> [ ;סק מתעטס6פע + ()*ע8ם0 עססהאע2ססס ;ן (1א) טסעם% ()5 16סע ; (82]5[1ם0 חטס6ם)ס עמעסס %ט 806 ...0 // 60 6 ++6 ו-009 למתכנת המקצועי במצב המתואר אין צורך לשחרר את הזיכרון שמוקצה בפונקציה. מפרק המחלקה וק משחרר את הזיכרון ונקרא כשהפונקציה מסיימת את עבודה בצורה רגילה, או כתוצאה ממצב חריג. כדי לטפל בבעיות מסוג זה פפתֶתח שני סוגי מחלקות. המחלקה הראשונה תטפל בהקצאת אובייקטים והשנייה תטפל בהקצאת מערכי אובייקטים. בסעיפים הבאים נראה שתי מחלקות אלו. מצביעים אוטומטיים לאובייקטים מצביעים אוטומטל?ים (0)מוסק 8060) הס מצביעים לאובייקטיםס שהוקצו מהזיכרון הדינמי של התוכנית, בעזרת האופרטור שסם. מצביעים אוטומטייס משחררים את המצביע שאליו מתייחסים במפרקיס שלהס. פרט לכך, מצביעים אלה מתנהגיס כמצביעים רגיליס. המחלקה צ)0 8660 מייצגת את המצביע האוטומטי. מצביע כזה נקרא, בסלנג של מתכנתי ++6, מצביע תכם (6)תוסק 811ת5). מחלקה זו היא מחלקת תבנית שהפרמטר שלה הוא סוג האובייקט שאליו היא מצביעה. אובייקט מסוג שק סטג מאותחל בבנאי שמקבל מצביע מסוג מתאים. במקרה אחר, האתחול הוא בעזרת בנאי העתקה. כשמאותחל אובייקט מסוג שק סוט בעזרת אובייקט אחר מאותו סוג, יש לשחרר את המצביע של האובייקט חשני, כדי למנוע שחרור כפול של המצביע שאליו מתייחסיס שני האובייקטים. שחרור המצביע מתבצע על ידי הפונקציה 1616486, שמאפסת את המצביע ומחזירה מצביע לערך הקודס שלו. לפי הגדרת השפה, הפעלת אופרטור 466166 על זיכרון מאופס אינה מבצעת דבר, ולכן איפוס המצביע הכרתי ומספיק. הפונקציה 592 מחליפה בין המצביע הנוכחי למצביע הנתון לפונקציה כארגומנט. הפונקציה 160096 משחררת את הציכרון שאליו מצביע המצביע של האובייקט הנוכתי. 0 ע86ט0 1588 6282168 בסנ1םתח ע6סםת01ק 882% 8 18 - עספס ססטה8 // 8% 16 תפתח 7ץ806008%10811 ע6ס6ת1סק 8686ם1סק 6םג₪ 661666 // 86 05 סגס // <1? 01858> 66801866 ]) ע6ק 8060 018588 עס6תנסס פםס // ;עפס* 7 :טס [+ (ס)עפס : (0=ס* 62)7ק ססטה8 (()%2)82.2610886ס : (ק68 <1>ע62 סספט62)8ק 8060 0 [ ;62 4616066 + ()62ק ססגוה8- (8ת82 <1>ע%2ק 8602028602=)8060 <62>7ק 8060 פרק 8: טיפול בשגיאות ועוד | 237 ו ו [ ;מסס ;סק מע660%ת2 [ ;סם ; 5 בת₪ מסגו6 [ ;עפ מעטסשע + 8%ם00 ס ;צסס=ס* 7 ) ; (0=ק* 2696%)7 16סע 65=0 ; מסגו6 ו * תע6%%0%ת 6 + 6פ5םת0סס = 0; 6 עסס ; (עףק.5ם2686%)2 [ ;2סק* םעט260 + 00286 ()*600628%02 () <-8602ת60ק0ס* *066)( *+616886 )( (ס* 1) סה8טפ* 7 ;עס = כן* יח ח ָ (ק8* 71)פטסתסע ס1סט 568610 ;סם =0;;< % ; ס=ס> א | ו הפונקציה המסובכת ביותר בנושא זה היא זו שמבצעת השמה מחדש למצביע. הפונקציה 16% מקבלת מצביע, ומשחררת את המצביע הקודם, אס אינו זהה למצביע הנתון לה. לאחר מכן, משימה הפונקציה את המצביע הנתון למצביע של האובייקט הנוכחי. כלומר, הפונקציה מחליפה את המצביע של האובייקט הנוכחי במצביע נתון. עססתנ1נסס 018 +1 ₪68 1% השימוש במחלקה זו הוא כזה: 12 >> 81ט >> "=81ט ₪686 8060-::₪6586 ססג8" >> סגוסס 51 .4 תשסש6ט61 6ם5 סם ע6סת1סק 016 6ם₪ 26866 // תס תסט1ש 88 586 6ם₪ ססם 18 // 66801866 >01858 ?1< (ק* 62>1<::2080%6)7ס ססג8 ב1סט 6ם11ת1 ו ;ק6 061666 ;ט=1אט + (ט %ם800628602=)1 ₪686 ססו8 [ ;18ם%* מעט660ע2 ;2 = סם* ;ס = ע (ק =! ס6) ] ₪686 ססגו 2 ם (0=ט 6ת₪68%)1 ססגו8 0 ₪68%6)( ;קט = 1 ו 7 % 4% 8 018885 םג :טס 8% העט ו המחלקה 6+ 860 הינה דוגמה לאובייקטיס שעליהס יכול המצביע החכם להצביע. ההדפסות במפרק של מחלקה זו נועדו להדגיס את פעולת המצביע התכם ולהציג פירוק אובייקט. 208 ++6 ו-009 למתכנת המקצועי לל - )+ ב ;[ )+ 2אם 7 -+ ב 5606 1 ו יפ ; (₪%2) טספםםף ()4 168סע (כאם ,1אם) טסעם> ()5 ב1סע %2 8000 חסם = ק <₪698% ספטה62>8ק 8060 ל = כן* 12 >> "6 6ע6500ס + ם1" >> 0006 ; 5 12 >> "6 ע8580 1 ם1" >> 006 ; () ₪81 שטסעם6 ו הפונקציה 1 מקצה אובייקט מסוג 16% 0זט4, ולאחר מכן מעדכנת את ערכו. מכיון שהפונקציה 8 מעוררת מצב חריג, אין התוכנית מגיעה לשורת ההדפסה השנייה, ובכל זאת נקרא המפרק של האובייקט 16 סוטג. פלט ההדפסה של קטע הקוד הוא: 1=1אט 668% 8060-::66856 ססטה מצביע אוטומטי למערך של אובייקטים מצביע אוטומטי למערך של אובייקטים (סומנסק 88 סוטג) מוקצה בעזרת האופרטור []ש6ם, אופרטור ההקצאה של מערך. מחלקה זו היא מחלקת תבנית ופרמטר התבנית הוא סוג המערך. במחלקה זו יש פונקציות דומות לאלט שבמחלקה הקודמת, פרט לעובדה שיש התייחסות לכך שהמצביע הוא מצביע למערך. האופרטור הנוסף במחלקה שק 0000 הוא אופרטור הפנייה לאינדקס (]) של המערך. אופרטור זה מחזיר ייחוס לאיבר נתון במערך. דבר וה מקנה למחלקה התנהגות כמו מצביע למערך רגיל של השפה. כשמפעילים את אופרטור 86166 עבור המצביע ₪, משתמשים באופרטור שחרור מערכים. גם כאן וגס במחלקה הקודמת, האחריות על מתן סוג המצביע הנכון מוטלת על המשתמש. כלומר, אם ניתן מצביע מסוג 1, המצביע למערך במחלקה הקודמת, או מצביע המצביע לאובייקט מסוג 1 במחלקה הנוכחית, התוצאות אינן מוגדרות. .תעה ם1161טע 8 60 עססת1סק 80826 8 18 עססק 8228 ססטה8 // % מתסתח צץ28ע8 66ם11ע62התט 626 0616668 665ת1סק 6ע8ת58 6מע // .9 05 סט00ס 6088 // <1? 01858> 66801866 ] עס 82287 8060 018589 קמסס* 7 :טס [+ (סם)עס6ס : (0=ס* 2)7סס צץ8228 ססטה8 פרק 8: טיפול בשגיאות ועוד | 239 (ק68 <1>ע52 צץ8228 62)8060 ץ8228 8060 (()80.2616886)ע62ס 0 [ ;62 [] 8616686 + ()62ק צץ28ע82 ססגוה- (8ת82 <71>ע52ק 82287 60ס0ו600628%02=)8 <62>1ק ץ8228 8060 [ ;18ם₪* תעט66ע ;(ע%ק.8ם2656%)2 [ ;5סק* תעגס6ע + 008% ()*600628602 [ ;עסק תעגס6ע + 0086 ()<-ע628602ס0* [ ;[1]עסק םמעט266 ) (ב %ם1)[]ע600628%602 [ ;עס תעטספשע + ספתסס ()66ק0* [ ;ס תעטספע ;0=עסק ;ע6ס=ס* 7 + ()1616886* יח יף ; (0=ק* 656%)71ע2 הנ1נסט (ס* 1) ס8ש5* [ ;ס6 מעטס6ע ;ק = עסס ;עס = ס>* ך (ק8* 6)71טסת6ע 16סט 568610 ( ;ק6 [] 64618686 ;0=ק ;ק=ק6* ך יח ;ן + .עפסת1סס תסשט1ף 6םתם 60 שְהעע8 6םתם 0 עפסת1סק 6םם 268668 // מפםתם ע6סת1סק 016 85 6ת88 6ם5 06ם 18 ע6סת1סק תפט1ף 6םס // ע6סת1סק 0186 646166658 // 66801866 >01858 ?1< (ק* 1<::20866)71>ע5ס צץ8228 ס6ט8 בנסע ָ ח ;עסק = ס>* ] ;ק = עסס (ק =! ס5ף) 15 ;סקס [] 061666 אופן השימוש במחלקה זו פשוט: (כאם ,1אםע) טסעם%> ()5 ב1סע 57 = 8228126 סםת1 005% ;[668%]8228126 0סט8 שסם = קש <₪686 6268060 צץ8228 ססטה8 (+1+4 ;1>82281206 ;1=0 %ם1) 108 ;1 = [1]ס 12 >> "6 6ע6502ס 5 ם1" >> סטסס ; (60 012 >> "6 816602 5 ת1" >> סטסס ; () ₪81 שסעם6 0 ++6 ו-009 למתכנת המקצועי השימוש באובייקט ע הוא כמו שימוש רגיל במצביע למערך אובייקטיסם בשפה. הלולאה בפונקציה מכניסה ערכיס עוקבים, החל באפס, אל האיבריס העוקביס של המערך. הפונקציה 8 מעוררת מצב חריג, ולכן לא תבוצע שורת ההדפסה האחרונה בפונקציה +. לעומת ואת, המפרקיסם של האובייקטיס הנמצאיס במערך ייקָראו, ופלט קטע תוכנית זו נקרא כך: % 65026 5 ם1 > ם1 814 668% 8060-::66856 ססטה 3 מ008%0 8060-::₪68% ססגו8 1=2הט ₪686 8%860-::₪68% ססט8 1=1אט 668% 8060-::66856 ססטה 1=0הט ₪686 8860-::₪68% ססט8 שימוש במשאבים זיכרון המחשב הוא אחד ממשאבי המחשב. משאביס אחריס של המחשב יכולים להיות מתארי קבצים (605011010:8 1116), אשר לעתיס מכניס אותס מצביעים לקבצים, או זיכרון משותף למספר תהליכים. כאשר נרכשים משאביס כאלה יש צורך לשחרר אותם, אחרת התוכנית אינה יכולה לתפקד באופן תקין. בסעיף גה נלמד טכניקה העוזרת להתגבר על מצביס כאלה. הטכניקה נקראת באנגלית : מ1011141188010 18 ם80018100 10800106. משמעותה בעברית רכישת המשאב בזמן אתחולו (או לכידת המשאב היא אתחול). כבר הפעלנו טכניקה זו להקצאות זיכרון כשהגדרנו את שתי המחלקות (זוק סוטג). העיקרון שהנחה אותנו היה שהמפרקים של האובייקטים שנמצאים במחסנית של התוכנית נקראים גם אם מתעורר מצב חריג. לפיכך, עטפנו את הקצאת הציכרון באובייקט ששחרר את הזיכרון בעת הצורך. נניח שיש לנו פונקציה שקוראת קוב לחוצץ. הפונקציה מקצה עבור החוצצ קטע יכרון המתאים לגודל הקובץ, והיא עושה ואת כך: (6תהת* 0282 85ת2116)00 26086* מַהַם0 2 56080 ; (65%) 5686 2 ,8120 80.86 = 8126 1116 6ת1 ; (צ1תאס עתפ ,פתהת)תסקס = 514 ;[8126 5116]צ8םת0ס שסם = 1טס* מַַַם0 ;(8126 5116 ,פטס ,2080)16 ת866פץ8 6םת5 סם 26800206 6ם6 םע2600 //‏ ;(616056)18 ;פטס תעט60? פרק 8: טיפול בשגיאות ועוד | 241 הפונקציה משתמשת בפונקציית המערכת +89 המחצירה מידע על הקובצ. בין חיתר, מוחזר מידע על גודל הקובץ. הפונקציה מסקס פותחת את הקוב לקריאה ומחזירה ידית לקובץ. בידית וו יש להשתמש כשמשתמשים בפונקציה 1084. לשם פשטות, בדיקת השגיאות אינה נעשית כאן. בקטע הקוד הקודסם עלולה להתרחש בעיית הקצאת ויכרון. כלומר, אס הקוב גדול אין מספיק זיכרון. כשאין מספיק ויכרון יכולה המערכת לעורר מצב חריג 81100 86פ. לאופרטור ש6ת יש אפשרות לקרוא לפונקציה המטפלת במקרה זה, אס הפונקציה מועברת למערכת דרך הפונקציה +13₪016 אוסת 566. לדוגמה: () צץ,סתפסת 05 סטס 16סע ו ;1 >> "שעסתסת 81100866 60 181166 טחטסם" >> 0605 ; (1) 681% 1 0 ; (עצסתסת 05 סגוס)מַ16ת8ם ש6ם 566 ננייח שדבר זה לא נעשה, ושהמערכת אכן מעוררת מצב חריג. כתוצאה מכך, אין השורה הסוגרת את הקוב מופעלת, ולכן יש וליגה של ידיות קבציס. הפתרון המתבקש הוא לעטוף את פתיחת הקובצ באובייקט שסוגר את הקובצ כשהאובייקט יוצא מתחוס השליטה שלו. כלומר: 01885 1116 ] סתם1 :טס ;ן ;(צתאס עת ,תת)תסקס = 50 + (תםת* 82ם0 8%6ם1116)00 -1116)( + 01086)50(; [ [ ;20 מעטס6ע + ()6ם1 628602קס ;ן כעת יכולה פונקציה כמו 1116 1086, שהשתמשנו בה קודם, לחיכתב כך: (6תהת* 0282 85ת2116)00 2086* מַהַם0 2 5608 ; (568%6)850 2 סְ80.86 = 8126 1116 סת1 ; (סַתַהת)58 1116 ;[8126 5116]צ8םת0ס שסם = 1טס* מ8ם0 ;(8126 5116 ,פטס ,2080)56 ;פטס תעט60? בכל מצב חריג ייקרא המפרק של האובייקט 18, ולכן תשוחרר ידית הקוב למערכת. 2 ++6 ו-009 למתכנת המקצועי אילו היינו משתמשים באובייקט מסוג ‏ 180068 לא היינו צריכים להוסיף מחלקה נוספת, שכן אובייקט זה סוגר את הקוב המחובר אליו, במפרק שלו. אבל הדוגמה לעיל נעשתה כדי להמחיש משאבים שיכולים להיות שוניסם מקבציסם. שילוב בין תבניות למצבים חריגים כשמשתמשיס בתבניות (מחלקות או פונקציות) איננו יודעיס הרבה על האובייקטיס של פרמטר התבנית. כתוצאה מכך, איננו יודעים גס את סוג החריגיס שמעורריס אובייקטיס אלה. למשל: <1? 01858> 66801866 ] לעפת 01855 ;דבא ₪ 7 ס>םב :טס [ ;(8110060)82 + (8126)0 ,(2)0ע82 : (5852 סם1)ץה8ללת (82 %ת81100)1 נ1נסט ; [1]52 חסת = קתםס* ץ ]) ב לן כשמקציס מערך של אובייקטים מסוג 1, נקראים הבנאיס חסרי הארגומנטים (בנאי ברירת המחדל) של האובייקטים מסוג 1. בנאי זה יכול לעורר מצב חריג. כמפתתי המחלקה ש4118, איננו יודעיסם אילו מצביס חריגיס מסוגל אובייקט מסוג ד לעורר. מצב זה קיים גס בפונקציות פשוטות כמו: 66801866 >01858 ?1< (2ט8 7 ,601 1)ק8ח5 %הנ1בסט ו ; (1ט) קתס 7 27 = 1[ט ;סתף = 2ץ כל אחת משלוש השורות של פונקציית התבנית 880 יכולה לעורר מצב חריג. השורה הראשונה משתמשת בבנאי ההעתקה של אובייקט מסוג 1. אס בנאי זה מנסה לרכוש משאב ולא מצליח, עלול הבנאי לעורר מצב חריג. שתי השורות האחרונות משתמשות באופרטור ההשמה, שיכול לעורר מצב חריג מסיבות הדומות לאלו של בנאי ההעתקה. דוגמאות אלו מסבירות גס את הסיבה לכך שפונקציה, שלא מצהירה על המצביס החריגיסם שהיא מעוררת, יכולה לעורר כל מצב. פונקציית תבנית אינה יכולה להצהיר על סוגי מצביס חריגיס המתעורריס כתוצאה מהפעלתה! בסעיף זה ניקח דוגמה של מחלקת תבנית המייצגת מחסנית, ונראה כיצד מזהיס את המצביס החריגיס ואיך מטפליס בהס. פרק 8: טיפול בשגיאות ועוד | 243 מחלקת התבנית - מחסנית מחסנית (51808) היא מבנה נתוניס שבו האובייקט האחרון שנכנס הוא הראשון שיוצא. כלומר, המחסנית מקיימת את החוק הבסיסי: נכנס אחרון יוצא ראשון. המחסנית שנממש כאן בנויה על מערך אובייקטים (ע8194) כש-ק0ז מציין מיקוס אחד מעבר לאובייקט העליון במחסנית. השדה 500886 01 6ם6 הוא אינדקס אחד מעבר לסוף המחסנית. כאשר המחסנית מלאה, היא מקצה מקוס חדש, שגודלו כפול מזה שהיה ועוד אלמנט אחד בסוף. כאשר גודל המחסנית הוא אפס, היא מקצה מקוס אחד בלבד! מדיניות ההקצאה של המחסנית גורמת לה לגדול במהירות. הדבר דומה לאלגוריתם של המחלקה ץ418, שראינו בפרקיסם הקודמים בספר זה. כאן מוקצה מערך של אובייקטים, ולכך שני חסרונות עיקרייס: > | לאובייקטיםס המוכנסים למחסנית חייב להיות בנאי ברירת המחדל. * הקצאת מערך של אובייקטים גורמת להפעלת בנאי המערך על כל המערך. מכאן, שייתכן שבנאיס יופעלו (שקול לקריאה לפונקציה) עבור אובייקטיס שלא השתמשו בהם. למרות חסרונות אלה נרצה לראות את בעיות השילוב בין תבניות למצביס חריגים, ולכן לא נסבך את הדוגמה, אלא נפתור בעיות אלו. הפונקציה גפטק דוחפת אובייקט נוסף למחסנית, והפונקציה קסנ מוציאה אובייקט מהמחסנית. אס המחסנית ריקה, מעוררת פונקציה זו מצב חריג. הפונקציה עוקנמס 18 מחזירה ערך השונה מאפס, אס המחסנית ריקה. 66801866 >01858 ?1< 0185855 56080% )] ;ץ228ה* 7 אססת1 6ת61006 1886 // ;קסם 6ם1 ץעה 01 צ680801% // 05 66 ₪ם1 ; (8126 %ם81100866)1 18סט :טס (8602806)0 05 86ם6 ,(600)0 ,(82287)0 : ()56080% 0 [ ;ץ8ע2ע8 [] 861666 + ()5680%- + ()ססס 7 (0 => 500) 15 ; "5680% צשסקתם" חספצםם <1א68> // ; [ק50--]ץ8228 מעט66ע2 1 ] (8081 7 ספתסס)םפטס בנסט (8%602806 05 6ם6 =< סס6) 15 ;(2+1 * 8602806 05 6ם81100866)6 <6%2> // 2 = [++ק8228]60 4 ++-+6 ו-009 למתכנת המקצועי ] [ ;(0 => ק0סם) תעטססע + 86ם0ס ()צ6קח6 18 6םת1 ;ו הפונקציה 811008466 מקצה זיכרון בגודל נתון. לאחר ההקצאה מועתקת תכולתו הקודמת של המערך לאזור החדש ואז משוחרר האזור הישן. <1? 01858> 66801866 (52 %ת5680%>71<::811008%6)1 ב1סטע ָ <6%3> // ;[71]52 חסת = עעהסת>* 7 (++1 ;8602806 05 6מם1>6 ;1=0 סת1) מס: <6%4> // ;[1]ץ28ע82 = [1]עעש8קתס ;ץהעעה [] 061666 ;עקת = צְ8228 660 05 5602806 = 27 השימוש במחלקה 5)90% השימוש במחלקה זו פשוט למדי. אובייקטיס מוכנסיס למחלקה בעזרת הפונקציה בפטוק ומוצאיס ממנה על ידי הפונקציה קסק. נגדיר מחלקה %א16 המייצגת מחרוזות ונכניס אותה למחסנית. המחלקה )168 מחזיקה מצביע לאזור בויכרון שאליו מועתקת המחרוזת הנתונה לבנאי של מחלקה זו. כשיש מחלקה ולה מצביעים למחרוזות, מומלצ להגדיר למחלקה בנאי העתקה ואופרטור השמה, כדי למנוע הצבעה כפולה לאותו אזור זיכרון. כתוצאה מהצבעה כזו עלול אזור הזיכרון להיות משוחרר פעמייס. המחלקה משתמשת בפונקציות המערכת המקצות זיכרון (ק5060) והמשחררות אותו (1106). ] %א76% 01858 2 * 88ם0 (8* 082 8%ם00)צקסס בנ1נסט [ ;(802000)58 = ע80 ;(1206)8%2 (ע56) 11 1 :טס [ ;(5)צץ000ס ;862=0 ] (""=8* 0282 56ת6)00א76 [ ;(ע5206)562 ] () 768% [ ;(8%2.%)7ץ000 ;862=0 1 (60 716%%6 56ת6)00א76 ח (60 1686 86םת60028602=)00 686" [ ;15םת6* מתעט66ע ; (ע6.56)צ000 ]1 [ ;5802 מעטס6ע + ()* ע8ת0ס ספתסס עססהעסקס [ ;(ע8801)562 מעט66ץ + ()%6ם1 628%0%קס ו [ ;(ע8605)586 תעטס6ץ ()1108% ע62860%ק0ס פרק 8: טיפול בשגיאות ועוד | 245 הפונקציה תפטק מכניסה למחסנית אאָחז אובייקטיס מסוג %א16. הפונקציה מקבלת ייחוס למחסנית של אובייקטים מסוג +768. (א8ת %ם1 ,65 <%א5680%>716)םפ5גטס ב1בסט ;[32]+טס 028% ] (++1 ;אהת>1 ;1=0 6ם1) 108 ; (32 ,0%ומ)ע05% ת085629%208ס 7 >> 1 >> 0868 ; (5גוס)ס 76%%6 ; (ס) םפגוס. 5 ו הפונקציה קסק מוציאה אובייקטיס מהמחסנית. הפונקציה מוציאה אובייקטיס כל עוד המחסנית אינה ריקה. האובייקטיס שהוצאו מודפסיס לפלט הסטנדרטי. (868 <56080%>16%%)ססק ב1סט ו + (()ץ6קתס 8.18!) 16נ1םט ;" " >> (()00ק.8)%ם1 >> סטסס ] ;081[7ת6 >> 00806 ו הפונקציה הראשית מגדירה מחסנית וקוראת לשתי הפונקציות הראשונות כדי להכניס, להוציא ולהדפיס את האובייקטיס שבמחסנית. ()מ1נהת %ם1 ;57 <5%80%>710%6 ;(25 ,5)תפוס ; (8) ססס ;1 תעגו66ע האובייקטיס מודפסיס בסדר הפוך להכנסתם, מהגדול לקטן. פלט התוכנית ייראה כך: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 טיפול במצבים חריגים בקטעי הקוד שראינו בסעיפים קודמים, היו מספר מצביס חריגים שהטיפול בהס לוקה בחסר. בסעיף זה נלמד כיצד לטפל במצביס אלה במקומות שאפשר. ייתכנו מקומות בהם אין פתרון טוב יותר. מקומות אלה נתאר בהמשך. 6 ++-+6 ו-009 למתכנת המקצועי ניתוח של מצבים חריגים יכול להתבצע לאורך שני מסלולים : + מצבים חריגים מקומיים. מצבים חריגיס שמתעוררים על ידי מחלקת התבנית. > מצבים חריגים חיצוניים. מצביס חריגיס שמעורריס האובייקטיס שמשמשיס כפרמטר של התבנית. הסוג הראשון של מצביס חריגיס קל לזיהוי משוס שאנו, כמפתחי המחלקה, יודעיס מהס המצבים שמעוררת מחלקת התבנית. לעומת זאת, המצביס החריגיס שמתעורריס על ידי פרמטר של התבנית אינס ידועיס לנו, לכן הטיפול בהםס קשה יותר. מצבים חריגים מקומיים במחלקה זו יש מצב חריג מקומי יחיד שמעוררת אותו הפונקציה קסט. לא השתמשנו בעובדה זו. רצוי לציין את סוגי המצבים החריגים שמעוררת פונקציה. במקרה שלא יודעיסם מהס החריגים שפרמטר התבנית מעורר, אין אפשרות לסמן את המצבים החריגיס שהפונקציה מעוררת, ולכן השארנו את הפונקציה ללא סימון כזה. במקרה זה, אין בעיה במחלקה 5180% עצמה, מכיון שלא מתבצע דבר כשהמחסנית ריקה. במצב וה מעוררת הפונקציה קסק מצב חריג ובּה היא מסתיימת. בקטע הקוד המשתמש במחסנית בדקנו לפני כל קריאה לפונקציה קסנ, אם המחסנית אינה ריקה ורק או קראנו לה. מצבים חריגים חיצוניים מצבים חריגים חיצונייס מתעורריס על ידי פרמטר התבנית של המחלקה. המקומות האפשרייס למצבים חריגים כאלה מסומניס בהערות וממוספריס בתוספת הקידומת אס. נעבור עתה על מקומות אלה וננתח מצב אחר מצב. הפונקציה קסס פונקציה זו מחזירה העתק של האובייקט האחרון שנמצא במחסנית, אשר ממומש על ידי קריאה לבנאי ההעתקה של האובייקט, או קריאה לאופרטור ההשמה. אס אחד מהס מעורר מצב חריג, זה יקרה לאחר החזרת הפונקציה, ואין שוס אפשרות לדעת ולגלות זאת בפונקציה קסט עצמה. + ()ססס 7 (0 => 600) +1 ; "5580% צש>סתם" חאסעם6 [ <1א6%> // ;[ק50--]ץ8228 מעט66ע2 ו הדבר היחיד שניתן לעשות, הוא לאפשר הגדלה של טס על ידי המשתמשים במחלקה. אס נוקטיס בשיטה זו, מוטל על המשתמש במחלקה לגלות את הבעיה ולטפל בה בעצמו. לכן, גישה גו אינה מומלצת. פרק 8: טיפול בשגיאות ועוד | 247 הגישה השנייה, היא להתריע בפני המשתמש על אפשרות של מצב חריג, כך שהוא ידע שקייס חשש שהאובייקט בראש המחסנית יאבד ואז לא תהיה לו גישה אל האובייקט. לצערנו, אין פתרון מספק לבעיה גו. המלצתי האישית היא לחימנע במקרים כאלה משימוש במצבים חריגים, ולהשתמש בהם רק במקומות שזה הכרחי. כאמור, קל לעורר מצביס חריגיס, אך קשה מאוד לטפל בהם! הפונקציה חפטש הפונקציה גפטק קוראת לפונקציה 81100916, אשר נדון בה מיד. כשמעתיקים את הערך הנתון לראש המחסנית, יכול אופרטור ההשמה של אובייקט מסוג 1 (הפרמטר של התבנית) לעורר מצב חריג. לכן, יש למנוע את הגדלתו של קסו, ולבצע את ההגדלה רק לאחר שההשמה אכן התבצעה. כך שומרים על שלמות מבנה הנתוניס של המחסנית. ) (8081 7 8%ם00)םפטס נ1בסט (8%602806 05 6ם6 =< ס00ס5) 15 ;(2+1 * 8002806 05 6ם81100866)6 <6%2> // ;1אט > [00ם] ץ28ע82 ; ++קסם הפונקציה סצּ6סוו3 בפונקציה זו יש מספר רב של אפשרויות למצביס חריגיס. במצב הראשון, כשמקציס מערך של אובייקטיס מסוג 1, נקרא בנאי ברירת המחדל (מסגו601מסס )861901) של אובייקטיס אלה. כדי להגן על מצב זה ועל שאר המצביסם החריגים, נשתמש באובייקט מסוג זו 8118 סז שיכיל את המצביע למערך החדש שמקציס. בלולאת ההעתקה של המערך החדש לישן משתמשים באופרטור ההשמה, ולכן ייתכן שהאחרון יעורר מצב חריג. אס מתעורר מצב חריג כזה, אוּי המערך החדש נהרס על ידי המפרק של זזאקננו. בעיה זו נפתרה אף היא. בסוף הפונקציה אנו דואגיס להחליף מצביעיס בין המערך החדש לישן. לכן ייהרס המערך הישן על ידי המפרק של זוגקות). 66801866 >01858 ?1< (52 מ%ת5680%>1<::81100866)1 1בסט ז <3א6> //‏ ;[1]82 חסם = מפהאקתף <71>מ6 צאעע8 0ס6גו8 (++1 ;8602806 05 6ם1>0 ;1=0 סםת1) 1058 <6%4> // ;[1]ץ8228 = [1]עש8קתס ; (צ228) ק8א5. עע8קת6 = צְ822 27 = 8602806 05 66 ו ראינו אס כן, שהשימוש בכלים שפיתחנו עוזר להתגבר על בעיית שחרור זיכרון או משאבים. ללא כליס אלה, היו הבעיות קשות יותר והקוד המטפל בהן היה מסובך. 8 ++-+6 ו-009 למתכנת המקצועי סיכום בפרק זה למדנו על המושג מצבים חריגים ב-++0. ראינו למה צריך מצבים חריגים. הצורך במצבים חריגים נובע מכך שיש פונקציות ב-++6, כגון הבנאי, שאינן מחזירות ערך המודיע על הצלחה, או כישלון. לטיפול במצביס חריגים התוספו בשפה מילות המפתח הבאות : ץא, 0866, אוסזום). כשפונקציה מכניסה בלוק תחת הקוד עש, היא מסמנת למהדר שהיא תטפל במספר מסויס של מצבים חריגים שיתעוררו מפעולות בבלוק וזה. מצב חריג מטופל מופיע לאחר בלוק ₪ ומסומן בבלוק של 69602. בלוק כזה דומה לפונקציה עס ארגומנט אחד המסמן את המצב התחריג בו הוא מטפל. יכוליס להיות מספר בלוקים של טיפול כזה,זה אחר זה. כשמתעורר מצב חריג, נקראים המפרקים של האובייקטים שנמצאים במחסנית. ניצלנו ואת כדי לפתח טכניקות טיפול מתאימות במצבים חריגים. טכניקת הטיפול הראשונה היתה ירכישת משאב בזמן אתחולויי כשביטול המשאב (שחרור) נעשה על ידי המפרק שלו. פיתחנו כלים לטיפול בוּיכרון המוקצה בפונקציות החשופות למצבים חריגים. כלים אלה כולליס מצביעים חכמים לאובייקטים, אשר מפרקים את האובייקטיס הקשורים איתס ומשחררים את הזיכרון הקשור אליהם. לכן, כשמשתמשים במצביעים חכמים בפונקציות הצפויות למצבים חריגים, מובטת לנו שהזיכרון ישתחרר אס וכאשר מתעורר מצב חריג. בנוסף, מובטח לנו שהמפרקים שלהם ייקָראו ואו ישתחררו המשאבים שהוקצו על ידי האובייקטים. ראינו כיצד יש לנתח קוד המשלב תבניות ומצביס חריגיס. כשכותבים קוד הכולל בתוכו תבניות, איננו יודעיס מה הס סוגי המצביס החריגיס שיתעוררו, ולכן דבר וה קשה לפיתוח. ראינו, שקוד פשוט לכאורה, כמו מחסנית, צופן בחובו הרבה מצביס חריגים. לסיכום, המלצתי היא: השתמש במצבים חריגיס כשאין כל אפשרות אחרת. אם אפשר להחזיר ערך המסמן הצלחה או כישלון מפונקציה, השתמש בדרך זו ואל תעורר מצב חריג. פרק 8: טיפול בשגיאות ועוד | 249 - 7 | שאלות 20 האס קיימת דרך טובה יותר להתגבר על מצב חריג בלולאת ההעתקה בפונקציה קסק של המחלקה מחסנית, כך שישמרו האובייקטיס שהועתקו! האס יש יתרון לאפשרות כזו? נתח את מחלקת התבנית עְגזו.. האס יש בה מקומות הצפויים למצבים חריגים: אם כן, כיצד יש לטפל בהס! נתח את מחלקת התבנית +8ו1. האס יש במחלקה זו מקומות הצפויים למצבים חריגיס? אם כן, טפל בהס. האס אפשר להשתמש במחלקת תבנית כדי להגדיר מחלקה שתתגבר על בעיית שגיאה בבנאי, במקוס להשתמש במצב חריג! כתוב את המחלקה 580% בצורה יעילה יותר, כך שלא ייבנו האובייקטיס כשמקציס מערך של אובייקטים. אובייקטים ייבנו רק כשמכניסיס אובייקט למחסנית (רמז: השתמש באותה טכניקה כמו ב-18). נתח את המחלקה מהשאלה הקודמת וטפל במצביס חריגיס שוניס העלוליס להתעורר. ++6 ו-009 למתכנת המקצועי פרק 9 חידושים ב-++;) בפרק וה נבחן מספר תוספות לשפת ++6 שנודעו לאחרונה. רוב המהדרים אינם תומכים עדיין בתוספות אלו ולכן, הדוגמאות שמוצגות בפרק זה אינן רצות תחת רוב המהדרים. להרצת התוכניות בפרק זה השתמשנו במהדרי בורלנד מגירסה 4 ומעלה. אפשר להשתמש גס במהדר מיקרוסופט ובמהדרים אחרים בגירסה מקבילה ומעלה. קבלת מידע בזמן ריצה - 8171 (מסגו8גננס)ם1 1776 6נמג'1 מטא) היא אפשרות שנוספה ל-++6 לפני ומן לא רב. מטרתה לקבל מידע על אובייקטיםס בזמן שמריציס אותם. מידע בומן ריצה מאפשר לנקוט בפעילות יעילה יותר כתלות בסוג האובייקט, גם אס הוא פוגס בתכונות הפולימורפיות של התוכנית. לפיכך, יש להשתמש באפשרויות אלו של השפה בתבונה. מרחב שמות (80860 סהַַגח) מאפשר שמירה על מרחב שמות נקי מהתנגשויות בין חלקי תוכנה בלתי תלוייס (חשוב לזכור זאת, מכיון שבכל פרויקט גדול יש צורך בתיאוס שמות). דבר וה מקל על מפתחי ספריות גנריות, ועל שימוש חוזר בחלקי תוכנה בלתי תלוייס בפרויקטים גדוליס. המרות שונות של מצביעים, או של ייחוסים, מאפשרות לשנות את האובייקטים מקבועים לשאינס קבועים. נראה את סוגי המרות אלו בפרק זה. הן מבוצעות בעזרת מילות מפתח חדשות, ולכן קל יותר לזהות אותן. מידע בזמן ריצה שפת ++6 תומכת במידע בוזמן ריצה המאפשר קבלת מידע שונה, וברמות שונות בומן ריצה. התמיכה במידע בזמן ריצה נתונה על ידי האופרטוריס הבאיס: 6 - אופרטור המזהה את סוג האובייקט ומחזיר ייחוס לאובייקט מסוג 0 6סץ. 0 6פץ+ - מחלקה בסיסית המוגדרת על ידי השפה ומסופקת עס המהדר. 116 מץ0 - התמרות (המרות מבניס) של מצביעיס בומן ריצה. בסעיף זה נסקור את שלושת האופרטוריס האלה. פרק 9: חידושים ב-++6 251 האופרטור 08:0עו אופרטור וה מחזיר ייחוס לאובייקט מסוג 10ח1 6+ לאחר שהוא בודק אס הסוג של שני אובייקטיס זהה. למשל, אס נגדיר את שתי המחלקות 2486 ו-6עוז6כ ואשר להן פונקציות וירטואליות, נוכל להשתמש באופרטור בצורה הבאה: <ת.ת108%268> 61066ת1+ <ת. %0ת61סץ5> 01086ם1+ 01889 2886 ] :טס (+ ()8856 [+ ()2856- 81ט6ע1טש % ()פתאת 01888 666* 02852 0086 81ט126ט [ ;"ספהםת" םע600ת + ?ןז ]) 2886 110סטק : 6ט1ע6כ 01855 :טס [+ ()6ט1ע6כ % ()פתהת 0188595 %66* ע8ם0 00856 [ ;"סט1ע6שכע" םמעט66ת ] ;5 2856 2 6ט1ע6כ ;0781 000016 7812 עאַם60 ((610)0081קץ6 == (בַהט610)0סץ5) 15 ;601 >> "שתסעח 8ם1ם66ת50 פקסס" >> סטסס 16 12 >> "(610)0081סץ₪ =! (81ט610)0קץ₪" >> סטסס ((08610)0ץ6 == (ס)16פסץ5) 15 ;01ת6 >> "(610)0סץעץ₪ == (610)0סץ₪" >> סטסס 16 ;61ת6 >> "(610)0סעץ₪ =! (ס)610סץ₪" >> סטסס ניתן לבדוק סוגיס של אובייקטים, או של משתנים בסיסיים בשפה, כגון 60006 וכוי. האופרטור מאפשר לבדוק זהות, או שוני של סוגי משתניס. בשני משפטי 11 מתבצע ה-66 ולכן הפלט שנקבל הוא : (610)0081סעץ6 =! (6184)0081סעץ6 (6106)0קץ6 =! (ס)618סץ6 סוג המשתנה 041 וסוג המשתנה 81ש6, שונים. גם סוג האובייקט ט שונה מסוג האובייקט 6. 2 ++0 ו-009 למתכנת המקצועי גם אס היינו משתמשים במצביעים למחלקה הבסיסית שפונים לאובייקטים שונים, היינו מקבליס תובאות מתאימות. לדוגמה: 22* ,1קס* 2856 ;5 = 1סס 7 = 2סס ( (2קסע*)610עץ6 == (1סס*)10פַסע6₪) 11 12 >> "!!! 2סק* == 1סס*" >> סגגוסס 1-6 12 >> "!!! 2סק* =! 1סס*" >> שגוסס גס במקרה זּה, למרות שאנו משתמשים במצביע מאותו סוג, הביטוי 1קט* הוא אובייקט מסוג 2886, והביטוי 2קט* הוא אובייקט מסוג 6₪96כ. לכן, הפעלת האופרטור 2616 על שני ביטוייס אלה, יחזיר ערך אפס. במילים אחרות, אופרטור וה יודע להבדיל בין סוגי אובייקטים שוניס, למרות שהתייחסות אליהם היא דרך מצביע למחלקה הבסיסית. לפיכך יהיה הפלט: !!! 2סס* =! 1סס* האופרטור 12616 מחזיר ייחוס לאובייקט מסוג 110 06ץ). המחלקה סזחו 06ץ) המחלקה 1810 106 מספקת מידע בסיסי על אובייקטים. אובייקט של מחלקה זו הוא התוצאה של האופרטור הבסיסי של השפה 1/0616. המחלקה 10מו 6כץ+ מוגדרת כך: ) ס2ת1 6סץ6 01858 58610-0%6ת6ת10קת1 // :עס 18 צְ600 סם // ; (508ת1 סץס 5%ת0ס)50ם1 6סץ6 ; (6 10ת1 6סץ6 צץ8%ם800628602=)00 50ם1 6סץ6 :טס 6ממעצסחץ1סס // ; () 20ם1 6סצ5> 1א8ט%ע1ט סהסתסס 06 ם08 //‏ ;86ת00 (8 50ם1 6סץ6 86ם00)==עס6286סס 6ם1 2 ((8 50ם1 66 86ם628602!=)00ק0ס 6ת1 עס // 2 ((60 16 6סץ6 8%6ת65026)00ס 6ת1 6 05 סתאַם // ()פתהת* ע8ם0 008% ;ן הדבר המעניין הראשון שניתן לראות הוא, שאין בנאיס בחלק הציבורי של המחלקה האחרונה. לכן, אין למשתמש אפשרות להגדיר אובייקטיס השייכים למחלקה זו. הבנאיס בחלק הפרטי של המחלקה מונעיס העתקה של אובייקטים מסוג 10םג 06ע1. אם לא היו בנאיס אלה בחלק הפרטי היה המהדר מעניק בנאי העתקה ואופרטור העתקה אוטומטית לאובייקטים כאלה. גם אין אפשרות לגזור מחלקה אחרת מהמחלקה 0מג 6כְש, דבר שימושי כאשר רוציס להרחיב את הפונקציונליות של מחלקה זו. פרק 9: חידושים ב-++6 | 253 האופרטורים "==" ו-"=!יי מאפשרים לבדוק בצורה פולימורפית שוויון בין סוגיס שוניס של אובייקטים. בסעיף הקודם בדקנו שוויון בין סוגי אובייקטים, בעורת האופרטור 6ו06ע1. אופרטור זה מחזיר ייחוס לאובייקט מסוג 10םו 6סץו, ולכן המהדר מפעיל אופרטוריס המתאימים של 40םו 06ץו, כדי לבדוק את השוויון. הפונקציה 61016ט מאפשרת למיין אובייקטים מסוג 10מ1 06ץ1. הפונקציה מחזירה ערך אמת (1) אם האובייקט הנוכתי ייקודם" לזה שנתון לה. הקדימות יחסית לסדר לקסיקוגרפי בין שמות המחלקות של האובייקטיס ש-1810 06 מתייחס אליהס. המאקרו הבא משתמש באופרטור ₪266 כדי להציג את יחס הסדר בין שני אובייקטיס. אי אפשר להגדיר אובייקט מסוג 10םג 6כע בצורה עצמאית, ולכן יש להשתמש באורפרטור 6וסכץ. המאקרו משתמש בפונקציה 06106 כדי להחליט על הסדר בין האובייקטיס, וכדי לקבל את שמות המחלקה שלהס. מס 0869 6םת5 61096 18 6תס תסגתח צץ615018 061026 618018 // // (%2 ,065026)%1 צ015018 6ם10611 + (((610)%2מץ6)6ע6502ס. (610)%1קעץ6) 15 ; () סתם. (610)%1קץ6 >> סגוסס ;" 065026 18 " >> סגוסס ; () סת8ת. (610)%2קץ6 >> סגוסס ] ] (((610)%1סעץ61026)5ע. (618)%2קעץ6) 11 6156 ; () סתהםת. (610)%2קץ6 >> סגוסס ;" 065026 18 " >> סגוסס ; () סתם. (610)%1קץ6 >> סגוסס ] 1-6 א ; "61000 06ת5628" >> סטסס ;61ת6 >> " השתהה דהה החדהה הת" 6% ₪605 4 ++0 ו-009 למתכנת המקצועי בדרך כלל, מומלצ שלא להשתמש במאקרו, אלא אס אין כל דרך אחרת לפתרון הבעיה. בהמשך נראה שבמקרה זה יש אפשרות אחרת, אך ננצל הזדמנות זו כדי להראות כיצד מגדיריס ומשתמשיס במאקרו מסובך. מאקרו וה דומה לפונקציה, הוא מקבל שני ארגומנטים. בניגוד לפונקציה, במאקרו מטפל הקדס-מעבד ולא המהדר. הקדס-מעבד מחליף את הארגומנטיס הפורמלייס של המאקרו בארגומנטים אקטואליים, שהס הארגומנטיס בנקודת השימוש במאקרו. במאקרו המשתרע על יותר משורה אחת חייבים להכניס את התו לפני כל סוף שורה, כדי לבטל סימן זאה. מאקרו משתרע תמיד על שורה אחת. הפונקציה 1008 16% מפעילה את האופרטור 0616ץ1 על סוגיס בסיסיים של השפה ועל מחלקה בסיסית (2880) ומחלקה שגזורה ממנה (פטגסע), כדי לבדוק שוויון בין אובייקטיס. עס8%ע6קס 678616 6םם ₪686 // // () 65סץ6 ₪686 16סע ;ס 2856 6עט1עסכ ;781 000016 12 פם0 ((610)0081קץ6 == (בַהַט610)0ַסץ5) 15 ;601 >> "שתסעח 8ם1ם66ת50 פקסס" >> סטס0 1-6 12 >> "(610)0081סץ₪ =! (81ע610)0קץ₪" >> סטסס ((08610)0ץ6 == (ס)16פסץ5) 15 ;061ת6 >> "(610)0סץעץ₪ == (ס)616צץקם" >> סטסס 16 ;61ת6 >> "(10)0פסעץ₪ =! (ס)610סץ₪" >> סטסס ;61ת6 >> ()שתהםת. (610)0081קץ₪ >> סגוסס הההההההההההההההההההההההההההההההההההה77777-7------// 0תוססץם 6ם6 סַת1פט פפַתַת 6קצץ6 6>ת1עס // הרה ה = ההדות הוה סיד תי הרי הי תי היה 7 2 %>> ()סתהם. (81₪)5ק7ץ6 >> "=ספַה2" >> סגוסס 2 >> ()פתהם. (810)0ק7ץ6 >> "=ס6ט1עסכ" >> סגסס 12 >> ()שתאת. (16סט0) 610קץ6 >> "=16סטסס" >> סגסס ;1 >> ()פתת. (82ם610)0קץ6 >> "=פַהםס" >> סגסס ;(3 ,065026)0 צץ415018 ;(82ת6 ,ס ; (300516 ,ס ; (262106ע ,065026)400016 צ415018 6 ץ415018 86 ץ415018 ( ( ( ( פרק 9: חידושים ב-++6 | 255 % סנתהתץ3 6ם60%81ם6 // ((688%>2886*<)80 10תהתץ60) 15 ;01ת6 >> "בסאפ2סח 2858 תחססספה8ס" >> סגוסס ()מ1נהת %ם1 | ; () 56065 6686 2 תע660ע קטע התוכנית זה ידפיס את הפלט הבא : (610)0081סעץ6 =! (6184)0081סעץ6 (610)0קץ6 =! (ס)618סץ6 1 2סס₪* =1 1מס* 6 8-6 106 6כ=6ט1צסכ וס =6 001 שאתס=עאַתס טבעפע 6ע06+0% 15 2856 0% 6ע26%00 18 6שט1ע6כ עס פ8ם תח085600% הפלט מראה לנו שמשתנים מסוגים שוניס אכן מזוהים על ידי 10םו 0188%8. כמו כן, מודפסים כהלכה שמות המחלקות. הפלט מראה שהסדר המושג בין האובייקטיס השוניס הוא סדר לקסיקוגרפי בין שמות המחלקות שלה. אפשר לכתוב פונקציה שמקבלת ייחוס לאובייקטים מסוג 60ם1 106 ומשתמשת בהס כמו באובייקטים רגילים. למשל: (6%2 50ת1 6סץ7 86ת00 ,661 50ם1 6סץ7 86ת50)00ם1 צ6415018 בנגנסט )+ ((61.261026)%2) 15 ; () סתהם. 61 >> סגוסס ;" 065026 18 " >> 000% ; () 6ת8ם.%2 >> סגטסס ] ((%2.061026)%1) 15 6156 ; () סתהם. %2 >> 6טסס 6 ++6 ו-009 למתכנת המקצועי ;" 061026 18 " >> 0006 ; () סתהם. 61 >> סגוסס ] 1-6 ; "65020ס 06םת5628" >> סגוסס ; 61מ6 >> " חה ה שה הת היה ה" 6% 606 אופן השימוש בפונקציה כזו: ;((106ע6כ)610סץ5 , (610)2856ס7ץ50)6ם1 צ418018 ; ( (62106כ)610סץ6 , (16מ610)000סץ6) 50ם1 צץ4158018 ;((610)2886ס67 , (82ם7610)0ץ50)6ם1 צץ4158018 האובייקטים המוחזרים על ידי 6ַוּסטְע1 הם כמו אובייקטים רגילים של השפה שניתן להשתמש בהם בפונקציות של השפה. המשפט האחרון בפונקציה 008ץ+ 16% משתמש באופרטור )698% 8:116מץ0, שהוא נושא הסעיף הבא. האופרטור +085 6וה3חץ0 אופרטור זה מאפשר המרה דינמית (6980 81110תץ6) בין מצביעיס, או ייחוס, בומן ריצה. ניתן להשתמש באופרטור מסוג מצביע למחלקה בסיסית, שמצביע בפועל לאובייקטיס השייכיסם למחלקות הגזורות ממחלקה הבסיסית, כדי להמיר את המצביעיס למצביעיס המתאימיס לאובייקט בפועל. אופרטור וה יכול לשמש רק על אובייקטיס פולימורפיים, על אובייקטיס שיש להס לפחות פונקציה וירטואלית אחת. ההבחנה בין סוגים שונים של אובייקטיס חשובה כשהאובייקטיס הס פולימורפים. אופרטור זה "מאפשריי למתכנת לפגוס במערכת תוכנה פולימורפית. במילים אחרות, אופרטור זה פועל בניגוד לכללים המנחים תכנות מוכוון אובייקטים. הוא חושף את התוכנית לסוגיס הקונקרטיס של אובייקטים, וכך חושף את התוכנה לשינוייס כשסוגי האובייקטים משתנים. בתכנות מוכוון אובייקטיס מטפלת התוכנה במצביע, או ייחוס, למחלקה בסיסית מבלי לדעת את הסוג האמיתי של האובייקט. התוכנה מניחה למערכת הפולימורפית לבצע את הפונקציות המתאימות לפי סוג האובייקט האקטואלי. בפרקיס הקודמיס ראינו דוגמה של ציור צורות. היתה לנו מחלקה 523806 ומחלקות אחרות היורשות ממחלקה זו. אפשר לממש פונקציית ציור בדרך זו: (065ק8ת65 <*6ק8מ115%6>92)א328 ב1בסט ;(()ם65.0601ק8ת1)5 6*<::16628602ק8םת115%>5 ] (1) 116תשט ; (016*<)*1ת088%>260%8 10תהת7ץ0 = ס,* סנַָסַתה6ס6ת פרק 9: חידושים ב-++6 | 257 ] (סע) 15 86 סם %א₪885 52601110 תַע0+ת6ס // 1-6 ; () א028<- (1*) בפונקציה 618 נבחין במקרה המיוחד של מלבן. אובייקט מסוג זה מצויריס בצורה שונה. גישה טובה יותר היא לשנות את פונקציית הציור של אובייקטיס מסוג מלבן, כך שתבצע את הפעילות הנוספת הנדרשת, ולא ליצור סוגי אובייקטיס חדשים בזמן ריצה. האופרטור 638% 683816 פועל בצורה דומה לתבניות. בתוך ה-"<>' מכניסים את הסוג שרוציס לקבל כתוצאה מההמרה. האופרטור מקבל כארגומנט את המצביע, או את הייחוס שרוצים להמיר. ייתכנו המרות ממצביעים למצביעים של אובייקטים יורשים, או מייחוס לייחוס של אובייקט יורש. כשממיריס מצביעים, יחזיר האופרטור מצביע מבוקש לאובייקט, אם האובייקט אכן מהסוג המבוקש, או מסוג היורש מהסוג המבוקש. ההמרות נעשות בתנאי שהמרה הינה אל האובייקט של המחלקה היורשת, בצורה ציבורית, מהסוג הבסיסי. כלומר, זוהי ירושה ציבורית, המסומנת על ידי מילת המפתת ס1פטק. אס ההמרה אינה מצליחה, מוחזר מצביע לאפס. קטע הקוד המשתמש באופרטור זה צריך לבדוק אס המצביע אינו מצביע ריק (11טא). כשממירים ייחוס, אין אפשרות לבדוק אם הוא ריק. לכן, אס ההמרה נכשלת, מתעורר מצב חריג 6881 886. המצב מתעורר על ידי המערכת ומתבצע בזמן ריצה: ;1סס* ,סס* ,ס 2856 ;0 פט1עסכ 2 = סס 7 = 1סס + ץע62 ; (קסם*)<66ט085%>260210 10תהתץ0 = 8021 6טנעסכ ; (1סס*)<66ע085%>20210 10תהתץ0 = 8022 סטנעסכ "מת" >> ()סתַהת 0188585 621.68 >> 6גו60 ; () סתהת 01888 022.66 >> ו ) (8 0886 2806) ם0860 12 >> "668902 ם1 088% 286 6ם6ט08" >> סגוסס ] ההמרה של הייחוס ל-612 נכשלת, ולכן מתעורר על ידי המערכת מצב חריג 680 2806. המלצתי לקורא, לא להשתמש בהמרות של ייחוס, כי הן יכולות לגרוס למצב חריג. עס זאת, מומלצ גס לא להשתמש באופרטור ההמרה, משוס ששימוש כזה נוגד את רות התכנות מוכוון האובייקטים. מכיוןו שההמרה לסוג מסויס מחייבת לדעת מהו סוג היעד, אי אפשר להשתמש בקוד כוה עבור סוגיס שוניס ובלתי ידועיס מראש. 8 ++-+0 ו-009 למתכנת המקצועי המרות נוספות של מצביעים עד כה בוצעו המרות המצביעים על פי התחביר של 6. אס היה לנו מצביע שמכיל בתוכו יכולנו לבטל את הקביעות שלו בדרך הבאה: (ע08%2* ע8ת6 56ת00ס)5 ב1סטע ;7 (*ע8םת0) = ע6פ* מַהַם0 0 ] ההמרות הנוספות של מצביעיס אלה פועלות בדרך הישנה ואינן מוצגות בקוד. המרה מסוג (006/) אינה מצביעה על סוג ההמרה שבוצעה. לדוגמה: ;א חסם = אסק* א ספ5םסס 8 ;אם(*צ) = צְס האס ההמרה הקודמת היא המרה ממחלקה בסיסית למחלקה יורשת! האם המרה זו מבטלת את קביעות (60₪80) המצביע! לכן, הקורא קוד כזה אינו יודע מה היתה כוונת מחבר הקוד כשביצע את המרה. בנוסף לבעיית קריאות הקוד, אין המהדר יכול לעזור בהודעות שגיאה כשהמתכנת כותב המרה שאינה מתאימה למה שהוא מתכווין, כי אין ציון מפורש של סוג ההמרה המבוקשת. כדי להתגבר על הבעיות שתוארו כאן, מגדיריס שלושה סוגי המרות כאלה: * )62% 808016 - המרות סטטיות של מצביעים מסוג אחד לאחר. *‏ +68% 6005% - המרות המבטלות קביעות של אובייקט. = 688% +ז6קז0)ם61ץ - המרות המפרשות מצביעים באופן שונה. בסעיפים הבאים נסקור המרות אלו. המרות סטטיות 685% 6וז518 האופרטור (1<)6>+6988 548416 שקול להמרה בסגנון הישן של 1(6), המרה של ביטוי 6 לסוג 1. בדרך כלל, ההמרות הן ממחלקות בסיסיות למחלקות יורשות. לדוגמה: 0188585 2 72 72 ק 018885 (ססם* ע ,מס* 5)5 8%נ1בסט ו 00216 0ם עסק 0886 088% //‏ ;(מס)<*כ>08586 568810 = 62ס* פ ב פרק 9: חידושים ב-++6 | 259 אפשר לחשוב על אופרטור וה כהמרה הפוכה של המרה הבנויה בשפה, כגון המרה ממצביע למחלקה יורשת למחלקה בסיסית. אופרטור זה שומר, קודס כל, על הקביעות, ולפיכך אין אפשרות לבטל )60% בעזרת אופרטור זה. בניגוד לסגנוו ההמרות הישן, ההגדרה של המחלקות המשתתפות בהמרות חייבת להיות מלאה ולא חלקית. כלומר, ההצהרה של מחלקות המשתתפות בהמרה חייבת להיות מלאה. בשל כך, קטע הקוד הבא אינו קביל: 0188585 7 0188585 2 0188585 2 ;מס* ם2 ; (ססם)<*21ע>0885% 868610 = 60* 1 כשממיריס ממחלקה בסיסית למחלקה יורשת, יש מקריס בהס המהדר ממיר את כתובת האובייקט. במקריס אלה חייב המהדר לדעת את גודלס של האובייקטים, לכן המרות כאלה אינן מצליחות. ההמרות בסגנון הישן רק ממירות את סוג המצביע, ללא שינוי הכתובת. מצב זה יכול לגרוס לבעיה. למשל: 7 42% פפהוס ₪ 60ע12סטק :> 01 61855 ;[... 5 110סטס : 22 0185858 ;מס* ם2 ; (קסם)<*088%>22 868610 = 60* 2 במקרה וה הערך של קט אינו מועבר ישירות ל-ק4, וברוב המהדריס מתוסף אליו גודלו של אובייקט מסוג 1. לכן, המהדר מגלה בעיות כשאין הגדרה מושלמת של האובייקטיס ומאפשר לקבל דיווחיס מתאימים. ההמרות של האופרטור 046 580866 נעשות בזמן הידור ולא בזמן ריצה. לכן, אס המצביע אינו מתייחס לאובייקט מתאים בזמן ריצה, עלולות להיות בעיות. במקרה כזה התנהגות התוכנית אינה מוגדרת ואינה צפויה. המרות המבטלות קביעות )085 +6005 המרות שמבטלות קביעות של אובייקטיס מבטלות את מילת המפתת )6025. המרות כאלו מבוצעות תוך שימוש במילת המפתח 688% 6085%. הן יכולות להיות שימושיות באופן הבא : ; (82* ע8םת0 ,581* 8ם0) קת0ע55 6ם1 (82* 0282 86ת00 ,81* ע8ם0 86ם2)00ת8520 ספתסס 6ת1 , (088%>0282*<)81 86ת00) קת0ע562) תע660ע2 ; (((81*<)82ת085%6>0 6פת00 0 ++-+0 ו-009 למתכנת המקצועי מצביע לתוויס קבועים יכול להיות מומר למצביע לתוויס שאינס קבועים. שאר ההמרות שומרות על קביעות המשתנים. איני ממליצ להשתמש בהמרות המבטלות את הקביעות, מכיון שהן עלולות לגרוס לבעיות בלתי צפויות. למשל: ;"800" = 6םת1ע8% 0086 6פ8פתסס* ע8ם0 6פ5תסס (85%2* 82ת0)ע6קקט ₪0 16סע זָ ;'8' - 'ת' = 6 6ם1 ] (ע86*) 16נתט 0 + ע8%* = ע86%* ;++5%7 ; ((09ם8%21 8%ם82*<)00ת088%6>0 58%ת00)ע6ססט 60 אס המהדר הקצה את המחרוזת "ספא" באזור ויכרון קבוע, אוּי הקריאה לפונקציה זססקט 10 אינה מוגדרת. ביטול קביעות מראה על תחביר שגוי בתוכנית, או על הגדרה לא נכונה של פונקציות (למשל הגדרה ללא +8תס6). המרה חוזרת 6854 +6זכז46חו6ז המרות המבוצעות על ידי האופרטור 6880 )6זק67)מ61ע גורמות בסופו של דבר להתייחסות שונה לאזור הזיכרון. אס יש צורך לשנות ערכי מצביעים, אין להשתמש באופרטור זה. למשל, המרה ממצביע למחלקה בסיסית למצביע למחלקה יורשת אינה יכולה להתבצע בצורה טובה על ידי אופרטור וה. היא אינה משנה את ערכי המצביעיס ולכן, במקרה של ירושה מרובה לא מוגדרת תוכנית המשתמשת בהמרה כזו. ההמרה (1<)6>+645 1618060160 שקולה להמרה 1(6). ההבדל הוא, שכאן אין שינוי מצביעים. המרה זו טובה כשממיריס ממצביעיס לסוגים בסיסיים של השפה, כגון מצביעים לתוויס למצביעיס לשלמים. אפשר להשתמש בהמרה זו גס במצביעיס לאובייקטיס שאינס שייכיס למחלקות הקשורות ביניהן ביחסי ירושה. למשל: 01858 %; ;צ 018558 (1081 סת1 ,צְס* צ ,צְס* א ,סק* 86ם0 ,1ק* סםת1)סםבט5 בנסע ו ; (1ק)<*א>0856 6620266ת261 = א* א ; (אסק)<*צ>0885% 606020266ת261 = ץ* צ ; (צס) <*088%>0285 206ק862ם261 = 60* פַַַם0 ; (סס)<*%םת0886>1 26%ק502ת261 = 0ק *1‏ 6ת1 ; (סק)<%ם088%>1 206ק662ם261 = 11 6ת1 פרק 9: חידושים ב-++6 261 האופרטור הזה מרשה להמיר מצביע כלשהו לכל מצביע אחר. האופרטור + 66ע07+מ61ע מרשה המרה של מצביעים לערכים שלמים, ולהיפך. כל ההמרות האלו הן המרות שאינן בטוחות, או שהן תלויות בסוג המהדר. כשמשתמשים בהן, האחריות לדעת את סוג המשתניס המשתתפיס בהמרה היא של המתכנת. שלא כמו האופרטור )68% 518116, אין תוצאות אופרטור וה בטוחות לשימוש. הדבר הבטוח בשפה הוא להסב את תוצאות ההמרה לסוג המקורי, ואו להשתמש בה. השפה מאפשרת להשתמש באופרטור זה כדי להמיר מצביעים לפונקציות, או מצביעים לשדות המחלקה, דבר שאינו ניתן לביצוע על ידי האופרטוריס הקודמים. למשל: [ ;'8' = ס* + (ק* ע8ת0)0ם5621 סִסֶתהתס בנסט ;(* 0282 6פ5םסס) (עק*) ב1נסט 6661סץ6 2 ספ (ק* 82ם0 5)0028% 8נ1בסט "6056" עסעפם // ; (ק)0ם5621 ססַם8ם0 86 מססת1סק 086 08סעע // 86ם8ם0 = + ; (60ת8%21 06ם8ם0886>25<)0 808610 = 05 8% סססתנ1סק 0886 2סשע6 // ; (0ת8%21 06ם0886>25<)028 6020266ת201 = 05 !!!ס 6ם58521 6םת5 86םת8ם60 פססס // ; (ס) (5ס*) ] הפעולה של השמת המצביע לפונקציה במצביע לפונקציה 8תו80 86ה638, היא המרה מסוכנת, משוס שהיא עוקפת את מערכת בדיקת ארגומנטיס של פונקציות. ההמרה היחידה המותרת בשפה (פרט לסגנון הישן) היא זו המשתמשת באופרטור +01 השורה האחרונה היא השורה היתחידה בפונקציה האחרונה שאינה מסומנת כשגיאת הידור. גס במקרה וה ההמרה אינה בטוחה. היא גורמת לשינוי פרמטר הפונקציה 1, למרות שהפונקציה מגדירה את הפרמטר כמי שאינו משתנה על ידה. לסיכום סעיף ההמרות, ההמלצה היא להשתמש בהמרות בתבונה בכל מקרה שתחייביס לעשותן. כשמשתמשיםס בהמרות רצוי לא להשתמש ב- 095%‏ 16כ061תו0ז. ההמרה היחידה האפשרית ללא חשש היא 68% 5)9666. בשאר המקריס חייבת להיות סיבה טובה מאוד לשימוש בהמרות. אני ממליצ שקורא יבדוק את עיצוב התוכנית בכל מקרה שהוא נאלצ להשתמש בחמרות. 12 ++0 ו-009 למתכנת המקצועי מרחבי שמות 6ס50פח3ח ייתכנו מצביס בהס אנו מקבליס שתי ספריות, שכל אחת מהן מגדירה מחלקה מסוימת. היינו רוציס להשתמש בשתי הספריות, אך השימוש בשתיהן באותו קטע קוד גורס להתנגשויות בין השמות השונים. למשל, מספר ספריות מגדירות מחלקות כמו: %), פתוו. 8 // ; ... + 6ם1ע560 01888 ; ... + 007606 01885 ;( ... + 10866א 01885 מפנן // ;[ ...)+ 080066 018855 ; ... + 007606 018585 ; ... + 6ם1ע560 01888 קטע קוד המשתמש בספריות 8 ו-5 ייתקל בבעיית שמות. אין אפשרות להבחין בין המחלקה 8מו5₪ מספרייה 8 לזו של ספרייה פ. בסעיף ה נשקול מספר אפשרויות שונות לטיפול בבעיות אלו. שימוש בהגדרות מקוננות פתרון פשוט, שאינו דורש תמיכה מהשפה, הוא להגדיר את המחלקות של ספרייה כלשהי בצורה מקוננת (868/06). המחלקות של ספרייה א כלשהי יוגדרו בתוך רשומה בדרך זו: ] אס11 566% 2. + 6םת1ע850 018858 2. + 007606 018858 ;.. + 10065ח 018858 ;ן המתכנת המפתח את הספרייה א יכתוב כעת את הקוד שלו בדרך הבאה: % ()מ8::16ם5%21::א110 6ם1 ; (85%2)ת5%216 תעמ66ת המשתמש בספרייה א צריך כעת להשתמש בספרייה כך: ; ("6110ם")8ם1עספא 8ם1ע56::אס11 גישה זו אכן פועלת, אך גורמת לסרבול גם עבור מפתח הספרייה וגם עבור המתכנת המשתמש בה. כדי להתגבר על בעיה זו מספקת השפה תמיכה למקרים כאלה. פרק 9: חידושים ב-++6 | 263 המונח ססהּפפהההּח המונח מרחב השמות - ס6סִהּספוחגת - נוצר כדי להתגבר על בעיית ההתנגשויות בין מחלקות זהות בשם, לבין חלקי תוכנה שוניס שצריכיס לפעול באותה תוכנית. ההגדרה משייכת שמות לקבוצה, מרחב השמות, וכך אפשר להבדיל בין שמות זהים בקבוצות שונות. למשל, ניתן להגדיר כך את הפונקציות הזהות בספריות 8 ו-5: 6 סתאם 1108 // ] 1108 ססַַספסתהת ;2. + 8ם1ע8560 018858 2. + 007606 018858 2 ... + 10066ח 018858 ; (%ם5)1 16סע 6 סתהם 1100 // ] 1100 ססַספסתהַת ;. + 680066 01888 ;. + 007606 018858 2.. + 8ם1ע8560 018858 ; (82ת6)0 %6ם1 ] המתכנת המשתמש בספריות אלו יכול להשתמש בדרך הבאה בפונקציות ואובייקטיס מספריות אלו: ; ("ס611ם")81 8מם1ע1108::56 ; ("18עסט")82 8ם1ע1100::56 (ס 82ם0 ,1 סםת6)1 %הנ1בסט ; (1ב)1108::5 ; (05::8)0ס11 ] המתכנת משתמש בספריות אלו בצורה הבסיסית, כמו במחלקות מקוננות. כשרוציס להשתמש בפונקציה, או במחלקה, השייכת למרחב שמות כלשהו, עלינו להשתמש באופרטור יי::יי שקובע את מרחב השמות האקטואלי שמתייחסים אליו. השורות הראשונות מגדירות אובייקטיס מסוג מחרוזות; הראשון ביניהס שייך לספרייה 1108 והשני שייך לספרייה 00ו1. בצורה דומה משתמשת הפונקציה 6 בפונקציות 1 ו-8 מהספריות 1198 ו-סטון, בהתאמה. ההמתכנת יכתוב את הפונקציות והאובייקטיס של הספריות באופן הבא : (8* 8%ת0 8%ת6)00ם8::5%21מם1ע1108::582 8 4 ++6 ו-009 למתכנת המקצועי (ס 1100::8)0282 6ם1 ו 7 ] גם כאן משתמשים באופרטור *::" כדי לשייך פונקציות, או אובייקטיס למרחב שמות. דוגמה זו מגדירה את בנאי המחלקה שַפו50 במרחב השמות 1/0 ואת הפונקציה - במרחב השמות 1:08. שימוש במילת המפתח פַחוזפו עד כה ראינו שימוש במרחב שמות שהיה שקול לשימוש במחלקות מקוננות. גם ראינו שיש להשתמש באופרטור ''י:: כדי לשייך אובייקטים, או פונקציות למרחב השמות. מצב זה אינו נוח ומסרבל את הקוד, הן של המשתמש והן של כותב הספרייה. פתרון הבעיה הוא מילת המפתח שתופט. השימוש בה גורס להכרת שמות של מרחב השמות מאותה נקודה ואילך, ללא צורך בציון מפורש של מרחב השמות. יש שתי צורות לשימוש במילת המפתח שחופט. בדרך השימוש הראשונה גורמיס להכרת כל השמות במרחב השמות, ובשנייה גורמים להכרה בצורה בדידה של פונקציות, או אובייקטיס. שימוש מוכלל כשמשתמשים בשימוש המוכלל, גורמיס לכך שכל השמות של מרחב הכתובות מוכריס מעתה בקטע הקוד המשתמש בהס. דבר וה מתבצע כך: ;8 ס6ססַַספ65ת8ם 8מם1פגו %ם1ע118::56 סת1פט // ; ("6110ם")81 6ם1ע56 ?3 תד 15 שזש6ת1פט // ;(5)1 כשמשתמשיס במילות המפתח שסהקסגת שחופט ‏ "מכניסים"י את האובייקטיס והפונקציות של מרחב השמות לתחוס המתאים. השימוש באובייקטיס או בפונקציות של הספרייה 1194, אינו דורש שימוש בשס מרחב הכתובות. מצב וה מקל על השימוש במרחב השמות, אך גורס לבעיות כשיש שמות זהיס לאובייקטיס או פונקציות ממרחבי שמות שוניס. 87 מססַַספסתַ8ם 8מם1פגו ;105 סַסַַספסתהםת 8מם1פגו ; ("13עסח")5 6ם1ע56 במצב כזה אין אפשרות להבחין באיזה אובייקט להשתמש מבין מרחבי השמות השוניס. במקרה כזה יש להשתמש באופן מוכלל רק באחד ממרחבי השמות שעליו פרק 9: חידושים ב-++6 | 265 מצהיריס עס שַמופט. אובייקטיס או פונקציות של מרחבי שמות אחרים יש לציין באופן מפורש. למשל: 87 ססַַּספסתַהם 8מם1פגו ; ("6110ם")5 8ם1ע56 ; ("18עסט")81 8ם1ע1100::56 שימוש מפורש בציון מפורש של מרחב שמות נעשה באמצעות מילת המפתת פַפופט בצורה בדידה לאובייקטים, או לפונקציות ממרחב שמות נתון. תחביר השימוש המפורש: 7 : :1108 8מם1פגו ;: :1100 6מם1פגו בשורות אלו מצייניס שהמחלקה 518 שייכת לספרייה 1188 והפונקציה 6 שייכת לספרייה 95ו1. לאחר הגדרות אלו אין צורך להשתמש בשמות מרחבי השמות. אפשר להשתמש באובייקט ובפונקציה באופן ישיר, בצורה הבאה: 8 שת1פגט // ; ("5)"8 6ם1ע56 ;0 שםס 8 שת1פגט // ; (0)0 השימוש במילת המפתח פַמופט גרס להכרת הספריות של השמות והאובייקטיס שאנו מתייחסיס אליהס. אס מוגדריס כבר בתחוס זה משתניס או מחלקות באותס שמות, נוצרת התנגשות שמות והמהדר יסמן ואת כשגיאה. כינון של מרחבי שמות ניתן לקונן מרחבי שמות כפי שאפשר לקונן מחלקות. קינון מרחבי שמות מיועד למרחביס מורכבים, שבהס ממספר מרחבי שמות. הגדרת מרחבי שמות מקונניס נעשית בדרך זו: ) 00062 סַסַַספ5סתהת ? 1 סט // ) עסתת1 סַסַַספ5סתהת ; ()52 18סט ; ()53 18סט // ו השימוש במרחבי שמות מקוננים (050800ות8ת 650606ם) דומה לשימוש במחלקות מקוננות. כלומר, יש לספק את השמות של כל מרחבי השמות, מהחיצוני לפנימי, באופן הבא: 6 ++0 ו-009 למתכנת המקצועי ()1+::0056 ב1סע ן ()2+::ע6תת00%629::1 ב1סע ו ; 110 ו בפונקציות שנמצאות במרחב שמות פנימי אין צורך להשתמש בשם של מרחב השמות החיצוני, או הפנימי. לא כך הדבר לגבי פונקציות השייכות למרחב השמות החתיצוני. פונקציות כאלו יכולות להשתמש בפונקציות מאותו מרחב בצורה רגילה, אך עליהן להשתמש בשם מרחב השמות בצורה מפורשת בעת קריאה לפונקציות של מרחב השמות הפנימי. למשל, הפונקציה 11 חייבת לציין את שס מרחב השמות המקונן כשהיא משתמשת בפונקציה של מרחב השמות הפנימי (סמם1). ()1+::0056 ב1סע | ; ()3+::ע6םםמך הרחבת מרחב שמות אפשר להגדיל מרחב שמות (ססהַסִסוַַח) על ידי הוספת פונקציות, או אובייקטיס. אפשרות זו אינה נתונה למחלקות. במרחב שמות ''פתות'י אפשר תמיד להוסיף שמות. הדבר נעשה כך: ) ב סַסַַספ5סתהת ; ()5 18סט ;( ... + 10866א 01888 ;ן // ;()5::ת מס1נססתט1 686םת651תט ע0סעע6 // ;()6::ת ]) ב סַסַַספ5סתהת 2 50806 סתַהם ₪0 6 868 // ;()6 16סט 6 סשת 0ם 80066 מ066 85ם 6 אס // ;()6::ת הוספת פונקציות או אובייקטים יכולה להיות בכל מקוס ובכל סדר. לכן, הקריאה הראשונה לפונקציה ₪ אינה מוגדרת. לעומת ואת, הקריאה השנייה לפונקציה 6 מוגדרת, שכן הפונקציה הוספה למרחב השמות. פרק 9: חידושים ב-++6 | 267 מילת המפתח פופגּ+טחז לשפת התכנות התוספה מילת מפתת 016+₪ע, אשר מתייחסת לשדות שוניס באובייקטיס. כשמצייניס ששדה מסויס באובייקט הוא מסוג 9016)שמח, המשמעות היא שפונקציות קבועות של האובייקט יכולות לשנות אותו. כלומר: ) 8% 01858 ;ך 6ת1 16סמה6טת ; 6םת1 :טס [ ;0 = 4 ;0 = א + ()א %פתסס (70ך 6ם1)ך 866 בנסט יי (ס< 10סט)א% 866 6נ1סע [ ;סא = א + ו הפונקציה (( 5%), המשנה את ערך השדה [, יכולה להיות קבועה, כלומר, אינה משנה את האובייקט עליו היא פועלת. לעומת זאת, הפונקציה (% 5%) שמשנה שדה רגיל (שאינו 8016)טגת) אינה יכולה להיות קבועה. אפשר להשתמש בפונקציות אלו בדרך זו: 2 א 0050 ;א א ;(7)1 866.א ;(2)א% 866.א שר 18 ך - אס // ;(1)3 6.566א תה8ספתסס ם1 6א - 08עע6 ם118610קתסס // ; (4)% 0.866א רק הפונקציה הקבועה ([ 66 מותרת להפעלה על האובייקט הקבוע סא. הפונקציה השנייה (א 666 אינה קבועה, ולכן המהדר דוחה את ההפעלה שלה על האובייקט הקבוע סא. תכונות שדה שניתן לשלנול (8060טו) באובייקטיס קבועיס, נראיס תמוהים במבט ראשון, אך יש בהס היגיון. כדי להבין זאת, נתבונן בדוגמה. נניח, שיש לנו רשימה שמאפשרת להכניס לתוכה, או להוציא ממנה אובייקטים. כמו כן, היא מאפשרת לסרוק אותה. לצורך האיטרציה (כלומר, המעבר על פני הרשימה) מחזיקה הרשימה מצביע לצומת הנוכתי. שינוי מקוס האיטרציה אינו משנה את הרשימה מבחינה לוגית. כלומר, הרשימה אינה קטנה או גדלה. דרישה הגיונית נוספת היא לאפשר למשתמש ברשימה לעבור על רשימה קבועה. כדי להשיג זאת, יכול מפתח הרשימה להשתמש במילת המפתח 4216)מז באופן הבא : ]) 18% 018855 ] ש6ססם 5606 08%82* 18סע ;%אסת* 6בסת ;ו % 6 0% 686 // ;/680ם* סשסת 8 ++-+0 ו-009 למתכנת המקצועי 68 ת15678010 סתסעעטס //;6ת6עעטס* 6סם 16כ8שגוח :וטס [ ;0 = 680ם = סתפעעטס + ()1156 ()1128%* 16סט [ ;(0 : 0868<-%ת26ת00 ? 6מ6עעט0ס) מתעטספע ;680ם = סתפעעטס )+ שפתסס ()1128%* ב1סט 56םת0סס [ ;(0 : 0868<-%ת26ת00 ? 6םמ6עעט00ס) מתעטספע ;680ם = סתפעעטס )+ ()%א6ת* 18סט ;%אפת<-00226% = 6מ6עעט60ס (6ם6עעטס) 15 ) [ ;(0 : 0868<-%ם00226 ? 6ת6עע002ס) םעט26%6 %פתסס ()6אפת* 16סט 0086 ;%אפת<-6%ע0022 = 6םמ6עע00 (6ם6עעטס) 15 )+ [ ;(0 : 6868<-%ת00226 ? ס6ת6עעג0ס) םעט266 ;ן המתכנת שמפתח את המחלקה מגדיר שתי גרסאות של פונקציות שמבצעות איטרציות על הרשימה. גירסה ראשונה היא של פונקציות שאינן קבועות, והגירסה השנייה היא של פונקציות קבועות. במילים אחרות, הגירסה השנייה אינה משנה את האובייקט עליו היא פועלת. לפיכך, אפשר לבצע איטרציה על רשימה קבועה. מילת מפתח +ו0ווסא6 (מפורש) בנאיס של מחלקות בעלי ארגומנט יחיד יכוליסם לשמש כאופרטורי המרה. כלומר, בנאיס יכוליס לשמש כאופרטורי המרה מסוג הארגומנט שלהם אל אובייקט המחלקה. כשיש פונקציות המקבלות אובייקט, רשאי המהדר להמיר את הארגומנט האקטואלי לאובייקט של המחלקה. למשל: ] 768% 0185855 ;7* תס :טס ; (8* ע8ת0 56ת00ס)6א76% (6% 768% ספםתסס)5 ב1סע ; ("0ם1ע8%2 8 18 15םך")1 הפעלת הפונקציה 1 גורמת ליצירת אובייקט זמני על ידי המהדר. אובייקט וה הוא מסוג +א10. האובייקט נמסר לפונקציה + והמהדר דואג להרוס אותו אחרי שהפונקציה חוזרת. לפעמים מצב וה אינו מה שרוצה מפתח המחלקה :א16, כי יצירת אובייקט זמני עשויה להשפיע על ומני הריצה של התוכנית. כדי למנוע המרה אוטומטית על ידי המהדר, אפשר להשתמש במילת המפתתח |01161א6. שימוש במילה זו מסמן למהדר שלא פרק 9: חידושים ב-++6 | 269 להשתמש בבנאי ההמרה, אלא אס נורה לו אחרת בצורה מפורשת. לכן, אפשר להשתמש במילת המפתח בצורה הבאה: ) 8% 01858 ;* עשהםס :טס %2 ((85* 088 6)0028%א76% ?ןז (6% 768% ספםתסס)5 ב1סע 5 086 21106א6 צץ1םס עסעעע// ‏ ;("6ם1ע86 8 18 185םע")1 18 0ע0000ע8%ם60 // ; (("6ת1ע86 8 18 18ם6)"7א1)76 צ11016קאס 9560 18 תסנ1פעסטתס60 0% // בקריאה השנייה לפונקציה + מתאפשרת ההמרה באופן מפורש, ולעומתה נכשלת הקריאה הראשונה כבר בשלב הידור התוכנית. צורה זו ברורה יותר למתכנת שמשתמש במחלקה %א16. בנוסף, המתכנת יכול להחליט מתי לבצע את ההמרה בצורה מפורשת, ואז לשלס ביצירת אובייקטים זמנים. סיכום בפרק זה ראינו אפשרויות רבות וחדשות שהתוספו לשפת התכנות ++6 בעת האחרונה, ולכן אינן נתמכות עדיין על ידי מהדריס רביס. הדוגמאות בפרק זה יכולות לפעול עם חלק מהמהדרים בלבד, לא עם כולם! עס ואת לא ירחק היוס שתכונות אלו יהיו חלק אינטגרלי של כל מהדר ++6. מידע בזמן ריצה (8₪1711) היא היכולת לקבל את סוג האובייקט בזמן ריצה. במערכת פולימורפית בה מטפלים באובייקטיס בעזרת מצביעים גנרים למחלקות בסיסיות יש לכך חשיבות רבה. מידע בומן ריצה יכול לעזור כשיש לבצע פעולות שונות כדוגמת השוואה בין אובייקטים שונים. סגנון חדש של המרות מצביעים, כגון 6850 6ווהתץ0, 6856 5)8060, 6856 60056 ו-)685 +1618076061, תורס ליכולת המהדר לגלות שגיאות, עוד בזמן קומפילציה ולדווח עליהן למתכנת. בנוסף, שימוש באופרטוריס אלה גורס לתוכנה להיות הרבה יותר ברורה, כשהקורא את התוכנה מבין בדיוק מה מחבר הפונקציה רצה לבצע. מרחבי שמות (סספִסַתַא8ה) באיס לפתור התנגשויות בין שמות בחלקיס בלתי תלוייס של התוכנה. השימוש במרחב שמות מזכיר את מרחב המחלקה. לעומת מרחב 0 ++-+6 ו-009 למתכנת המקצועי המחלקה, שבו יש להשתמש באופרטור ההבחנה ''::'י, לכל פעולה אפשר להביא שמות ממרחב שמות אחד לשני, כך שאין צורך להשתמש באופרטור ההבחנה. מרחבי שמות הס פתוחים, כלומר, ניתן להרתחיבס במספר מקומות. מחלקות לעומת זאת, אינן פתוחות ולא ניתנות להרחבה. - 7 | שאלות כתוב תוכנית המאפשרת לכתוב ולקרוא אובייקטיס לדיסק ומהדיסק. 2 השתמש במידע בזמן ריצה כדי לכתוב פונקציה כללית המשווה בין אובייקטיס פולימורפיים. 5 ממש את הרשימה ואת האיטרטוריס מהפרק הקודם, בעזרת מרחבי שמות. פרק 9: חידושים ב-++6 271 פרק 10 ספריית תבניות סטנדרטיות .זפ בפרק זה, ובפרקים הבאים, נלמד על ספריית התבניות הסטנדרטית - .511 (08160ם518 1 1810קנת 1) של ++6. פרק זה משמש כמבוא ותיאור כללי של ספרייה זו, וגס נסביר בו את עקרונות התכנון של הספרייה. בפרקיס הבאיס נראה מספר דוגמאות ונסקור מחלקות שונות של הספרייה. בספרייה יש שימוש נרחב בתבניות ++6. למרות שספרייה זו היא סטנדרטית והתקבלה על ידי המועצה של 581א4, מרבית המהדרים עדיין אינסם תומכים בה. בעת כתיבת ספר זה תומכיס בספרייה המהדריס של בורלנד מגרסאות א.4 ומעלה, המהדר של ?זא (++6), והמהדר ++6 1841 של מיקרוסופט, מגירסה 4 ומעלה. חברת מט5 הכריזה על מהדר שיתמוך גס הוא בספרייה זו. הדוגמאות בפרק זה הורצו בעזרת המהדרים של בורלנד. עקרונות הספרייה .!ד5 הספרייה הסטנדרטית .511 מורכבת ברובה ממחלקות תבנית ופונקציות תבנית. בספרייה יש שימוש נרחב בתבניות ולכן נדרש ידע בסיסי לפחות בנושא, אס לא למעלה מזה. קורא ששקד וקרא את הפרקים הקודמים, רכש ידע מספק כדי לייהתמודדיי עס השימוש בספרייה זו. הספרייה אינה מתבססת על ירושה, אלא על תכנות גנר? (פמוותותגזפסזק 856710). ראינו לכך דוגמאות בפרק על תבניות ופיתחנו וקטור ורשימה מקושרת המבוססים על תבניות. פיתחנו גס אלגוריתמיס המטפלים במבני נתוניס שוניס, ללא צורך לדעת את סוג מבנה הנתונים. תכנות גנרי משתמש בפונקציות המקבלות איטרטוריס לתחוס מסוים שעליהן הן עובדות. האיטרטוריס מתנהגיס כמו מצביעים, ולכן פונקציות גנריות טובות גם למצביעיס וגם למחלקות. על עקרונות אלו מבוססת הספרייה הסטנדרטית של ++6. הספרייה עצמה מחולקת לשלושה מרכיבים עיקריים, כשיש מספר מרכיבים משניים. מרכיבי הספרייה העיקרייס הס : פרק 10: ספריית התבניות הסטנדרטיות | 273 * מכולות (019ת91ום60, או אוספים) - אלה הם אובייקטיס שמכילים אובייקטיס אחרים, כמו למשל רשימה או מערך. + איטרטורים - אובייקטים מסוג וה מאפשריס איטרציות על אוספים המכיליס אובייקטיס אחריס. > אלגוריתמים - אלה הן פונקציות תבנית שאינן קשורות במחלקה מסוימת באופן מיוחד. פונקציות אלו מבצעות אלגוריתם, כמו 826, המוצא אובייקט באוסף כלשהו. ,1, אם כן, היא ספרייה של אוספי אובייקטיס שהס למעשה מחלקות שנבנו בצורה גנרית, ולכן אפשר להשתמש בהן כמעט בכל יישוס. בהיסטוריה של ++6 כבר היו מספר לא קטן של ספריות כאלו, כמו למשל ספריית האובייקטיםס 1זא, ספריית האובייקטיס של בורלנד וספריית האובייקטים של 8068/ 6טפסם. החיסרון של כל הספריות שהזכרנו בכך שלא היו סטנדרטיות. הספריות פעלו בסביבה מסוימת, אך כשהעבירו את התוכנה שהשתמשה בהן לסביבה אחרת, היה צורך להעביר גם את הספרייה. במקריס רבים היה הדבר קשה, ולעיתים בלתי אפשרי. ספריית .511 תצורף לכל מהדר עם ממשק 81אא4, ולכן, תוכנה שתיכתב בעזרת .811 בסביבה מסוימת תפעל גם בסביבה אחרת. חיסרון אחר של הספריות הקודמות הוא אלגוריתמים. הספריות הקודמות לא תמכו באלגוריתמים כגון 801, או סטוףופט (נראה בהמשך). הן סיפקו מבני נתוניס שאיפשרו להכניס, להוציא ולמצוא אובייקטים, וגם סיפקו איטרטורים. הגישה בספריית האובייקטים הסטנדרטית של ++6 שונהת מהגישה המקובלת בתכנות מוכוון אובייקטים. לפי גישה זו, יש מחלקה מסוימת ופעולות ששייכות למחלקה, אך אין פונקציות חיצוניות שפועלות עליה. גישה וו אכן שומרת על עיקרון הסתרת המידע של המחלקה, אך אינה מאפשרת לנצל תכונות משותפות בין משתניס בסיסיים של השפה לבין מחלקות המייצגות אוספים של אובייקטים. גישה זו מתאימה לשפת תכנות מוכוונות אובייקטים טהורה (060מ0110 00[606 6פטק 0 ) כמו א18111818ת5. ב-א811)41ות5 כל משתנה, או מצביע לאובייקט, שנגזר מאובייקט בסיסי נקרא 00[6. לכן, כל פונקציה שייכת למחלקה 00[6 או מחלקה אחרת היורשת ממנה. ממילא, כל פונקציה שפועלת על אובייקטיס מסוג 0016 פועלת על אובייקט היורש ממנה. לכן, אין מקוס וצורך בפונקציות גנריות. לדבר זה יש יתרונות וחסרונות, והדעות בנושא זה חלוקות. ספר וה עוסק ב-++6 ולא בפילוסופיה, ולכן לא נעסוק בוויכוח זה. שפת ++6 מספקת משתנים בסיסיים ופונקציות, בנוסף לתמיכה בתכנות מוכוון אובייקטיס, ולכן היא נקראת ++6 שפה משולבת (6גוטץ1). כשאנו כותבים פונקציית מיון ב-++6 עבור מערך של אובייקטים כמו 6חוזו5, נרצה להשתמש בפונקציה זו גס עבור מערך של מצביעיס לתווים. איננו רוציס להעתיק את מערך המצביעיס לתוויס למערך של אובייקטיס ולבצע את המיון רק לאחר מכן. לכן, אם נכתוב פונקציית מיון עבור מחלקה המייצגת מערך של אובייקטיס, היא לא תהיה טובה עבור מערך של משתניס בסיסיים של השפה. 4 ++-+6 ו-009 למתכנת המקצועי תכנות גנרי הוא המונח העומד מאחורי הספרייה הסטנדרטית, והוא הרעיון המרכזי בספרייה זו. בתכנות גנרי אנו מנסיס להתעלס מסוג האובייקטים, או המשתניס עליהס פועל האלגוריתם, ולהתרכז בפעולה הבסיסית של האלגוריתם עצמו. למשל, אלגוריתס מיון צריך רק לקבל יחס סדר בין האובייקטים ותחוס המתאר את קבוצת האובייקטיס שצריך למיין. סיבות אלו מראות מדוע ספריות האובייקטיס לא הצליחו ב-++6 כמו בשפות תכנות אחרות. ,811 פותרת בעיות אלו ומספקת מבני נתוניס רבים ומורכביס ביעילות רבה, וגס אלגוריתמיס הפועלים על מבני נתוניס אלה ועל מערכים בסיסיים של השפה. הקוד שפותח ב-.511 יעיל מאוד, לכן אין כל צורך לשכתב את הספרייה הבסיסית כדי להגיע לביצועים גבוהיס יותר, פרט לבעיה אחת. הבעיה בקוד וה היא שכולו מבוסס על תבניות, ולכן כמות הקוד שיוצר המהדר היא רבה כפי שנראה בהמשך. בספר וה נשתמש בגירסה הציבורית שפותחה בחברת "11 על ידי 1סַמהשג51 416%.. נציין את יתרונותיה של ספרייה זו בהמשך. ספריית אובייקטים המספקת מיגוון רב של אובייקטים מקלה באופן משמעותי על כתיבת התוכנה, חוסכת זמן וטעויות וגם יעילה מאוד. ספרייה כזו הופכת את התכנות לפעולה נעימה, וחוסכת את הצורך לשוב ולדאוג למחלקות שכבר כתבנו. מכולות ב-.1ד5 ב-.511 יש מספר מכולות (פסמואתס6) השונות זה מזה ביכולות שלהס, אשר מתאימיס למצביס שונים. הממשק לאובייקטיס השייכיס למחלקות אלו דומה בדרך כלל לממשקיס שאנו מכירים, ולכן הדבר מאפשר פיתוח אלגוריתמיס שעובדיס עבור מספר רב של מכולות ואינס קשוריס למחלקה יחידה. במיליס אחרות, האלגוריתמיס אינס פונקציות של מחלקה. המחלקות המייצגות מכולות, כוללות פונקציות הכנסה והוצאה, התלויות במבנה הנתוניס של המחלקה. כל המכולות מכילות אובייקטים, ולא מצביעיס לאובייקטים. כלומר, כשמכניסיס אובייקט למכולה, המכולה יוצרת תחילה העתק של האובייקט, ואת ההעתק הזה היא מצרפת לאוסף האובייקטים שלה. מסיבה זו אין שיתוף בין אובייקטיסם במספר מכולות. המתכנת יכול ליצור אוסף של מצביעיס ואז ליצור שיתוף בין אובייקטיס במכולות שונות. במצב כזה אחראי המתכנת להקצאה ושחרור של אובייקטים. נניח, למשל, שקיימת מכולה כלשהי: 7 ,01 <*6ם62>9%21םת%81ת00 ; ("צ>ס") 8ם1ע56 שסם = ספ* 8מם1ע56 ; (קס080%)5 םפ5טק.01 ; (קס080%)5 ם5טק.01 הכנסנו מצביעיס למכולות ולכן המתכנת גס חייב לבטל את האובייקטיס האלה. כשמוכנסים אובייקטים (ולא מצביעים), אחראי האוסף לשחרור והקצאת זיכרון עבור הצמתיס שבאוסף, וגס עבור האובייקטים שצורפו לאוסף. פרק 10: ספריית התבניות הסטנדרטיות | 275 המכולות מאפשרות למשתמש בהן לשנות את הדרך שבה מוקצה עבורן ויכרון. כך יכול המשתמש לקבוע את אופן הקצאת הזיכרון. לפי מודל התוכנית אפשר לקבוע את סוג המצביעים ל-:₪69 או ₪81 במונחיס של מחשב אישי. הדבר מאפשר גס לקבוע זיכרון שיהיה זמין גס מעבר לתקופת החייס של התוכנית, כלומר )מ6181800. האוספיס הנתמכיס ב-.511 הם: אוסף הדומה לווקטור (דומה לה שראינו בפרקיס הקודמים), האובייקטיס באוסף כזה אגוריס בצורה סדרתית בזיכרון רציף. הגישה לאובייקטים באוסף כזה היא אקראית בעזרת אופרטור [. 1% רשימה מעגלית כפולה. הגישה לאובייקטים באוסף וה היא סדרתית, קדימה או אחורה. 6 תור כפול שמאפשר להכניס אובייקטיס משני הצדדיס (תחילת התור וסופו). התור הכפול גם מאפשר להוציא אובייקטיס משני צדדיו. % אוסף סדור (קבוצה) של אובייקטים. לאובייקטים המוכנסיס לאוסף זה יש יחס של סדר. הדבר אינו דומה להגדרה המתמטית של אוסף (ההגדרה המתמטית של קבוצה היא: אוסף שאינו סדור של אובייקטיס, ללא חזרות). באוסף זה אסורות החזרות של אובייקטיס. התכונה החוקה של אוסף וה היא מהירות גבוהה של חיפוש אובייקטים. אוסף הדומה לאוסף הקודם. אוסף סדור של אובייקטים, אך החזרות מותרות. כלומר, מותר להכניס את אותו אובייקט מספר פעמים. סו מפה, לעיתים נקרא מבנה נתוניס זה בעגה המקצועית - מילון. והו אוסף של זוגות אובייקטים, שכל אחד מהם מורכב ממפתח וערך. המפה היא אוסף סדור לפי המפתחות. באוסף מסוג זה ייתכן רק מפתח יחיד מערך מסוים. קאנתנו[טגת אוסף סדור של זוגות אובייקטים, כשכל וג מורכב ממפתח ומערך. במקרה וה מותר מספר זוגות עס מפתת זהה. כל המכולות, או האוספים, מאפשריס להכניס כל אובייקט לתוכם, כולל סוגיס בסיסיים של השפה, כמו שלמים או 108%. איטרטורים איטרטורלם (100790088) הם אובייקטיס שמאפשרים סריקה של אוספים, כלומר - של מכולות. לכל אחד מאוספים אלה יש הגדרה של איטרטור. איטרטור מסוג מסויס מתאיס אך ורק לאוסף מסוים. דבר וה מאפשר להפעלל פונקציות בצורה גנרית, ללא כל צורך בידיעת סוג האוסף. 7 רואה את האיטרטורים כסוג מצביע מסוים. כשרוצים לקדס מצביע, מפעילים עליו אופרטור "++". כשרוציס להתזיר את המצביע לאחור מפעילים עליו את 6 ++6 ו-009 למתכנת המקצועי האופרטור *--יי. האופרטור יימצביעיי לאובייקט נוכחי שנמצא באוסף. לכל איטרטור יש מידע המציין את האובייקט הנוכחי של האיטרציה. כשרוציס להשתמש בתכולת מצביע משתמשים באופרטור י*יי. בדומה, כשרוציס לקבל את האובייקט הנוכחי של האיטרציה משתמשים באופרטור 'י*יי. הדבר מאפשר לפתתח אלגוריתמיס שוניסם המתאימים למצביעים וגם לאיטרטורים. כבר נפגשנו בטכניקה זו בפרקיס הקודמיס של ספר זה. .51'1 מגדירה את סוגי האיטרטוריס הבאים: > 10078007 4606058 601ת13 - איטרטור לגישה אקראית - איטרטור מסוג ה תומך באופרטורים '++", "--יי ו-יין)'י והוא בעל כל התכונות של מצביעים בסיסיים בשפה. האופרטור "++" מאפשר להתקדס באוסף שאליו מצביע האיטרטור. האופרטור ''--י מאפשר לנוע לאחור באוסף שאליו מצביע האיטרטור. האופרטור יי[]יי מאפשר גישה לכל מקוס באוסף שאליו מצביע האיטרטור. הגישה במקרה זה היא על פי אינדקס. % 078)07)] ב601706)10 [8ת₪101760)10 - איטרטור דו-כיווני - איטרטור מסוג וה מאפשר לנוע לשני הכיווניס באוסף שאליו הוא מצביע. התנועה עס איטרטור זה מתאפשרת על ידי האופרטורים "++" ו- י--'י. איטרטור זה אינו מאפשר גישה אקראית בעזרת אופרטור 'י]''. איטרטור זה נחשב לבעל יכולות נמוכות יותר מהקודם. > 10078008 זה /וץ0/ - איטרטור מתקדם - איטרטור מסוג ה מאפשר לנוע קדימה בלבד באוסף שאליו הוא מצביע. הוא עושה ואת בעזרת האופרטור "++". > 10078008 זה 236% - איטרטור נסוג - איטרטור מסוג וה מאפשר תנועה לאחור בלבד באוסף אליו הוא מצביע. הוא עושה ואת בעזרת האופרטור *--. * 678000)ו )טקם] - איטרטור קלט - איטרטור זה מאפשר השמה בלבד של אובייקטים ממנו אל אובייקט כלשהו. בדרך כלל, הוא קשור לקובצ ומאפשר לחלצ ממנו נתוניס. > 106784018 +%0₪ט0) - איטרטור פלט - איטרטור זה מאפשר השמה של אובייקטים לתוכו. בדרך כלל, האיטרטור קשור לקובצ ומשמש לפלט. לכל אוסף 600431861 מוגדר האיטרטור בצורה הבאה: 12 16008%08::עסת1ה6תסס דבר זה מאפשר לאלגוריתמיס שוניס להשתמש באיטרטור של מכולה נתונה, מבלי לדעת את סוג המכולה או את סוג האיטרטור. שימוש באלגוריתמים ואיטרטורים האלגוריתמיס השוניס יכולים לפעול גם על מצביעיס בסיסייס של השפה. במקריס כאלה יש להבדיל בין סוגי האיטרטורים כדי לממש את האלגוריתמים באופן יעיל. כדי להבין את משמעות הדבר נבחן דוגמה. נניח, שיש לנו פונקציה המקדמת איטרטור, או מצביע, במספר נתון ם. פרק 10: ספריית התבניות הסטנדרטיות | 277 <%ע16602860 01858> 66801866 (ם %ת1 ,81662 1662860%) 08ת86078 1%סטע ָ ;םת =+ 166% ו הפונקציה הגנרית הזו יכולה לעבוד עבור איטרטורים מסוג מצביעים, או עס איטרטורים מסוג גישה אקראית. עבור איטרטורים דו-כיווניס אין פעולה '=+', ולכן קטע קוד וה אינו עובר הידור. אפשר לשנות את הפונקציה הזו בצורה הבאח: <1662860%> 66801866 (ם %ת1 ,81662 ע1662860%) 08ת86078 1%סע ָ (0 < ם) +1 (0 < --ם) 16נ1תשט ;6+ 1-6 (0 < ++ם) 16נתט --; ו פונקציה זו מתאימה לפעולה עס איטרטורים מסוג גישה אקראלת (8000588 גמס6מגע 07 ), או איטרטורים דו-כיוונים. הבעיה נוצרת כשמפעיליס פונקציה וו על איטרטור דו-כיווני. במקרה כזה מספיק המשפט הזה: ;ת =+ 166% במקרים כאלה יעילות הפונקציה גרועה במיוחד, כי נדרשות ם פעולות במקוס פעולה אחת. כדי לפתור בעיה זו מוגדר המושג תווית (888) עבור איטרטורים. נסקור מושג וה בסעיף הבא. תווית של איטרטור כפי שניתן לראות, קיימת בעיית הבחנה בין הפונקציות השונות. אס נכתוב פונקציה גנרית שתקדם איטרטור, היא תהיה בזבזנית מאוד עבור איטרטורים לגישה אקראית. פתרון אחד הוא להגדיר היררכיה של מחלקות איטרטורים. לדוגמה: <6קץ71 01858> 661866 ]) 1606280602 505820 018588 :טס [+ ()16628602 1028206 ()++600628%02 16628602 102826 [ ;18ם6* מעט0ם6ע + // ;ן <6קץ71 01858> 661866 ] 10628602 800088 תסםת8ע 01858 8 ++-+6 ו-009 למתכנת המקצועי :טס [+ ()16628602 800688 מסבםת8ע ;(ם %ם1)=+600028%02 1662860% 800688 מס6ם28 ל כעת יכולנו לגזור את האיטרטוריס שלנו מהאיטרטוריס הבסיסיים, למשל: <6קץ71 01858> 661866 ]) 06016 0185858 :טס ) <706ץ16028%02>1 800688 תססתה8ע 116מטק : 166286058 01858 (ם %ם1)=+8600628%02 16628602 [ ;15םת6* מעטסשע ;םת =+ עטס ]) לן עכשיו אפשר להשתמש ביכולת של ++6 להגדיר גירסה מסוימת של הפונקציה הגנרית 0, באופן הבא : <6סץ71 018558> 66001866 (ם %ת1 ,[8 <06ץ16628602>1 8000688 תססתבּת) 800806 ב1סט הבעיה המתגלה בפתרון וה היא בכך שהוא אינו יכול לפעול עבור מצביעיס בסיסייס של השפה. הסיבה לכך היא שהמצביעים הבסיסיים אינס יורשיס ממחלקה כלשהי, ובפרט אינס יורשיס מהמחלקה ז11079%0 866088 186081 הפתרון שמציגה הספרייה ,811 לבעיה, הוא שימוש בתוויות איטרטורים 100900 5). תחילה מגדירים את התוויות השונות של האיטרטוריס: ;[) 6806 16628608 סוקם1 ס6סגו562 ;[1 680 16028608 סטקסגטוס 6סגו562 ;[) 680 16628608 502826 56206 ;[+ 680 16028608 81ת101260%10ס 56206 2[ 686 18628608 800688 מס6ם28 56206 לאחר מכן מוגדריס האיטרטוריס השוניס והקטגוריות הבסיסיות שלהם. קטגוריות אלו מספקות מחלקות בסיסיות עבור איטרטוריס המוגדריס במכולות השונות. ;(] 16628602 6טקם1 862006 <71 01888> 660001866 ;[) 160286028 סטקסגטס 6סגו562 66801866 >01858 ' -. ק[) 16028608 820אע502 862006 <" ;[] 18628608 81ת161200%10ע 862008 <" ;[] 18628602 800088 תס0םת28 862006 <7 01888> 66001866 60801806 8 פרק 10: ספריית התבניות הסטנדרטיות | 279 לכל איטרטור מוגדרת הקטגוריה אליה הוא שייך. אין וו מחלקה בסיסית שממנה יורשיס האיטרטוריס, אלא הקטגוריה בלבד. כזכור, אין יחס של ירושה למצביעיס הבסיסיים של השפה. <1? 01858> 66801866 % 166028000 סגמסת1 6ם11םת1 + (16628%02>1<8 סטקת1 8%6ת00)ץ0866002 16628605 ;()680 16628608 סטקם1 םעט266 %) ץ0806702 10628608 680 16028608 סטקפטס 6ם11ת1 ] (166286028 סגמוקסגטס ; ()%80 16628602 סגוקפטס םעט2660 66801866 >01858 ?1< % 10628005 502826 6ם11ת1 ] (15628%02>1<8 5029826 8%6ם00) ,0866002 16628605 ;()680 166286028 5028826 םע2660 66801866 >01858 ?1< 6 10028005 81ת101260%10ס 6ם11ם1 1 (1%628602>1<8 81ת0101260%10 8%6םת00)ץ0866002 16628605 ; ()%80 16628602 81ת161260%10מ םע2600 66801866 >01858 ?1< 8 16028000 800688 מס6ם28 6ם11ת1 1 (160628602>1<8 800688 מס0םת28 8%ת00)ץ0866002 16628605 ; ()%680 16628602 800688 תססתה8ע םע2600 66801866 >01858 ?1< %) צץ0806702 10628608 680 16028608 800688 מססםת28 6ם11ת1 + (*ץ ; ()%680 16628602 800688 מססתה8ע םע2660 הערה! בפונקציה ובמחלקות המקוריות יש פרמטר תבנית נוסף, 6סחאזפוע. לצורך פשטות ההסבר הרשיתי לעצמי לבטל אותו. הורדת הפרמטר אינה משנה את עקרון התוויות לאיטרטורים. 0 ++-+6 ו-009 למתכנת המקצועי לאיטרטורים מסוג גישה אקראית (1007000 800088 1ע60ת18) יש שתי פונקציות מועמסות המספקות תוויות. הפונקציה הראשונה מספקת תווית איטרטור מסוג גישה אקראית עבור איטרטוריס מסוג מחלקות, והפונקציה השנייה מספקת תווית מסוג של איטרטור גישה אקראית עבור איטרטוריס שהס מצביעיס בסיסייס. כעת, באמצעות תוויות האיטרטוריס אנו יכוליס לכתוב את הפונקציה 84/8206 בצורה הבאת: 661866 >0188 1662< (ת %ם1 ,6 ע8078206)1862 10סט 6ם11םת1 ָ ; ((()ץ08%660002 16628602,ת ,ך)06ם8008. <206551562860%ת00ת38 01855> 1866קת66 ,[8 שַס6ַעַ66ד1ַפפַ6סתתסְתַַ8) 06ת8008 | 1סט 6ם11ת1 (%580 16628602 800688 מס6םת28 ,םת 6ת1 <%ע811%28%0ם216120%10 01855> 18%66קת66 ,6 811662860%ת101260%10ם) 06ת8008 | ב1סע (580 16628602 81ת161260%610ס ,םת 6ת1 (0 =< ם) +1 (--ת) 16נ1תשט ;ר++ 1-6 (++ת) 16נ1תשט : == ] כלומר, הפונקציה הראשית שנקראת מפנה את הקריאה לפונקציה אחרת, שלה יש את אותס הארגומנטיס, בתוספת תווית ויהוי של האיטרטור. מנגנוו העמסה של ++6 בוחר את הפונקציה המתאימה לפי סוג התווית! טכניקה זו מאפשרת הפעלה של פונקציות שונות בצורה פולימורפית סטטית (נמפנםכזסנתץ!סק 5486). סוג הפונקציה נבחר על ידי המהדר לפי סוג הפרמטריס (התווית של האיטרטור) בזמן הידור, ולא בזמן ריצה. אלגוריתמים אחד הדבריס המייחדים את .511 הס האלגוריתמים של ספרייה זו. בניגוד לספריות אחרות, מספקת .511 מיגוון רחב של אלגוריתמיס גנריס המתאימים ליישומיס ושימושיס רבים. אלגוריתמיס רביס מתוכם טובים גם לאוספיםס בסיסיים של השפה, כמו מערכים. פרק 10: ספריית התבניות הסטנדרטיות | 281 אפשר לקחת את האלגוריתמיס של ,511 ולהשתמש בהס עבור ספריות אחרות, שחסרות אלגוריתמיס כאלה. למשל, ספריית האובייקטיס של 0/8468 6ט8ס החדשה מאפשרת שימוש באלגוריתמיס של,511. בדרך כלל, האלגוריתמים ב--.511 פועלים על תחוס נתון. העיקרון המנחה הוא פעולה בעזרת איטרטורים. האלגוריתס מקבל, בדרך כלל, איטרטור להתחלת התחוס ואיטרטור לסוף התחום. אלגוריתס כזה, למשל, הוא 16 המוצא אובייקט נתון בתחוס. האלגוריתס ממומש בצורה הבאה: <16628%602 01888 ,6קץ71 01855> 66801866 ,1% ע1662800 ,7ץ68%86 6קץ71 0)00286מם11 ע1662860 (188% 16628602 (ץ6א =! 1128%* 66 1886 =! 51286) 116תט ;5% 1+++ %2 מע6%00ע2 ו האלגוריתם הוא פונקציית תבנית בעלת שני פרמטרים; הראשון מייצג את סוג האובייקט והשני מייצג את סוג האיטרטור. הפונקציה מקבלת ייחוס לאובייקט שצריך למצוא, ותחוס המאופיין על ידי האיטרטוריס 820 ו-1886. הפונקציה מחזירה איטרטור לאובייקט הזאהה למפתח שנמסר לה, אס נמצא אובייקט כזה, ואחרת היא מחזירה איטרטור הזהה לסוף התחוס. הפונקציה עשויה להחזיר מצביע לסוף האוסף, ולכן האובייקט האחרון בתחוס אינו נחשב בתוך התחוס. דבר זה מתאפשר הודות לתכונה של ++6, שכתובת אחת אחרי המערך היא כתובת חוקית לקריאה, אבל לא לכתיבה. נוהל עבודה וה בעזרת אלגוריתמיס הביא את המושג תכנות גנרי (670ם80 תות זפַסז), שבו כותבים פונקציות שאינן מכירות את מבנה הנתוניס עליהן הן פועלות. הפונקציות, שמממשות אלגוריתם, מקבלות איטרטוריס לתחילת התחוס ולסופו. פונקציה כזו מניחה שיש לאיטרטור אופרטורים (++) המאפשריס לקדם אותו לאלמנט הבא. כמו כן, מניחה פונקציה כזו שיש אופרטור (*) המקבל את האובייקט הנוכחי כשהאופרטור מופעל על האיטרטור. על פי הנחות אלו יכולה הפונקציה לפעול גם על איטרטוריס של מחלקות יימכולהיי (או אוספים) וגם על מערכים בסיסיים של השפה. דוגמה אחרת לאלגוריתס כזה, היא אלגוריתס המבצע היפוך סדר של אובייקטיס במכולה (אוסף). אס האובייקטיס מסודריס בסדר עולה, מסדר אותם האלגוריתס בסדר יורד. <1662860% 01858> 66801866 (188% 1%6₪78%0% ,1129% ע6286)1%028%0ט60ע2 ב1סע --%2 ) (1856 =! 5128%) 116תט 2 ++6 ו-009 למתכנת המקצועי ; (188%* ,1125%*) 587 ;68%עס (1888 == 1128%++) 15 %2-- ו כפי שראינו קודסם לכן, האלגוריתס מקבל תחוס שעליו הוא פועל, ובכל שלב של הלולאה הוא מחליף את האובייקטיס בקצות התחוס וגס מקטין את התחום. כמו במקרה הקודם, גס כאן יכול אלגוריתם כזה לפעול על מערכיס בסיסייס של השפה, או על אוספים. כשהוא פועל על מערכים בסיסיים של השפה הוא מקבל מצביעים, וכשהוא פועל על אוספיס הוא מקבל את האיטרטור של האוסף. מתאמים (5זס+03) מתאמים (80800089) הס אובייקטים שמקבלים אובייקט אחר, ומשתמשים בו כדי לממש פונקציונליות מסוימת. המתאמים אינס נחשבים כאחד מהמרכיבים העיקריים של הספרייה, אבל הם מציגים רעיון תכנות שראוי לציינו כאן. המתאס עצמו אינו מממש מבנה אלגוריתמיס כלשהו, אלא משמש כמעטפה של מחלקה אחרת שמממשת את מבנה הנתוניס והפונקציונליות הבסיסית. המעטפה מתאמת את הממשק של המחלקה הבסיסית לממשק מבוקש. למשל, אס רוציס לממש מחסנית, עומדות בפנינו מספר אפשרויות. אפשר לממש מחסנית בעזרת מערך, בעזרת רשימה או בעזרת תור כפול. לכן, המחלקה מחסנית יכולה להיות מתאס שמקבל סוג של מחלקה ומממש את הפונקציונליות הדרושה. <1 018858 ,02ם%81ת00 018585> 1866קת66 ) 8080% 01888 62 עסשת681ת00 :טס 5680%)( 1 (ט8 7 ספתסס)םפטס פנסט [ ;(ט)פ6םסע5 םפטק.6 ) ()ססס 7 [ ;()6ם520 6.000 מעטס6ץ ) ;ן המחלקה 5/8068 היא מעטפה (טס1סַעת6) למכולה אחרת, ומשתמשת בה כדי לממש את הפונקציונליות של המחלקה. כל הפונקציות של המחלקה מבוצעות בעזרת המכולה הנתונה לה. כשמגדיריס אובייקט ממחלקה זו, מספקים לו את המכולה ואת סוג האובייקטיס שבמכולה (ראינו שאפשר להסתדר גס ללא סוג האובייקט). למשל: ;נעטפ <%ת1 ,<%ת5680%>660%02>1 2 <%ת1 ,<%6ת5680%>1156>1 למעשה, הגדרנו מחסנית המבוססת על וקטור, או רשימה. לפי סוג השימוש שלנו במחסנית ניתן לבחור את מבנה הנתוניס המתאים יותר. פרק 10: ספריית התבניות הסטנדרטיות | 283 אובייקטי פונקציות (000[6615) חסוףסחט) אובייקטי פונקציות (600[ט0 מ6010ם0) אינס נחשביס כאחד החלקים העיקריים של הספרייה, אך ראוי להכיר מונח חשוב זה. אובייקט פונקציה מתנהג בצורה דומה לפונקציה. קיים אופרטור () שאפשר להפעילו כפונקציה. למשל: ) עסססתטת 06וע5% ()()268%02ק0ס 6ם1 )/ לן אובייקט וה מעמיס את אופרטור הפונקציה, ולכן אפשר להשתמש באובייקט בצורה הבאה: 2 עסססתות 1% יכולת זו חשובה כשרוציס להעביר פונקציה, או אובייקט, לאלגוריתמיס המשמשיס להשוואה בין אובייקטים. האלגוריתס יכול להתייחס לאובייקט כפונקציה, ואז הדרך פתוחה בפני המשתמש להעביר לאלגוריתם פונקציה או אובייקט. האלגוריתס 6580 בספרייה הסטנדרטית של 6 מקבל פונקציה המאפשרת לקבוע את הסדר הערכי (מספרי או אלפביתי) בין שני אובייקטיםס, באמצעות ממיון המערך בויכרון. באופן דומה אפשר לכתוב אלגוריתס המבוסס על פונקציית תבנית ב-++6 למיון מערכים, או מכולות. עלינו לספק לאלגוריתס אובייקט, שמאפשר לקבוע את הסדר בין אובייקטים שונים, או לחילופין, לתת לו פונקציה שמאפשרת זאת. <קתס060 01885 ,10028002 01855> 66801866 (קתס קת00 ,0ם6 16628602 ,8%82% ע1₪628602)%ע8502 בנ1סט ו ל (0 > (06םת6* ,5682%*)קתס) 15 ָ בת תהם6 1688 18 %ע8682 // ו לפני השימוש באלגוריתסם עלינו להגדיר את האובייקט, או הפונקציה, שמאפשרים ביצוע השוואה בין אובייקטים, ולמסור אותם לפונקציית המיון. 4 ++-+6 ו-009 למתכנת המקצועי סיכום בפרק וה הצגנו את ספריית האובייקטים הסטנדרטית של ++6. סקרנו את החלקיס העיקריים שלה ואת רעיונות התכנון שהינחו את מתכנניה. רעיונות אלה לכשעצמס יכוליס לשמש אותנו כשאנו מפתחיס תוכנה לצרכינו. הספרייה הסטנדרטית של ++6 מורכבת משלושה חלקים עיקריים: מכולות (1811019מ020), איטרטורים ואלגוריתמים. בניגוד לגישה מוכוונת האובייקטיס שבה יש אובייקטים בלבד, ספרייה זו מציגה גישה חדשה שמתאימה ל-++6. בגישה זו יש אלגוריתמיס נפרדיס שאינם קשוריס לאובייקטים. אלגוריתמיס אלה פועלים על תחומים נתוניס. האלגוריתמיס משמשים כהפשטה בפני עצמה, כי אין הס מכירים את מבנה הנתונים שעליו הס פועלים. האלגוריתס דורש איטרטוריס, או מצביעיס למבנה נתוניס זה, שיאפשרו לו לסרוק את מבנה הנתוניס. אלמנטיס אחריס המרכיבים את הספרייה כולליס מתאמים (075ס)ו8080) ואובייקטי פונקציות (00[608₪ מסוזסתט1). המתאמיס מאפשרים שימוש במחלקה אחרת והתאמתה למבנה נתוניס מסויס. המתאם מאפשר גמישות למשתמש, בכך שהוא מאפשר לבחור את המחלקה המתאימה. לאובייקט המשמש כפונקציה יש אופרטור קריאה לפונקציה, ולכו אפשר להעבירו כפונקציה לאלגוריתס שצריך פונקציה המתארת את יחס הסדר בין אובייקטיס שעליו האלגוריתם פועל. מקורות ,"110787108 2000110 160מ16ס ב1801110/" .0%ם8ק510 .ג .א מה .₪ .כ מספפטא .1 .4 101 ,24)7(:623 ,8261710206 86 27801100 5010/8176 ++0 :020100 6107100 6ם8 [0118זט10 ,57171 .1םו58 .4 מה .כ 05850 .2 ,5מו640 ,ץ0/681 מ006150/ .ץ81ץס1 1 1816קות6 1 51820816 116 ואו פחוות8זסץק .6 ,אא פרק 10: ספריית התבניות הסטנדרטיות | 285 פרק 11 מבני נתונים סדרתיים ב- 511 בפרק וה נלמד על מבני נתונים סדרתיים ב-.511. מבני נתוניס סדרתייס כולליס מערך דינמי, רשימה מקושרת ותור כפול. על מבני נתוניס אלה פועלים מרבית האלגוריתמיס של ,511, ואין צורך לשמור על סדר כלשהו בין האובייקטיס המוכלים בהם. מבני נתוניס סדרתיים מאפשרים להכניס לתוכם אובייקטיס בכל מקוס ולשמור על סדר הכנסתם. אובייקטיס שמוכנסיס בסדר מסויס מתאימיס לסדר הסריקה שלהם. אובייקט שהוכנס ראשון, יהיה ראשון כשמגדיריס איטרטור על מבני הנתונים. אובייקטיסם שהוכנסו מאוחר יותר, יופיעו מאוחר יותר בסדר האיטרציה. במבני נתוניס כאלה סדר ההכנסה קובע את סדר האיטרציה, ויש אפשרות לעבור על האובייקטיס במכולה לפי סדר כניסתם, או בניגוד לסדר הכניסה. סדר האיטרציה יכול להיות הפוך. אז עובריס מהאובייקט שבסוף המכולה לתחילתה, מאובייקט שהוכנס לסוף המכולה לאובייקט שהוכנס לתחילת המכולה. מכאן אנו למדים שיש סדר של אובייקטיס במכולה על פי סדר הכנסתס. | 11.1 | וקטור מבנה הנתוניס וקטור מאפשר גישה אקראית לאובייקטים שהוא מכיל. למבנה נתוניס זה יש גישה סדרתית, מאובייקט ראשון לבא אחריו בתור, ויש אפשרות לגישה שאינה סדרתית. כלומר, מבנה הנתונים תומך בגישה אקראית על ידי אינדקס, לכל אובייקט בווקטור. הווקטור, כמו רוב המכולות ב-,511, מכיל איטרטור המאפשר לסרוק את האובייקטים שנמצאים בו. מבנה הווקטור הגישה האקראית (800055 60₪1ם8?) הנתמכת על ידי מבנה נתוניס זה יעילה (ולכן גס נתמכת) כמו גישה רגילה שנעשית לכל מקוס במערך. מבנה הנתוניס עצמו מוגדר כמערך של אובייקטיס. המערך גדול בדרך כלל ממספר האובייקטים שהוא מכיל, מטעמי יעילות. ברגע נתון יש במערך מספר אובייקטים הנמוך מנפח המערך. פרק 11: מבני נתוניס סדרתיים ב-.511 287 הווקטור הוא דינמי, ובעת הצורך הוא גדָל כדי לאחסן מספר גדול יותר של אובייקטים. הווקטור מכיל שלושה אלמנטיס חשוביס: מצביע לתחילת אזור הזיכרון של הווקטור, מצביע לסופו ומצביע לאובייקט האחרון שנמצא במערך. כשיש צורך להכניס אובייקט נוסף למערך, נבנה אובייקט חדש בתחוס שאינו תפוס עדיין במערך. ץז ססות א א/ א/ 1 6 06 01 0 איור 11.1 מבנה הווקטור הווקטור תומך בפונקציות המאפשרות להכניס אובייקטים בסוף המערך, או בכל מקוס בו. פונקציות המכניסות אובייקט באמצע המערך, מעתיקות אובייקטים מהמקוס הנדרש לכיוון סוף המערך, כדי להכין מקוס לאובייקט החדש. על כן, פונקציות כאלו אינן יעילות. הפונקציה חיעילה ביותר היא זו המכניסה אובייקט בסוף אזור האובייקטים (986) ואינה מעתיקה אובייקטים. אובייקטיס המוכנסיס למערך אינס זקוקיס לבנאי ברירת המחדל. הסיבה לכך נעוצה בעובדה שהמערך אינו נבנה, מלכתחילה, כמערך של אובייקטים, אלא כזיכרון רגיל (זסות6ג או18). רק כשמכניסים אובייקט למערך, נבניסם בו האובייקטים. גישה זו יעילה יותר גס מהגישה שבח מגדיריס את הווקטור באופן הבא : 66801866 >01858 ?1< 760602 ] ;שב - 2 סמסם1 :טס [+ (8126)0 ,(822)0 :3 ()ע2ס%סבע [ ;[82 = 1]8126 שסם = עעה8 + (52 סם1)עס6פסבע ו ל הבנאי השני של המחלקה וקטור מקצה מערך של אובייקטים. עבור כל אובייקט במערך נקרא בנאי ברירת המחדל. בתחילה הווקטור ריק, ולכן בניית אובייקטיס מיותרת. בדרך כלל, קוד המשתמש במערך כזה מכניס אובייקטים למערך מייד לאחר בנייה, וכתוצאה מכך מתבצעת העתקה נוספת של האובייקט המוכנס למערך. על כן, מייד לאחר הכנסתו, מופעל אופרטור ההעתקה (900זסק0 עק00) של האובייקט. 8 ++-+6 ו-009 למתכנת המקצועי האיטרטור הווקטור מכיל איטרטור, ובמקרה זה האיטרטור הוא מצביע לסוג האלמנט המוכל בווקטור. דבר ה מאפשר גישה מהירה לאלמנטים בווקטור ללא כל בזבוז, בדומה למצביעים רגיליס בשפה. במילים אחרות, האיטרטור של מכולה זו הוא מצביע, ויש לו כל היתרונות והחסרונות של מצביעיס ב-0, או ב-++6. איטרטור של ווקטור הוא איטרטור לגישה אקראית (100900 800655 ת60ת13). הוא מאפשר לנוע קדימה או אחורה בווקטור, וגם גישה אקראית לאובייקטים לפי אינדקס. כל האלגוריתמיס הקיימים ב-,511 פועלים על איטרטור זה. למחלקה וקטור יש מספר סוגי איטרטורים. לכל אחד מהם פונקציונליות שונה, אבל כולס בנוייס על אותו רעיון. סוגי איטרטוריס אלה קיימיס גס עבור המחלקות האחרות עליהן נלמד בפרק שלפנינו. ההסבר תקף גםס למחלקות אחרות, ולא נחזור עליו שנית. איטרטוריס מסוג קבוע מאפשריס לסרוק מכולה נתונה, אך אינס מאפשריס לשנות את תכולתה. איטרטוריס כאלה שקולים למצביע לקבוע כגון: /17* עאַת0 0056 המצביע אינו מאפשר לשנות את התו שאליו הוא מצביע. איטרטוריס מסוג 166186 מאפשריס לסרוק את המכולה בסדר הפוך מסדר האיטרטור הרגיל. פעולת האופרטור 'י++" מדמה את האיטרציה לאחור במקוס קדימה. בדרך זו, מתחילה האיטרציה מסוף המכולה ונגמרת בתחילתו. כשמשתמשים באיטרטור הפוך לווקטור מקבליס אובייקט, ולא מצביע בסיסי, ולכן במקרה זה יורדת היעילות. מומלצ להשתמש באיטרטור הרגיל ולהפעיל את האופרטור '--', פונקציות חשובות בסעיף זה נסקור פונקציות חשובות של הווקטור, כאלה שהשימוש בהן רב. בהמשך, נראה שימוש בפונקציות אלה. החתימה (040/06זכ) של הפונקציות היא : 760602 )( ; ; ()ם691ע 16628602 ;()0ם6 16628602 ;(8081 7 8%6ת080%)00 בפטס בנסע ;(8081 7 008% ,05סק 6)16628%0%2ע562ת1 18בסט ; (008 62856)1₪628%02 1בסט ; ()806% ססס 7 הפונקציות המאפשרות איטרציה בווקטור הן הפונקציות ם681ס ו-626. הפונקציה ם1ג6ס מחזירה איטרטור לאובייקט הראשון שבווקטור, והפונקציה 626 מחזירה איטרטור לכתובת אחת לאחר סוף הווקטור. דבר זה נובע מכך שבשפת 6 מוגדרת כתובת אחת לאחר סוף המערך ככתובת חוקית, אך אין לבצע על התוכן שלה כל פעולות כלשהן, אלא רק להשוות. פרק 11: מבני נתוניס סדרתיים ב-.511 289 שתי הפונקציות מושסט ו-6מ6 מאפשרות לפתח אלגוריתמיס בדרך הבאה: <1606% 01858> 66801866 (0תם6 1662 ,8%82% 5)166% ב1סע | ] (6ת6 =! %ע58568) 16ותט 40 18 סהתח 60 ... // ו בנאי ברירת המחדל (00ס500מסס )661901) של המחלקה וקטור יוצר וקטור ריק שאינו מכיל אובייקטים. כדי להכניס אובייקטים לווקטור נעזריס במספר פונקציות שימושיות (נראה בהמשך). הכנסת אובייקטים לווקטור יכולה לגרוס להגדלתו. אס אין מספיק מקוס בווקטור, מכפילה המחלקה את אזור הזיכרון שלה. המחלקה מתחילה עם אזור זיכרון אפס, או קבוע מראש, ומכפילה את אזור הויכרון שבו מאוחסנים האובייקטיס. אלגוריתס ה מקטין את מספר הקצאות הזיכרון, ועקב כך את הזמן המבוזבו כתוצאה מכך. לעומת זאת, קיימת אפשרות לבזבוז גדול של זיכרון בהקצאה האחרונה. הפונקציה 886% תפש מכניסה אובייקט נוסף בסוף הווקטור. היא בונה אובייקט הוהה לאובייקט שהיא מקבלת בסוף הווקטור, תוך שימוש בבנאי ההעתקה של האובייקט. אס אין מספיק מקוס לאובייקט זה, מוכפל גודל הווקטור. הפונקציה +18867 מכניסה אובייקט במקוס נתון כלשהו לווקטור. גם במקרה זה ייתכן מצב בו יגדל הווקטור. בניגוד לפונקציה הקודמת, ייתכן מצב בו מעתיקה הפונקציה חלק מהאובייקטיס בווקטור כדי ליצור מקוס לאובייקט החדש. בדרך כלל, פונקציה זו צורכת יותר זמן מהקודמת. (8081 7 008% ,פ5סק 5626)166028%0%2םת1 בנ1בסט האיטרטור מסמן את המקוס להכנסת האובייקט, והערך המוכנס הוא הארגומנט השני של הפונקציה. הפונקציה 6+8%6 מאפשרת ביטול של אובייקט במקוס נתון (על ידי איטרטור). פונקציה זו יכולה לגרוס להעתקה של חלק מהאובייקטים בווקטור לכיוון תחילתו, כלומר, לכווץ את הווקטור. הפונקציה מפרקת את האובייקט האחרון במערך ומפעילה את המפרק של אובייקט זה. פונקציה אחרת המבטלת אובייקטים בווקטור היא 980% קסס. פונקציה ו מבטלת את האובייקט האחרון בווקטור. היא גם מפרקת את האובייקט האחרון על ידי הפעלת המפרק שלו. פונקציה וו אינה מעתיקה אובייקטים, ולכן היא יעילח יותר. לווקטור קייס אופרטור [] המחזיר ייחוס לאובייקט בווקטור. האופרטור אינו מבצע בדיקת חוקיות על האינדקס, ולכן שתי השגיאות הטיפוסיות הבאות עלולות להתרחש: > האינדקס המבוקש יכול להיות מחוצ לתחוס. * למרות שהאינדקס בתחוס, המקוס הנוכתי יכול להיות זיכרון בסיסי, ולא אובייקט. 0 ++-+6 ו-009 למתכנת המקצועי השגיאה השנייה נובעת מכך שמוקצה ויכרון בסיסי (ולא מערך של אובייקטיס) והאובייקטיס נבנים רק כשיש צורך. מוקצה זיכרון הכפול מגודלו הקודס בפעולת 0% תפטק, ורק אובייקט אחד הוכנס לתוכו. שאר האובייקטיס רק מציינים מקוס ואינס אובייקט. לאובייקטים פשוטים שאין להס פונקציות וירטואליות, וגס למחלקות הבסיסיות שלהן אין פונקציות וירטואליות, אין בעיה. לאובייקטיס המכילים פונקציות וירטואליות ההתנהגות אינה מוגדרת. | 11.2 | רשימה כפולה - +5ו! המחלקה רשימה (118) היא רשימה מעגלית כפולה, שבכל צומת (איבר) שלה נשמר נתוו מתאיס. הרשימה אינה שומרת את הצמתיס בצורה רציפה בזיכרון, ולכן הכנסות וביטוליס של אובייקטיס באמצע הרשימה אינס גורמיס להעתקת אובייקטים. כמו לכל המכולות, גם בספרייה הסטנדרטית יש איטרטור. האיטרטור מאפשר מעבר קדימה, או אחורה על הרשימה. מבנה הרשימה הרשימה מכילה צומת אחד המשמש כמצביע לראש הרשימה ולסופה. הרשימה היא מעגלית והמבנה שלה דומה למבנה הרשימה שלמדנו בפרקיס קודמים בספר וה. כל צומת ברשימה מכיל מצביע לפנים ולאחור. בנוסף, מתזיק כל צומת ברשימה אובייקט הזהה בסוגו לפרמטר התבנית, כלומר, סוג האובייקטיס שברשימה. 0 איוד 11.2 מבנה הרשימה הרשימה מאפשרת הכנסת אובייקטיס משני צידי הרשימה, וגסם הוצאתס משני צידי הרשימה. אפשר לקבל אותו אפקט מווקטור על ידי שימוש בפונקציה 67856 עס איטרטור לתחילת הווקטור. אך במקרה של וקטור, תהיה הפעולה בזבזנית מאוד ובלתי יעילה. לכן, לא סיפקו מתכנני הספרייה פונקציונליות ו במחלקה וקטור. האיטרטור איטרטור הרשימה הוא מחלקה מקוננת בתוך הרשימה. הוא מאפשר סריקת הרשימה בצורה דו-כיוונית, ולכן הוא מטיפוס איטרטור דו-כיווני (10079)07 [01011000008). האיטרטור תומך באופרטוריס "++" ואופרטוריסם '--"י שמקדמיס את האיטרציה לפנים ולאחור, בהתאמה. האיטרטור אינו תומך בגישה אקראית עס האופרטור []. פרק 11: מבני נתוניס סדרתיים ב-. 511‏ 291 כדי לאפשר לאלגוריתמים רבים לפעול על הרשימה באמצעות איטרטורים, תומך האיטרטור באופרטורים הבאים : . מאפשר לקבל את הייחוס לאובייקט הנוכחי שעליו מצביע האיטרטור. == מאפשר להשוות בין איטרטוריס זהים, אס הס מצביעים לאותו צומת. =! אופרטור השוני מחזיר ערך אמת אם האיטרטוריס מצביעים לצמתים שונים. אופרטוריס אלה מאפשריס להתייחס לאיטרטור כאל מצביע בסיסי של השפה, ולכן האלגוריתמיס הגנריס של הספרייה יכוליס לפעול על רשימות. לעומת האיטרטור של הווקטור, יעילות איטרטור וה נמוכה יותר. פונקציות שימושיות בסעיף זה נסקור פונקציות שימושיות של הספרייה, אך יש פונקציות נוספות שאינן מתוארות כאן. הקורא מופנה לספרות המקור של הספרייה, כדי לקבל את המידע על כל הפונקציות. הפונקציות שנסקור בפרק זה: "> > 10070107 0010)(( ;()0ם0 11079107 > ;([6/9 1 1102100081 תפטק 016 > ;([80%4 1 81ת080%)60 תפטק 016 > > 016 125011)11078101 005, 008% 1 8/8[(; 6 010 /078580)11070101 008(; ((0ת10 07 ך > *> 707 080%)(; ()16תט 010 > % 010 80110(; בנאי ברירת המחדל מגדיר רשימה ריקה, שבה יש צומת אחד בלבד שמצביע אל עצמו. צומת ה הוא שורש הרשימה (1000) והוא קיים לכל אורך חיי הרשימה. הפונקציות מושסט ו-6מ6 מחזירות איטרטוריס לתחילת וסוף הרשימה, בהתאמה. כשהאיטרטור לסוף הרשימה מצביע, למעשה, לצומת הראשון של הרשימה המשמשת כשורש הרשימה. שתי פונקציות אלו מאפשרות לאלגוריתמיס סדרתיים לפעול על הרשימה. נתבונן לדוגמה באלגוריתס הבא : <ץ286 01888 ,1002 01855> 66801866 (%* 7צ86 ,0ם6 1062 ,86826 0)1662ם51 1668 (% =! 6ע8582* 66 0ם6 =! 56826) 16נ1תט ; 5%82%++ %2 תעש60ע 2 ++6 ו-009 למתכנת המקצועי 2 <םס6ת115%>1 7 ;(1 ,()0ם11.86 ,()ם681ס.0)11ם11 = 1 ע6<::166028%0%ת1156>1 + (()8ם11.6 =! 1) 1% 1008 ... // ו הפונקציות )תס גפטק ו-080% גפטק מאפשרות הכנסת אובייקטיס בתחילת הרשימה ובסופה. הפונקציה 1561 מוסיפה אובייקט לרשימה במקוס הנתון על ידי האיטרטור. משך הזמן לביצוע פונקציות אלו והה. הפונקציות אינן צריכות להעתיק אובייקטים של הרשימה, גס כשמכניסיס אובייקטיס באמצע. הפונקציות 1ת0ז1 קסק ו-580% קסק מאפשרות להוציא אובייקטיס מתחילת הרשימה ומסופה, בהתאמה. הפונקציה 61985 מאפשרת להוציא אובייקט ממקוס נתון כלשהו ברשימה. המקוס נתון על ידי איטרטור. פונקציות אלו אינן צריכות לצופף את הרשימה, ולכן זמן פעולתן אינו תלוי באורך הרשימה. הפונקציה 801 ממיינת את הרשימה. ב-.511 יש פונקציית מיון כללית על פי אלגוריתס ספ אסנטף, אך הפונקציה דורשת גישה אקראית לאלמנטים של המכולה שעליה היא פועלת. מכיון שגישה אקראית כזו לא נתמכת על ידי הרשימה, נכתבה פונקציית מיון המתאימה לרשימה. יש להגדיר אופרטור > ו-'*==" עבור האובייקטים של הרשימה, מכיון שלרשימה יש פונקציית מיון. כזכור, עבור וקטור לא נזקקנו לאופרטוריס אלה. הפונקציה 6טשותט מבטלת מופעים כפולים רציפיס של אותו אובייקט ברשימה. כלומר, אם יש שני אובייקטיס או יותר, הזהים ועוקבים ברשימה, נקבל לאחר הפעלת פונקציה זו אובייקט יחיד. בדרך כלל, פונקציה זו מופעלת לאחר מיון הרשימה. הפעלת הפונקציה 6טףופט לאחר מיון מבטלת אובייקטים כפולים ברשימה. | 11.3 | תור כפול המחלקה 6666 היא תור כפול, אשר מאפשר הכנסת אובייקטים משני הקצוות. גס רשימה כפולה יכולה לשמש כתור כפול, אך ב-.511 התור הכפול אינו מיושס באמצעות רשימה, אלא בעזרת מערך של מצביעים. כמו לכל מכולה אחרת, גס לתור הכפול יש איטרטור ב-,511. מבנה התור הכפול התור הכפול מיושס באמצעות מערך מצביעיס אל מערכיסם של אובייקטים. סידור וה מאפשר הכנסת אובייקטים לתחילת התור, או לסופו, ללא צורך בהעתקות. כשצריך להוסיף אובייקט בהתחלה ואין מקום, מוסיפים בלוק של אובייקטים ומוסיפים מצביע כזה בתחילת המפה שמצביעה לבלוקיס של אובייקטיםס. פרק 11: מבני נתוניס סדרתיים ב-.511 293 8 קגות איוד 11.3 מבנה התור הכפול איור 11.3 מתאר תור כפול עס שני בלוקיס מוקציםס. במפה יש מצביעים לשני הבלוקיס. כל בלוק הוא בעל גודל קבוע. כשיוצרים אובייקט כזה, אין מפה ואין בלוקיס (מערכים) של אובייקטיס. כשמנסיס להכניס אובייקט ראשון, מוקצה הבלוק הראשון והמפה מאותחלת, כשהמצביעיס של התחלת המפה וסופה מאותחלים לאמצע הבלוק. מצביעים אלה הס איטרטוריסם של מחלקה זו. האיטרטורים מאותחלים להצביע לאמצע הבלוק הראשון. בצורה זו אפשר להכניס אובייקטים לשני צידי התור ללא צורך בהעתקות. כשמנסיס להכניס אובייקט לסוף תור (או לתחילתו) והאיטרטור מצביע לבלוק האחרון של המפה שבסוף הבלוק האחרון, יש צורך להקצות בלוק חדש של אובייקטים. יש צורך להגדיל את המפה, כדי שתוכל לקבל את המצביע לבלוק זה. הגדלת המפה מתבצעת על ידי הוספת מצביע חדש. מחיר הוספת מצביע חדש נמוך. דבר זה נובע מכך שבדרך כלל יש מספיק מקוס למצביעים נוספים במפה. רק כשאין מספיק מקום במפה, יש להעתיק את מצביעי המפה לאזור זיכרון חדש, וגדול יותר. ברוב המקרים גלישה שכזו לא תהיה ולכן לא תהיינה העתקות כלשהן. כשמנסים להכניס אובייקט לאמצע תור יש צורך בהעתקה, מכיון שבלוקים הס מערכים רציפים של אובייקטים. התור הכפול יעיל במיוחד כשמכניסים אובייקטים משני קצותיו, והוא יעיל יותר מרשימה, כי אין צורך לטפל במצביעים. לעומת זאת, הכנסת אובייקטיס באמצע התור אינה יעילה. הרשימה הכפולה יעילה יותר. האיטרטור האיטרטור בהקשר וה אינו מצביע, אס כי יעילותו מתקרבת ליעילות מצביעים בסיסיים בשפה. האיטרטור הוא מחלקה פנימית במחלקה המייצגת תור כפול. האיטרטור הזה הוא מסוג גישה אקראית, ולכן הוא תומך בהשוואה בין מצביעים (>), בגישה אקראית, חיבור ותוספת. האיטרטור מספק אופרטורים (כגון "=+", "*, '==", %'++ ,'--") ובכך הוא מתנהג כמו מצביע רגיל ב-++6. 4 +-6 ו-009 למתכנת המקצועי ברוב המקרים, נעשה קידוס האיטרטור באמצע בלוק ולכן, פרט להגדלת מצביע, לא נעשה דבר. במקרים אלה הפעולה יעילה כמעט כמו הגדלת מצביע בסיסי של השפה. עס ואת, האיטרטור נמצא בסוף בלוק ויש לקדמו לבלוק הבא. קטע הקוד הבא לקות מהספרייה ומדגיס את אופן קידוס האיטרטור. ] ()++ע62800ק0 166286028 ) (188% == מ6ת6עעט0ס++) 11 ; (006ם++)* = 11286 2 = סת6עפגטס 2 ₪ 520ט + 21286 = 1886 ] ;18ם* תעט6%ת ו כשהאיטרטור מגיע אל המצביע האחרון בבלוק, הוא מאותחל לכניסה הבאה במפת הבלוקיס. הכניסה הנוכחית במפת הבלוקיס מיוצגת על ידי 66סם. לאחר מכן, מעודכן המצביע לסוף הבלוק לפי גודל הבלוק. ברוב המקריס פעולת קידוס (או נסיגה) של האיטרטור, יעילה כמעט כמו ביצוע הפעולות המקבילות על מצביעיס של 0 או ++6. מבנה נתונים - דוגמה את מבני הנתוניס נלמד בעזרת דוגמה העוסקת ביומן טלפוניס. דוגמה זו תשמש אותנו בכל מחלקות .511 שנלמד בפרק זה. במקוס אחד (שנראה בהמשך) נציין את סוג המכולה שנשתמש בה. טכניקה זו מאפשרת לשנות את סוג המכולה ללא שינוי התוכנה המשתמשת בה. מבנה היומן יומן הטלפוניס מורכב ממספר גדול של כניסות. לכל כניסה ביומן יש שס אדס כלשהו ומספר הטלפון שלו. היומן נרשס לקובצ 45011 ונקרא מתוכו, בעת הצורך. כל רשומה ביומו היא שורה בקוב>. רשומה ביומן מיוצגת על ידי אובייקט מהמחלקה ות ץאוס. <ת.06ם5621> 010₪6ם1+ <(.0ת15%768> 61086ת1+ ) צְע>םמץע18כת 01888 :טס ;ן 12 = ם16 6םתסםק ,32 = ם16 פתהת + תגותס :עס ; [ת16 6תת] תת כַַַם0ס ; [ם16 6תסםס] פמסםס 85ם0 :טס פרק 11: מבני נתוניס סדרתיים ב-.511 295 () ץע>תמץע18כ 2 = [0]ָפתהם ) [ ;0 = [6]0םסםתס (תם* עאתס 6פתסס)פתהםת 866 בנ1נסט ; (ת16 סתהת ,תם ,סתהת) ץקסת562 (מת) 15 1 [ ;0 = [0]ָפתאם 156 (מסק* 0282 8%ם6)00םמסםתק 58566 בנסע ; (ת16 6תסתס ,םק ,6םסתס) ץקסת562 (םס) 15 1 [ ;0 = [6]0מסמס 1586 // 18שטשטטת 665 // // % (()פתהם 866* 0282 0086 [ ;סתהת מעטס6עץ + 7% ()6מסם 666₪* ע8ת0 0086 [ ;6תסםתק םע2600 + ;ו בנאי הרשומה ביומן מאפס את השדות שם וטלפון, ומספק פונקציות השמה לשס ולמספר הטלפון ופונקציות גישה לשדות אלה. הקוד של מחלקות אלו ושל הפונקציות הגנריות של היומן נמצא בקבציס 697.60 ו-1.צְז01. פונקציות עזר ליומן יש מספר פונקציות תבנית המשמשות לקריאה וכתיבה בקבצים. פונקציות אלו קוראות, או כותבות מכולה שבה אובייקטים מסוג עזוםמץזגוק. כדי לפלוט, או לקלוט אובייקט מסוג עשתתץזגוע מוגדריס האופרטורים "<<" ו-">>. האופרטור ">>" מקבל ייחוס לאובייקט מסוג 50642ס0, ומחזיר ייחוס לאובייקט כזה. מכיון שהאופרטור מקבל ייחוס לאובייקט מסוג 5₪682ס, הוא יכול לפעול על כל אובייקט שיורש מ-3949ס. האופרטור ">>:י מקבל ייחוס לאובייקט מסוג עשמםץזנגת, שאותו הוא מדפיס על זרס הפלט הנתון לו. באופן דומה מוגדר האופרטור י'י<<יי עבור זרמי קלט. ; (6060 שץעףתמץ182ע 0056 ,805 ת(ת602628602>>)05%208 ת(05%6208 ; (606 צע%תמץל18כת ,618 ת6020628%0%2<<)15%6268 ת185%6268 פונקציית התבנית 2694 מאפשרת לקרוא קוב המכיל כניסות של יומן הטלפוניס לתוך מכולה כלשהו. המכולה הנתון לפונקציה הוא פרמטר של פונקציית התבנית 108%. פונקציה ו מאפשרת לקרוא את הקוב לכל מכולה, כשהפונקציה מניחה שהמכולה היא בעלת פונקציה 980% 1פטק, המוסיפה אובייקט בסופה. לצורך קריאת אובייקט, משתמשת הפונקציה באופרטור "<<יי. הפונקציה מחזירה את מספר האובייקטיס שנקראו מהקובצ. 6 ++6 ו-009 למתכנת המקצועי עססתטת 6ם₪ פםתעט60ע 8₪ם8 62םת681ת00 מסט61 8 60ם1 2686 // 0016008 01 // <%ע6ת%81ת00 01855> 18%66קת66 (1116* 02829 8%ת00 ,80 ע6ת%81ת26₪80)060 6ם1 2 = סתטסס 6ם1 ; (116+)ם1 ת155%268 ]1 (ם1) 116תט 67 צְע6ממצפה1כת 67 << ת1 ; (066) 086% מפגוק. 0 ;%תו00++ ו ;%מטסס תעגוס6עץ ו פונקציית התבנית עְוַקְע3 מקבלת שני פרמטרי תבנית. הראשון, מכולה (שמכילה אובייקטים) והשני, פונקציה שיש להפעיל על כל האובייקטיס במכולה. הפונקציה סורקת את המכולה ומפעילה את הפונקציה 1 על כל אחד מהאובייקטים. הפונקציה מקבלת ייחוס למכולה, ולכן היא אינה פועלת עבור מערכיס בסיסיים של השפה. אילו רצינו להפעיל את הפונקציה עבור מערכיס בסיסיים, היינו צריכיס לקבל תחוס (מ81סס, 6םס). <סתות 01855 ,062ם681ת00 01855> 18%66קת66 (?1 סמות ,80 6%םת%81ם600)ץ1סק8 6ם1 ן ;(()86ם0)60.8ם6 ,(()ם601כ.8%82%)0 ע62::1662860ם681ת00 72 = סתטסס 6ם1 זָ (0ת6 =! %6ע58%68) 16נתט ; %תגו00ס++ ; (++1)*5%82% ] ;%מטסס תעגוס6ץ ו כדי להדפיס אובייקטיס לפלט, נשלב מספר אובייקטים ואובייקטי פונקציות. הראשון שבהס *6)מוזק, הוא אובייקט-פונקציה. כלומר, זהו אובייקט המתפקד כפונקציה, מכיל ייחוס לזרס פלט ומדפיס לזרס הנתון אובייקטיס הניתניס לאופרטור הפונקציה שלו. ] עססתנ1עס 06גע56 08%2608( 605; [+ (05)0 : (80 ת08%208)ע62סםת1עס (ט8 ץע%םממתץע18כע ספתסס) ()628602ק0 ב18בסט 5 ) ;ו פרק 11: מבני נתוניס סדרתיים ב-.511 297 כדי לכתוב אובייקט מסוג עומתץזגוע נשתמש בשתי פונקציות התבנית 1866זש. הראשונה מביניהן מקבלת מכולה שבה אובייקטים להדפסה ואובייקט מסוג זרס פלט (טס). הפונקציה מגדירה אובייקט פונקציה +ונ, המתייחס לזרס הפלט. המכולה מודפסת בעזרת הפונקציה ע1טק8. פונקציית ההדפסה השנייה מקבלת מכולה שבה אובייקטים להדפסה ושם של קובצ. הפונקציה יוצרת אובייקט )טס, מסוג זרם פלט. בנוסף, מגדירה הפונקציה אובייקט-פונקציה ומשתמשת בפונקציה ע1ְַע3 כדי להדפיס את המכולה הנתון לה. שתי פונקציות ההדפסה 116עאי יכולות להדפיס מכולה המכיל אובייקטיס שוניסם, לאו דווקא שמת עזגוכ, כל עוד יש לאובייקטיס אלה אופרטור הדפסה מתאים (>>6). הטכניקה המודגמת כאן היא טכניקה גנרית, ולכן חשוב להכיר אותה, כדי לנצל את יכולתה . <%ע6ת%81ת00 01855> 661866 (600% ת09%208 ,60 ע6ם681ת1%8)00עח %6ם1 ו 72 = סתטסס 6ם1 ] (סטס) 15 ; (שטס)26ס עפסתנעמעס ;(סעק ,0)ץ1סק8 = סתטסס ] ;%מטסס תעגוס6ץ ] 6 הִסש6ט61 8 60ם1 ע6ת581ת0ס0 מתסט61 8 166עח // <%ע06ם%81ת00 01855> 661866 (1116* 082 008% ,860 ע6ם%81ם16)00עש 6ם1 ; (6)5116טס מת058%208 + (סגמס) 15 ; (סמוס)26ס עפסתנגעמעס ; (סעס ,0)ץ01ק8 תעטססץ 2 תעגו6%ת ו הפונקציה 184 היא פונקציה גנרית המוצאת את האובייקט הראשון בתחוס נתון על פי קריטריון מסויס. התחום נתון על ידי שני איטרטוריס (או מצביעים) והקריטריון נתון על ידי אובייקט-פונקציה. אס קייס אובייקט בתחוס הנתון לפונקציה 4חו8, שאליו אובייקט הפונקציה מחזיר ערך אמת (שונה מאפס) יוחזר איטרטור (או מצביע) לאובייקט זה, אחרת יוחזר איטרטור לסוף התחוס. 68 0 ע6סת01ק 8 5פםתע600? סת8 עסת1ה8פתסס 8 5682095 8מם1+ // סת 1% .021606 60068660ע2 66 6עפמח ם1610פסק 16₪67860% // 868 01 6ם6 66 888 פםס 15658805 ת8 פתע6602ע2 6תגטס+ // ש6ת1הסתסס // 8 ++-+6 ו-009 למתכנת המקצועי <סתגו?ת 01858 ,10628602 01858> | 66801866 (?5 סתמטע ,0ת6 ע%ע18628060 ,50826 0)1₪628%0%ם51 1662860% (0ת6 =! %6ע8%68) 16נתט ((1)*8%82%) 1% %2 מעפגס6ץ 1-6 ; 85%82%++ %2 מםש600ע ו האופרטוריס של הקלט והפלט משתמשים בפונקציות הציבוריות של ץזומתץזגאוע כדי לקרוא, או לכתוב, אובייקט מסוג זה לוּרס קלט או פלט נתון. (606 ץע6םמץע18כת 00256 ,808 ת(602628%602>>)085%208 ת(05%6268 ו ()סתאת 66.06% >> 08 םע2600 2 >> ()6םסםס 66.06% >> "6ם6" >> (606 צע%תמץ182כע ,618 ת(ת60628%0%<<)15%6268 ת1856268 זָ ; [ת16 סתהת: נ:ץע6םתמץל18כ]+גוס מַַַם60 ;טס << 159 ; (5גוס) סת8ת 06.56% ?וס << ₪ ; (5גוס) סמסתש 06.56% 7 תעג66ץ ו אופרטור הקלט מסובך יותר, משום שעליו לקרוא את השס ומספר הטלפון לתוך חוצציס מקומיים, ורק אז להעבירם לכניסה ביומן. התוכנית הראשית התוכנית הראשית (ם60.+ עֶזג6:9) מכילה את פונקציות הניהול ואת ממשק המשתמש שמקבל פקודות מהמשתמש בתוכנית. כדי לכלול את הקבציס המתאימים, עלינו לכלול את הקבצים 6001ט, 1186 (-660₪6 שנמצאיס בספרייה ,511. התוכנית כוללת את קבציס האלה משום שהיא זקוקה לשלושתס. "מ.ץ132ת" 010066ם1 "מ.ע0ס%ס6ט5%61" 010₪6ם1 "ת.551118%" 010₪6ם1 "ם.56186006" 601006ת1 <ת(.ת5%2608+> 010066ם1 פרק 11: מבני נתוניס סדרתיים ב-.511 299 המשתמש יכול להפעיל פקודות הוספה או ביטול של רשומה ביומן, עדכון רשומה, קריאה או כתיבה של קוב המכיל את יומן הטלפונים. הוא יכול להציג את היומן הנוכתי וגס לצאת מהתוכנית. אפשרויות אלו מפורטות בפקודה נתטחס הבאת: ,סתס צע%ת6 6866קט ,0ת0 צעפת6 6טסת6ע ,תס צְ62ת6 800 + תטתס ;[ סתס 16א6 ,0ת0ס 415850187 ,תס 5116 6ס1נעח ,תס 1116 2086 כדי להגדיר את סוג המכולה (602141869) שבו משתמשת התוכנית במקוס אחד בלבד, נשתמש ב- 060661ק. אס נרצה לשנות את סוג המכולה עלינו להכניס להערה שתי שורות מהשורות הבאות, ולהוציא מההערה את המכולה המבוקש. אין צורך לתקן במקומות אחריס משוס שבכל מקוס אחר אנו משתמשים בסוג ז6ם91תסס ץ0181. ;צסת1הס6תסס 6182 <צע6םתמץ60%02>2182ט 6865ס67// ;2 [ש018 <ץש6םתץ182כ>115%6 6865ס6// ;עסת1הסתסס צץ4182 <ץ%62םתמץ182כ>6ו360 6766461 האופרטורים ‏ ">" ו-"==" משמשים להגדרת יחס סדר של אובייקטים מסוג ץזומתץווגת, כדי לאפשר מיון מכולה שבה אובייקטים מסוג זה. פונקציית המיון ו-סטותט שייכות למחלקה 1:8%, ולכן הן אינן אלגוריתמים גנריים ויש לספק להן את אופרטורי הסדר האלה : 68 פתס1ססתט1 115% שםם 10% 6ע8 860%9ע62ק0ס שסתנשס011ס+ 6םםס // אש 0ם שגשנ1תט םתה // ₪ (802 ץע%םמתץע18ת 5%ת00 ,801 ץעפםתטץע18כת 628602>6)0028%6קס 6ם1 ;(0 > (()6תהת 642.66 ,()פתהםת 41.066) ק8ת8620) םעגו66ת2 ] (802 ץע%םתץע18כתע 5%ם00 ,601 צץע6תמץע18תע 628602==)0028%6קס %6ם1 ָ ;(0 == (()6תהת 642.66 ,()פתםת 41.066) קת8620) םעג0ו266 ] האובייקט ס6ת₪ [60084 הוא אובייקט-פונקציה (09[60 תסטסתט!) המכיל :יחוס לאובייקט מסוג עםתץגו1ע. אובייקט הפונקציה מגדיר את אופרטור הפונקציה ומחזיר ערך אמת כשהוא מקבל כניסה ביומן, שהיא בעלת שס והה לשם של הייחוס 6 שמכיל אובייקט הפונקציה. כך אפשר להשוות אובייקט כלשהו לאובייקט שאליו מתייחס אובייקט הפונקציה. אובייקט וה משמש לאלגוריתמים כגון 84 שעובריס על תחוס ומוצאיס מופע של אובייקט בתוכו. ]1 סתטת 60081 560006 67 שע6םתמץע18ת 6פ5תסס [+ (86)0 : (60 צשְ62םתץ182ת 8%6ם6)00םט1 0081 (680 ץע%ם8ץע18כע 6פתסס) ()628%602ק0ס 6ם1 [ ;(0 == (()פתהם 4.066 ,()סתהםת 46.06%6) קת8620) םע2660 ] 0 ++6 ו-009 למתכנת המקצועי הפונקציה ומסג 618018 מציגה למשתמש תפריט שמכיל את אוסף הפקודות הניתנות לביצוע. הפונקציה מקבלת פקודה מהמשתמש ומחזירה את מספר הפקודה שבחר. התפריט מוצג על המסך (לא בחלונות) כשלכל אפשרות בתפריט יש מספר. ()ותסת ץ815018 6ת1 ָ ;תס 16א6% = 268 סת1 ;"תץ?%ם6 שסם 8 800 (" >> תס שְעסת6 800 >> סגוסס ;"תץע5ם6 ם8 6ט00סמ6ע (" >> ת0 צְע6ם6 6טסמס6ע >> ס6גוסס ;"תץע5ם6 םת8 0866ק0 (" >> תס צְע6ם6 0866קט >> ס6גוסס ;"ת5116 8 מסע+ 26806 (" >> תס 5116 2680 >> סגוסס ;"ת116 8 60ם1 1%6עש (" >> 0מ0 5116 166עח >> סגוסס ;"מץ018% סתסעעטס 6ם6₪ צ018018 (" >> 6ת0 0150187 >> סוסס ;"תת8עפָסעק 1208 16א6 (" >> 6ת0 16א6% >> ס6גו00 ;" :עס6סת6" >> סגוסס 7 << םת01 ;01 >> סגוסס 682 מעו66ע ו הפונקציה תס 806 מוסיפה כניסה ליומן הטלפוניס. הפונקציה מבקשת מהמשתמש להכניס את פרטי הכניסה. היא משתמשת באובייקט מסוג עשמתץזגוע ובאופרטור 'י<<יי כדי להכניס את המידע לאובייקט. לבסוף, היא מוסיפה את האובייקט למכולה הנתונה לה. (6800 ע6ת%81ת60 צ6182) צץע62ת6 800 בנסעט זָ ;06 צשעפ6תמץהנכ ;":0658115 662םת6" >> סגוסס 6 << ת01ס ; (06) 080% םפטק.06 12 >> 6טגט0ס0 ] הפונקציה 66 16096 מאפשרת למחוק אובייקט מיומן הטלפונים. כמו בפונקציה הקודמת, גם היא מגדירה אובייקט מסוג צשמפץזאוע וקוראת לתוכו את פרטי האובייקט המיועד לביטול. לאחר מכן, היא מגדירה אובייקט-פונקציה מסוג סמ 6081 ומוצאת את מיקוס האובייקט המבוקש בעזרת הפונקציה 856. אס אכן נמצא אובייקט כזה במכולה, הוא מבוטל ממנה בעזרת הפונקציה 67886. הפונקציה 6 של המכולה מקבלת איטרטור למקוס שצריך לבטל. (0ס80 62ת%81ת00 צ0182) ץע6ת6 6טסתסת בנ1סט ז ;66 שְע6מפצעהנ1נכת ;":06%8118 ע66%ת8" >> 0006 ;6 << ם01 פרק 11: מבני נתוניס סדרתיים ב-. 511‏ 301 ; (66)06 סמות 00081 , ()ם0)00.0601ת51 = 058 62::166028602ת681ם00 04182 ; (60 ,()0ת00.8 (()0ם00.6 =! 058ק) 15 00 .62886 )008( ; 1-6 ; "סתטס5 ססםת" >> 0006 ;601 >> 0006 ו הפונקציה 600 6816קט פועלת בצורה דומה לפונקציה עת6 6טסומ6ת. הפרטיס החדשים של האובייקט המבוקש נקלטיס לאובייקט 66ב מהמשתמש. במקרה זה, אס נמצא האובייקט המבוקש, הוא מעודכן בעזרת אופרטור ההשמה של האובייקט 66 לאובייקט במכולה. הפונקציה משתמשת באופרטור ההשמה של האובייקט ץטתי ץזהוס, כדי לעדכן את האובייקט במכולה. (0ס60 62ת681ת00 צץ0182)ץע62ת6 6866ק0 בנסט ָ ;06 צעפ6תמלפהנכ ;":0658115 662ם6" >> סגוסס 62 << ת01 , () ם0)60.0691ת51 = 1 ע62::1%02860ת681תסס 04182 ; ( (66) סט 81ג600, ()6ם6. 06 (()0ם80.6 =! 1) +15 ;06 = 1* ו ; "סתטס+ ססת" >> סגוסס 12 >> 0006 ] הפונקציה 1116 1686 מקבלת מכולה שיש לקרוא לתוכה אובייקטיס. את שס הקובצ היא מבקשת מהמשתמש. הפונקציה מבטלת את כל האובייקטיס במכולה, ואחר כך קוראת לפונקציה 16946 כדי לקרוא את הקוב ולמלא את המכולה. ביטול האובייקטיס נעשה בעזרת הפונקציה 62886. בגירסה השנייה של פונקציה זו (61986) היא מקבלת תחוס במכולה המיועד למחיקה. לכן, מועבר לפונקציה התחוס של כל המכולה. (800 ע6ת681ת00 צע1116)018 20806 בנסט ;[128]+טס 08% ;":סתהת 1116 ע66ת8" >> 0006 ;טס << םמ01 12 >> סטס0 ;(()0ם30.6 ,()ם601כ.30.62886)00 ; (5גוס ‏ -,2080)006 2 ++0 ו-009 למתכנת המקצועי הפונקציה 116 6 מקבלת מכולה של יומן ומדפיסה לקוב את האובייקטיס שנמצאיס בה. היא מבקשת את שס הקוב מהמשתמש ומכניסה אותו לחוצצ מקומי. הפונקציה משתמשת בפונקציה 6ווזא כדי לכתוב לקובצ את המכולה הנתון. (0ס80 ע6ם1ה6תסס צ1116)0182 6ס1עח בנסע ;[1]128גוס עַַם0 ;":סתהת 1116 ע66%ת8" >> 0006 ;+טס << םמ01 0006 >> 12 ; (5גוס ‏ ,₪6)00בעשט ] הפונקציה 180189 מציגה לפלט הסטנדרטי את האובייקטיס שבמכולה יומן. היא משתמשת באופרטור 'י>>יי הפועל על כניסה ביומן ובורס הפלט כדי להדפיס את היומן לפלט הסטנדרטי. (600 ע6ת681םת0ס0ס צץ0182)ץ415018 בנסע ,()ם60.0601 = 80826 62::166028602ת%81ם00 4182 ; ()0ם00.6 = 6םת6 (0ם6 =! 5682%6) 116תט 2++%ע8082* >> 0006 ] הפונקציה הראשית של הדוגמה מגדירה את המכולה שבה אובייקטיסם מסוג ץותתץוגת. היא מבצעת לולאה כל עוד אינה מקבלת מהפונקציה טמסות 81801 ערך השונה מ-0₪6 %א6. על פי הערך המותזר מתבצעת הפונקציה הדרושה מתוך אפשרויות 0886. ()תנאת %ם1 ו ;תס 6ם1 ;ץ0182 עסת81סתסס 04182 ] (6ת0 816א6 =! (()גמתפת 018018 = 6תס)) 16ותשט 1 (0תס) 51602 :תס צְע6ת6 800 08586 ; (ץצ0182) ץ%2ם6 886 ;268% :תס שְ62ת6 6טסתסע 0886 ; (צ4182) צץ%62ת6 6טסת0ת2 ;268% :תס צע6ת6 6866קט 0856 ; (ץ0182) ץ%2ת6 68%6ס0 ;268% :תס 5116 2680 0886 פרק 11: מבני נתוניס סדרתיים ב-.511 303 ; (צע018) 1116 26806 ;68%ע2ס :תס 5116 166ע₪ 0886 ; (צ5116)0182 6ס6נ1עש ;268% :תס 0180187 0886 ; (צ0182) ץ15018 ;68%תס :מס 6%16 0886 :ה ;68%עס ו ;0 ת6%0%ע תכנות גנרי 7 קידמה מאוד את נושא התכנות הגנרי. בתכנות גנרי (8מוותנת8זפ סז 562070) מוסיפים פונקציות מופשטות המטפלות במספר רב של מבני נתונים, ללא כל ידיעה מראש על סוג מבני הנתוניס. היתרון בכך הוא שאין צורך לכתוב שוב את אותה פונקציה עבור מבנה נתוניס מסויס, או אחר. לדוגמה, פונקציה כזו היא 8₪6. הפונקציה מקבלת תחום שעליו היא פועלת. תחוס זה מאופייו על ידי שני איטרטוריס המתנהגים כמצביעים. הס מאפשרים לסרוק את התחוס ולקבל בעזרת האופרטור 'י*י' את הערך הנוכחי של האובייקט המוצבע על ידי האיטרטור. בצורה דומה ניתן להגדיר את הפונקציות ע8001 ו-1186או. הפונקציה ץ1קק8 06110מ86 מקבלת תחוס שעליו היא פועלת. התחוס יכול להיות נתון על ידי מצביעיסם בסיסיים של השפה, או על ידי איטרטוריס התומכים במספר פעולות בסיסיות. הפעולות הבסיסיות יכולת לקדס את האיטרטור על ידי האופרטור "++", או לקבל את תוכנו של האיטרטור על ידי האופרטור **יי. הדרישה האחרונה מהאיטרטור היא יכולת ההשוואה בין איטרטורים. הפונקציה מקבלת פרמטר של תבנית שיכול להיות מצביע לפונקציה, או אובייקט-פונקציה (600[ט0-מסגסתט1). הפונקציה מפעילה את האחרון (הפונקציה, או אובייקט הפונקציה) על התחוס הנתון לה. תס פאעסח מתס1תח תס1ססםתט? צץ1שק8 6210ם86 8 198 סתנאס011ס+ 6םס // 8 50 6תטסס ססם 18 ם0ס061םתט1 6ם5 6ע676+0%ם1 .86םת28 תסט1ף 8 // 6 .8228 ם1161טק ++0 8 תס אעפסח 8180 םת08 67,16ת581ת60 // מספטנ1נף 168 11686ס0ק8 15 פתגס 01 עסכתטת 6ם₪ פתעטס6ץ מסנפססםט+ // 1+ עסססתג+ // <סתטת 01888 ,1002 018558> 01866ת66 (5 סתטת ,6ם6 166% ,85682% 166%)ץ01ק8 10ע6ת6ף 6ת1 4 ++-+6 ו-009 למתכנת המקצועי 2 = סתטסס %6ם1 ] (6ת6 =! %ע58568) ש1ותט ; %תגו00ס++ ; (++1)*5682% ] ;%תטסס מעט6%ע2 ו הפונקציה 1186 10ז0מ80 היא פונקציה גנרית המאפשרת לכתוב תחוס נתון לכל פלט. כמו במקרה הקודם, גם פונקציה זו פועלת על תחוס המאופיין על ידי איטרטורים, או מצביעים. האיטרטורים או מצביעים, חייביסם לתמוך בתכונות שתארנו כבר. הפונקציה מקבלת פרמטר נוסף של תבנית, המייצג את הפלט, אשר אינו חייב להיות קובץ, אלא למשל מחלקה אחרת שתומכת באופרטור ''>>:י. העלינו את רמת ההפשטה של הפלט! למשל, אס נגדיר את האופרטור '">>יי שיכניס אובייקטיס לזרס נתון עבור מכולה כלשהי, נוכל להשתמש בו כדי להעתיק אובייקטיס מהתחוס הנתון למכולה הנתונה. תס פאעסח מסנתח תס1פסתט1 66ס1עח 6%10ת66 8 158 שתנשס011+ 6םס // 70 ₪6 0568 16 .מס 16 פסם1עק 0ת8 66םת8ע2 מתסט1ף 8 // עס 822878 ם116%1טע תס א%עסח 60 םבס8סעסק8 טםנ1נתתהפססצס // תד 01 8ל6םת1הפת0ס // <סמק6ט0 018858 ,1002 01858> 01866ת66 (600% 006006 ,0ת6 10658 ,80826 ע2166)166ש 6210ת66 בנסע (0ם6 =! 5682%) 16נ1תט 7 >> %+8%806* >> מטס 12 >> סגוס <1 01888 ,02ם%81ת00 01885> 1866קת66 ]) ע0ססק808 01855 : עס 7 עשס6ת00681 :טס [+ (5ם00ס)6 : (6ם0ס80 ע6ת%81ם600)ע0ס6ק8038 (ט8 71 8%6ת602628802>>)00 8080605 [ ;18ם6* תע0ט6%ע ;(ט)80%מ םפטס.6 1 8 ;ו המחלקה 8080601 היא מחלקת תבנית המאפשרת להכניס אובייקטים למכולה כלשהי. מחלקה זו יכולה לשמש לצורך העתקת תחומיס לתוך מכולות. את מימוש המחלקה 07 אני משאיר כתרגיל לקורא. פרק 11: מבני נתוניס סדרתיים ב-.511 305 | 11.5 | סיכום בפרק וה סקרנו מספר מחלקות של הספרייה הסטנדרטית ,51'1. אלו הן מכולות שבהן נמצאיס אובייקטים שונים. למחלקות אלו יש תכונות ומבנה נתוניס שוניס ולכן הן עשויות להתאים במידה שונה לסוגי יישומים שוניס. המחלקה 6640 היא מחלקת תבנית המייצגת וקטור דינמי. וקטור זה גדל, בעת הצורך. הווקטור דומה למערכיס הסטנדרטיים של ++?), אשר האובייקטיס שנמצאיס בו נשמריס במקום רציף בזיכרון. כתוצאה מכך: * הכנסת אובייקטיס בסוף המערך יעילה מאוד, ואילו הכנסת אובייקטיס באמצע המערך אינה יעילה כלל. * סריקת הווקטור בעזרת איטרטור יעיל מאוד. המחלקה 1886 היא רשימה מקושרת מעגלית כפולה. מחלקה זו אינה שומרת את האובייקטים בצורה רציפה, ולכן הכנסת אובייקטים לאמצע המחלקה יעילה באותה מידה של הכנסה בקצוות. הכנסת אובייקטים בסוף הרשימה יעילה פחות מהפעולה הדומה בווקטור. סריקת רשימה כזו יעילה פחות מסריקת וקטור. המחלקה 66406 היא תור המאפשר להכניס אובייקטיס בשני צידיו. כלומר, אפשר להכניס אובייקטים לתחילת התור, או לסופו. התור הכפול מורכב מבלוקיס שבהס אובייקטיס שמאפשריס להכניס אובייקטיס בתחילה, או בסוף התור, בקלות יחסית. גס במקרה זּה, הכנסת אובייקט באמצע התור גורמת להעתקה של אובייקטיס ולכן התור פחות יעיל מרשימה בנקודה זו. ראינו את סגנון התכנות הגנרל (שחוותות4זפסזק 6110ת86) שפועל על תחוס נתון. סגנון וה מאפשר לכתוב אלגוריתמים גנריס על מכולהיס של .511, או על מבני נתוניס בסיסייס של ++6. שאלות 1. השלס את המחלקה ז8040%0 כך שניתן יהיה להכניס אלמנטים גם למכולות של .1. עליך להתייחס גם להכנסת תווים ו-6261. 2. ממש פונקציה גנרית המאפשרת לקרוא מקובצ לתוך מערך או מכולה. 3 ממש רשימה גנרית מקושרת (יחידה) בסגנון .511. 4 ממש איטרטור המאפשר לכתוב לתוך זרס פלט. 5. ממש איטרטור המאפשר לכתוב מזרס פלט. 6. ממש אלגוריתס מיון עבור הרשימה, הפועל בשיטת מיון ממוזג. בשיטה זו מחלקיס את תחוס המיון לשני חלקים, ממייניס כל חלק בנפרד ואז ממזגיס את שני החלקים. מה הסיבוכיות (זמן ומקום) של אלגוריתס זה: 6 ++6 ו-009 למתכנת המקצועי פרק 12 מבנים שאינם סדרתיים ב- 51 בפרק זה נלמד את המבניס בספרייה הסטנדרטית .511 שאינס סדרתיים. מכולות אלו אינן סדרתיות משוס שסדר הכנסת האובייקטיםס אליהן אינו נשמר, ובעת איטרציה על המכולה, כלומר סריקה, אין כל קשר בין סדר הכנסת האובייקטים לסדר האיטרציה. הדבר האופייני למבניס אלה הוא מהירות החיפוש הגבוהה של אובייקטים במכולות. הדבר חשוב במיוחד למבנה נתונים, כמו קבוצה,אשר מחייב מהירות חיפוש גבוהה. כל המכולות המוצגות בפרק שלפנינו מתבססות על מבנה הנתוניס עץ אדום- שחור (1200 186% 806). עציס אלה הס עצי חיפוש בינאריים מאוזנים (000ב08418 ץזהמוט 6 509101). לכל צומת יש מצביעיס לתת-עץ שמאלי ולתת-עצ ימני, וגס מצביע לצומת האב. לכל צומת יש גם ציון צבע אדוס או שחור, ולכן עצ מסוג זה נקרא עץ אדום- שחור. בפרק גה נלמד אודות המכולות האלו: )56, 1618060מז, כו (-קְגו1)!טות. כל אחת מהן מייצגת אוסף, המאפשר פעולות חיפוש מהירות. | 12.1 | הגדרת קבוצות המונח קבוצה (560) מגדיר אוסף של אובייקטים ללא חזרות. ההגדרה המתמטית של קבוצה אינה מתייחסת לסדר בין האובייקטים השוניס בקבוצה. קבוצה יכולה להיות אוסף סופי, או אינסופי. נתרכז באוספים סופיים, אשר יכוליס להיות גדולים מאוד. העובדה שקיימים אוספיס כאלה (קבוצות) לכשעצמה אינה אומרת דבר, ולכן מוגדרות פעולות מסוימות על קבוצות. פרק 12: מבניס שאינס סדרתיים ב-.ד51 | 307 פעולות על קבוצות את הפעולות המוגדרות על קבוצות אפשר לחלק לשני סוגים : * פעולות המשנות את הקבוצה. * פעולות שאינן משנות את הקבוצה. פעולות המשנות את הקבוצה מכניסות אליה, או מוציאות ממנה אובייקטים. פעולות אלו, בהכרח, משנות את מספר האובייקטים בקבוצה. פעולת 10861 שמכניסה אובייקט לקבוצה, היא דוגמה לסוג הראשון. בתחילת ביצוע ההכנסה יש לבדוק אס האובייקט קיים בקבוצה ואז, אם אינו קיים - להכניסו. לביצוע פעולה וו דרוש חיפוש של האובייקט בתוך הקבוצה. מכאן שדרושה לנו פעולת חיפוש מהירה. פעולה אחרת המשנה את הקבוצה היא הפעולה המבטלת אובייקט מהקבוצה. גם במקרה וה יש למצוא את האובייקט המבוקש, ואז להרחיק אותו ממנה. שוב עולה הצורך בפעולת חיפוש מהירה בקבוצה. פעולות אחרות שימושיות על קבוצות הן פעולת החיתוך ופעולת האיחוד. בפעולת החיתוך יוצרים קבוצה משתי קבוצות נתונות. קבוצת התוצאה מכילה את כל האובייקטיס המשותפים (מופיעים) בשתי קבוצות הקלט של פעולה זו. כמובן שגס צריך לחפש אובייקטיס בקבוצה אחת ולסרוק את כל האובייקטיס בקבוצה האחרת. גם כאן יש צורך בפעולת חיפוש מהירה. בפעולת האיחוד מתקבלות שתי קבוצות שמהן בוניס קבוצה שלישית המייצגת את איחוד שתי הקבוצות הנתונות. קבוצת האיחוד מכילה את האיברים של שתי קבוצות הקלט, כלומר, כל איבר שמופיע בקבוצה הראשונה או בשנייה, יופיע בקבוצת האיחוד. בפעולות שתוארו עד כה ראינו מדוע מהירות החיפוש חשובה, במיוחד לקבוצות. כדי לממש קבוצה בצורה יעילה, עלינו לספק מבנה נתוניס שמאפשר חיפוש מחיר. מבני נתונים אפשריים לקבוצה כדי לספק מנגנון חיפוש מהיר של אובייקטים, איננו יכוליס להסתמך על מבנה נתוניס סדרתי, כמו רשימה. חיפוש אובייקט ברשימה שאינה מסודרת יהיה יחסי למספר האובייקטיס שנמצאיס בה. למשל, אס קיימיס 100,000 אובייקטיס ברשימה, נצטרך לסרוק על 50,000 אובייקטים בממוצע, כדי למצוא אובייקט נתון. מימוש קבוצה צריך, אס כן, להיעשות על ידי מבנה נתוניס שזמן החיפוש בו אינו לינארי. יש מספר מבני נתוניסם שאינס לינארייס. בהמשך נלמד לפחות שניים כאלה. טבלת ערבול אחד ממבני הנתוניס שיכוליס לשמש ליצירת קבוצה הוא טבלת ערבול (18016 1188). טבלה כזו מאפשרת למצוא אובייקט בזמן קצר מאוד. כדי לא לחפש אובייקט לאורך 8 ++6 ו-009 למתכנת המקצועי רשימה אחת, מחלקים את מרחב החיפוש למספר גדול של רשימות. השאיפה היא לחלק את כל האובייקטים בין כל הרשימות באופן שווה, כך שבכל רשימה יימָצא מספר אובייקטיס קטן יחסית. את הרשימות מחזיקים במערך של רשימות. לכל אובייקט יש ערך ערבול (סט1ג/ 11882) שבעורתו קובעיס את הרשימה שבה עשוי להימצא האובייקט. מבנה טבלת ערבול: 3 , , , בטבלה המתוארת יש עשרה אובייקטים, אך חיפוש אובייקט בה הוא בסדר גודל של השוואה אחת, ולא חמש. הסיבה לכך היא, שאת הרשימה המתאימה לערך מבוקש אנו מקבליס מערך הערבול בפעולה מיידית. כלומר, בעזרת ערך הערבול מקבליס את האינדקס של הרשימה המתאימה במערך הרשימות. חישוב ערך הערבול אינו תלוי במספר האובייקטיס הכללי בטבלה. כעת שקולה מציאת האובייקט לסריקה של רשימה קצרה, שני אובייקטיס במקרה זה. כדי לממש טבלת ערבול, יש לספק פונקציית ערבול (מסגוסחטע ג1188) המקבלת אובייקט ומוצאת את הכניסה המתאימה לה במערך. בנוסף, יש לקבל פונקציית השוואה בין אובייקטיס. לטבלת ערבול אין פונקציית סדר בין אובייקטים. כלומר, אין כל סדר קבוע של אובייקטים, וכשסורקיס טבלה, מקבלים את האובייקטיס בסדר אקראי, ולא בסדר הכנסתס לקבוצה או סדר אחר כלשהו. אחת הבעיות בטבלה כזו היא התנגשויות. אס פונקציית הערבול אינה אופטימלית, יש מספר התנגשויות רב ומספר גדול של אובייקטים מרוכו בכניסות מסוימות של הטבלה. במקרה הפחות טוב, יהיו כל האובייקטיס מרוכזיסם ברשימה אחת, וזמן החיפוש בה יהיה לינארי. בעיה אחרת נוצרת כשאיננו יודעים מראש את מספר האובייקטים שאנו צריכיס באוסף. אם קובעיס טבלה קטנה מדי, תהיינה התנגשויות רבות והחיפוש לא יהיה יעיל. אס נקבע טבלה גדולה מדי, יהיה בזבוז זיכרון ללא צורך. אפשר למצוא שיטות לחישוב יעיל של ערך הערבול עבור סוגי משתניס שוניס ומספרס. בכל מקרה, קשה מאוד למצוא פונקציית ערבול אופטימלית המחלקת את האובייקטים באופן שווה בין הכניסות השונות בטבלה. פרק 12: מבניס שאינס סדרתיים ב-.511 | 309 לטבלאות קטנות ניתן להגדיר פעולה שסורקת את הטבלה ראשית, מכפילה את גודלה ומערבלת מחדש את כל האובייקטים בטבלה. פעולה כזו מקטינה את מספר ההתנגשויות ואת האורך הממוצע של כל רשימה במערך הרשימות. כתוצאה, פעולה כזו משפרת את מהירות החיפוש של אובייקטיס בטבלה. מבנה נתוניס אחר, בעל זמן חיפוש קצר, הוא עץ בינארי (1106 עְזגּתום). בעצ בינארי יש לכל צומת שני מצביעיס אל הצאצאיס הישיריס שלו. כלומר, לכל צומת יש מצביע לתת-ע שמאלי ולתת-עצ ימני. לעצ בינארי יש צומת מיוחד המשמש כשורש העצ, ואין לו צומת אב (הוא הראשון!) בין הצמתים של העצ מוגדר חס סדר (מ16]800 01601). אפשר להבתין מי גדול, או קטן יותר בין כל שני צמתים בע. כל הצמתים המופיעים כבנים שמאליים של צומת מסוים קטנים מצומת האב. כל הצמתים המופיעים כבנים ימניים (תת עץ ימני) של צומת מסוים גדוליס מצומת האב. הגדרה וו היא הגדרה רקורסיבית (מ10100מו661 181/6ט100), אשר מאפשרת חיפוש יעיל בעץ. כדי למצוא צומת כלשהו יש לרדת בע ימינה, אס הצומת המבוקש גדול מהצומת הנוכחי. אם הצומת המבוקש קטן מהצומת הנוכחי, יש לפנות שמאלה בעצ. הדוגמה הבאה מציגה עצ של ערכיס שלמיס, לשס הפשטות. בכל צומת יש מצביעיס לתת עצ שמאלי וימני, והצומת (האיבר) עצמו מחויק ערך שלסם. הפונקציה 12801 206 מדגימה את האלגוריתס של הכנסת אובייקט לע בינארי. כשרוציס להכניס צומת חדש לע, יש למצוא את המקוס המתאים לו. יורדים בעץ עד שמגיעיס לעלה (מתחילים מהשורש, כמובן). בכל רמה של העצ ייתכן שהנתון החדש גדול מהערך הנתון הנוכתי, ולכן צריך לפנות ימינה. אס הנתון החדש קטן מהנתון הנוכתי, יש לפנות שמאלה. כשמגיעים לעלה מוסיפים צומת נוסף לבן השמאלי, או הימני שלו. ] 6ססם 06גוע56 17ע* ,161%* 6בסת ;8 סתםב [ ;0 = 6ם10ע = 1656 + (848₪8)0 : (8 6מם1)פסםת ;ן (68%8 %6ם862%)1ת1 6266 ו 2 = ע8ק* ,0%סע = עגוס* סבסת (עטס) ש1ונתט 2 = 80 (08%8 > 08%8<-ע00) 11 ;%ם16ע<-ע002 = מעוס 1-6 2 <-תטס = עטס ] (0 == ע8ק) 15 ; (08%8) פסם שאסם = 006ע 0 ++-+6 ו-009 למתכנת המקצועי (08%8 > 08%8<-82ק) 11 6156 ; (08%8) 006 שטפם = 6ם16ע<-עהס 1-6 ; (08%8) פס שטסם = 1656<-82ס 1 הבעיות המתעוררות בעציס הן הכנסה של צמתים המסודרים בסדר עולה, או יורד. במקרה כזּה העץ מתנוון לרשימה, משום שכל הצמתים מוכנסים תמיד בתת עצ ימני, או שמאלי. במצב זה החיפוש בעץ איטי ומבנה הנתוניס הופך להיות שקול לרשימה. בעיה אחרת בע הבינארי, היא שיש לספק פונקציה המתארת סדר בין אובייקטים. סדר וה דומה לסדר שקיים בין מספרים, אולס הוא אינו תמיד קייס בין אובייקטים. למשל, בין מלבניס אין יחס סדר ברור. אנו לא יכוליסם לומר אס מלבניס שוניס מקיימיס את היחס קטן באופן כללי מספיק. כלומר, כאשר נתונים שני מלבנים, איננו יכולים לומר בוודאות מתי האחד קטן מהשני. עץ מאוז| - 776 136% 60 עץ מאוזן (11060 066ת2418) הוא עצ שהמרחק בו בין כל עלה אל שורש העצ זהה. בעצ כוה, המרחק בין שורש העץ לעלה הוא לכל היותר (ם)8ס1, כש-ם הוא מספר האובייקטיס שבעצ. תכונה וו הופכת את העא למבנה נתוניס המאפשר חיפושיס מהירים. כפי שכבר ראינו, חיפושים מהיריס נדרשים במיוחד בפעולות על קבוצות. לפיכך, עצ הוא מבנה נתוניס מתאים למימוש קבוצה. כבר ראינו שעציס דורשיס יחס סדר בין האובייקטיס שמוכנסים לתוכם, כדי לקבוע את מקומס בע ואכן, זה אחד החסרונות במבנה נתוניס זה. אך למרות החיסרון, הספרייה הסטנדרטית של ++6 משתמשת בע בינארי מאוזן כדי לממש את הקבוצות והמילוניס שכלולים בה. הספרייה משתמשת במבנה נתוניס של עצץ מאוזן אשר נקרא עץ אדום- שחור (1100 186% ₪066). עץ אדוסם-שחור הוא עצ בינארי המקיים את התכונות הבאות : * לכל צומת בע יש צבע אדוס או שחור. * לצומת אדוס יש בניס שחוריס בלבד. * כל עלה בע הוא שחור. * כל מסלול פשוט (ללא מעגלים) מצומת לעלה, כולל מספר וזהה של צמתיס שחורים. כשהעף מקייס את התכונות האלו אפשר לראות שהמסלול הארוך ביותר משורש העצ לעלה אינו גדול מ-(ם)2*108, כש-ח הוא מספר הצמתים בעצ ו-108 הוא לפי בסיס 2. עצ אדום-שחור אינו סובל ממצב בו יש חוסר איזון מוחלט, והחיפוש בו מהיר ופרופורציונלי ל-(ם)8ס1. פרק 12: מבניס שאינס סדרתיים ב-1ז5 | 311 כדי להגיע למצב הרצוי יש לאזן את העצ. עושיס ואת כשמוסיפיס אובייקטיס לעצ, או כשמבטלים אובייקטים, והדבר הרבה יותר מסובך מהכנסה של צומת לעצ, כפי שלמדנו בסעיף הקודם. נסקור פעולות אלו, אך לא נציג אלגוריתס מלא לפעולות אלה. כשמכניסים אובייקט לעצ, מוסיפים לו למעשה צומת אדוס בעל שני בניס (עליס) שחוריס. מכיון שהצומת החדש הוא אדום, אנו עלוליס להגיע למצב בו האב של צומת זה הוא אדוס. דבר זה מתוקן בעזרת החלפת צבעים וסיבוביס של העץ במידת הצורך. מכיון שמוסיפיס צומת אדום, אין פגיעה במספרי הצמתיס השחורים. כשמבטליס צומת מהעצ עלוליס לבטל צומת שחור, ואז מספר הצמתיס השחוריס במסלול מסויס עלול להיות קטן מבמסלול אחר. הפעולות האפשריות לתיקון הן החלפת צבעיס וסיבוב העצ. פעולות סיבוב של העצ גורמות לעץ להיות מאוזן יותר. האיור הבא מדגיס סיבוב ימינה יחסית לצומת 8 של החלק השמאלי. הסיבובים מאזניס את העצ וגורמים לכך שהחלק חימני שהיה חסר בצומת יוצב לאחר הסיבוב בצד השמאלי כדי לאזן את מספר הצמתיס בכל צד. 15 60 69( 0 0 4 | 12.2 | הקבוצה +66 המחלקה של הקבוצה, 5% נמצאת ב-.511. לקבוצה יש איטרטור המאפשר לסרוק את האובייקטיס של הקבוצה. הקבוצה עצמה מבוססת על עצ חיפוש אדוס-שחור. מבנה הקבוצה המחלקה 8% ב-.511 מייצגת קבוצה שבה אין חזרות, ופירוש הדבר שאובייקטים עס מפתח מסויס מופיעיס בה פעם אחת בלבד. מחלקה זו משתמשת בעצ שחור-אדום, כדי לממש את הפעולות הנדרשות על קבוצה. כל צומת בעצ מחזיק העתק הנתון שהוכנס לקבוצה על ידי המשתמש. 2 ++0 ו-009 למתכנת המקצועי פונקציות חשובות יש מספר פונקציות חשובות של המחלקה 5% שהשימוש בהן רב ולכן נסביר את המושג חת*מה (0ז6180800), או אבטיפוס (06ץ0101זכ) שלהן. חתימה, או אבטיפוס של פונקציה, הס הפרמטריס של הפונקציה, סוגם ומספרם, וסוג הערך של הפונקציה. אלמנטיס אלה מאפיינים את הפונקציה, והס הממשק שלה למשתמשים בה. אבטיפוס של פונקציה, כלומר הפרמטריס והערך המוחזר, נראה כך למשל, בתוכנית : (()0000826 = קתסס 00008268 586םת566)00 ,2 *ססץם 6ט10הט 00286 ,11286 *6קץ6 8106ט 86ת56%)00 (()0000826 = קתסס 8266קת00 ספםסס (18186 ,0.א)₪ : (א 826<86קת00 ,ץ566>86 86ם00ס)566 0826<8ת60 ,7ץ8960>86 628002=)00286ק0ס 2826<8ת00 ,7ץ566>86 (א הבנאיס מאפשרים ליצור אובייקט מסוג 5%%. כשמגדיריס אובייקט מסוג זה יש לתת לו את הפרמטרים של התבנית המייצגים את סוג האובייקט וגם פונקציה או אובייקט פונקציה, המשמשים להשוואות בין אובייקטים. הבנאי הראשון הוא הבנאי הריק המאפשר ליצור קבוצה ריקה. הבנאי השני מאפשר ליצור קבוצה מתחוס ערכיס נתון. הבנאי השלישי הוא בנאי ההעתקה והאופרטור האחרון הוא אופרטור העתקה. [ ;()ם0601.% מעטס6ע + 58ם60 ()ם6081כ ע1662860 [ ;()6ם6.% מתעטס6ע + 8%6ת00 ()0ם6 16628602 [ ;()ם20601.% מעטס6ע + 8%6ת00 ()ם1ס6סע2 16628602 266286 [ ;()0ם6.26 מעט60ע + 6פת00 ()0ם6ע2 16628602 26625856 [ ;()עץסקתס. תעטס6ע + ספתסס ()עץסקתס 1ססס [ ;()6₪.8126 תעט66ע + 0086 ()8126 6סץ6 5126 [ ;()8126 אהת.6 םע80ט260 + ספתסס ()585126 אאת 6סץ6 5126 [ ;(6.א)ק8חפ. + (א 826<6קת00 ,ץ6א>566) ק8ח5 בנ1בסט הפונקציות מוַשַסס ו-626 מחזירות איטרטורים שמתאימיס לתחילת הקבוצה וסופה. הפונקציה 5126 מחזירה את מספר האובייקטים הנוכחי בעצ. הפונקציה 5126 אא מחזירה את גודל העצ המקסימלי. (א8 66קץ6 08106 8%ת562%)00ת1 0001 16628605 תעגה הפונקציה 688מ1 מאפשרת הכנסת אובייקטיםס לעצ. הפונקציה מחזירה איטרטור שמציין אס אכן הוכנס האובייקט לעץ, או שההכנסה נכשלה. כשאובייקט כזה נמצא כבר בעצ, אין ההכנסה מתבצעת. פרק 12: מבניס שאינס סדרתיים ב-.1ז5 | 313 הפונקציה השנייה אספתו1 מאפשרת להכניס לעצ בקריאה אחת תחוס נתון של אובייקטיס. התחוס מתתיל ב-113 ומסתיים אובייקט אחד לפנל 18%0. כלומר, התחוס אינו כולל את )188. *6סץ> 8106ט 00286 ,11286 *6סץ6 6מ1אט 86ת6026)00פ8פת1 בנסט 185%( (תס1ף1פסק 62856)16628%02 1בסט (א 66קץ₪ צץ%6 8%ת62886)00 6סץ6 5126 (188% ע16₪6₪28%0% ,51289% ע₪2896)1%02860 ב1סע הפונקציות 61986 מוחקות אובייקטיס מהעצ. פונקציית המחיקה הראשונה מוחקת את האובייקט המוצבע על ידי איטרטור של העצ. הפונקציה השנייה מוצאת את האובייקט המתאיס לערך שהיא מקבלת ומבטלת אותו מהעצ. הפונקציה השלישית מבטלת את כל האובייקטים בעצ שנמצאיס בתחוס מסוים, כשהתחוס נתון על ידי שני איטרטורים. ב מ86₪ // 8% ((9א 607066 86 586ת0)00םת51 16028605 % ((9א 67066 צ6א% ס6פתסס)6תטסס 6סץ6 5126 (8 68קץ6 צ%6 8%ם00)בתטסס מפפשס1 16028608 % ((9א 07066 צץ6א 56ת00)בתטסס ע6קסט 160286052 <2ע1662860 ,812>1%028%02ק | 6061קץ6 100286027 16628608 עג1ה8ס פס 116%קתסס בתטסעה8 886 0ם 606 68661סצ₪ // % (9א 6066 צ6א% 86ת06)00ם28 60081 10628602 860%ע1662 מג1ה8ס יש מספר פונקציות המאפשרות פעולות מתמטיות על הקבוצה. הפונקציה 1:84 מוצאת אובייקט שנמצא בקבוצה. מובטח שפעולת החיפוש תהיה מהירה. סיבוכיות הזמן של פעולת החיפוש היא (ם)8ס1. הפונקציה +תט0ס6 מונה את מספר המופעים של אובייקט נתון (במקרה זה, אפס או אחד). הפונקציה 6מטסט 1061 מחזירה איטרטור המצביע לאובייקט הראשון הגדול ביותר, שעדיין קטן מהאובייקט הנתון לפונקציה. הפונקציה 6פטספ זסקקט מחזירה איטרטור לאובייקט הקטן ביותר, שעדיין גדול מהאובייקט הנתון לה. הפונקציה 6 60081 מחצירה זוג איטרטורים המהווים את תחוס האובייקט הנתון. פונקציה זו מחזירה צמד איטרטוריס השקולים לאיטרטוריס המוחזרים על ידי הפונקציות טסט זסאס1 ו- 6תטוסס זסקקט. על כן, הפונקציה מחזירה תחוס. האיטרטור איטרטור הקבוצה דומה למצביע רגיל. כשמפעילים עליו את האופרטור **יי מוחזר התוכן הנוכחי של האיטרטור, שכאן הוא האובייקט הנוכחי. איטרטור הקבוצה הוא למעשה איטרטור העצ. 4 ++-+6 ו-009 למתכנת המקצועי איטרטוריס לתחילת הקבוצה, או לסופה, מתקבליס על ידי הפונקציות מופסט ו-686 שלה. בצורה דומה מתקבליס גם איטרטוריסם הפועלים בסדר הפוך, כלומר מהאובייקט הגדול לקטן. השימוש באיטרטור, במקרה וה, הוא כדי לעבור על הקבוצה. אין להשתמש באיטרטור עבור אלגוריתם גנרי כמו ₪26 (וזו רק דוגמה אחת). הסיבה לכך היא, שהאלגוריתם האחרון סורק את כל הקבוצה. לעומת זאת, הפונקציה 4 של המחלקה 566 פועלת בזמן לוגריתמי, אשר הרבה יותר קצר מזמן ליניארי. זאת ועוד, האיטרטור מחזיר אובייקטים קבועים כשמשתמשים באופרטור "*". הסיבה לכך היא שאסור לשנות את תכולתו, כי שינוי כזה משנה את האובייקט שנמצא בעץ. כתוצאה משינוי כוּה יכול להשתנות הסדר בין האובייקט הנוכתי לאובייקטיס אחריס בקבוצה, ואז מיקוס האובייקט בעץ יהיה שגוי. הדבר יכול לגרוס לשגיאות באלגוריתס ההכנסה, או ההוצאה של אובייקטים. | 12.3 | קבוצה עם כפילויות קבוצה עם כפילויות (0561!ח), קבוצה כפולה, או קבוצה מרובה, דומה מאוד לקבוצה רגילה, אלא שבקבוצה כפולה מותרת החזרה על אובייקטים. כלומר, אובייקט בקבוצה כפולה יכול להופיע מספר פעמים. דבר זה נראה תמוה במבט ראשון, אך יש מצביס בהס רוצים לאפשר למספר אובייקטים, בעלי אותו מפתח, להופיע בקבוצה. תכונת הכפילות אינה מתאימה להגדרה המתמטית של קבוצה (וגס לא יחס הסדר), ולכן חשוב שלא לְעַרָב את שני המונחיס. בהגדרה המתמטית של קבוצה, אין מקוס לאובייקטיס חוזרים, ואין הגדרה של סדר בין האובייקטיס בקבוצה. לפי ההגדרה המתמטית קבוצה היא אוסף לא סדור של אובייקטים ללא חזרות, כלומר, כל אובייקט מופיע בקבוצה פעס אחת ויחידה. פונקציות חשובות פונקציות קבוצה כפולה דומות מאוד לפונקציות של קבוצה רגילה. השינוי הגדול הוא כשמכניסים אובייקט לתוך קבוצה כפולה, ולכן לא נפרט שוב את כל הפונקציות של קבוצה כפולה. (8781 6קץ6 08106 8%ת862%)00ם1 16628602 במקרה וה אין כישלון בהכנסת אובייקט, כי האובייקט והה לאובייקט שכבר נמצא בקבוצה. הפונקציה מחזירה איטרטור (מצביע) לאובייקט שהוכנס לקבוצה. פרק 12: מבניס שאינס סדרתיים ב-.511 | 315 דוגמה - שימוש בקבוצה בסעיף זה נראה דוגמה לשימוש בקבוצה ובקבוצה כפולה. השימוש בשתי מכולות אלו דומה מאוד (שכן הן מספקות פונקציונליות דומה), נדגיס את שתי המחלקות יחד. הדוגמה שנראה היא מימוש של מללון (ע600281ו6). במילון יש מילות מפתח שלכל אחת מהן יש הסבר המבאר את פירושה. ההסבר יכול להכיל מספר רב של מילים. הדוגמה מבוססת על פונקציות גנריות (בדומה לפונקציות הגנריות של ,511) שאינן תלויות בסוג הקבוצה. הדבר מאפשר לשנות את הקבוצה מקבוצה רגילה לכפולה, ולהיפך, ללא צורך בשינוי התוכנית. יכולת הכתיבה של תוכנה בצורה גנרית כזו חשובה מאוד, כי היא גורמת לכך שהתוכנה תהיה פחות חשופה לשינויים. הקורא ייטיב לעשות אם ישנן דוגמה זו היטב. בדוגמה אפשר להוסיף או לבטל כניסות למילון, לשנות את התיאור של כניסה מסוימת ולכתוב או לקרוא את המילון מקוב. כמו כן, נאפשר למשתמש להציג את כל המילון. הפעולה האחרונה יכולה להיות מאוד לא ריאלית כשהמילון גדול. הדוגמה נמצאת בדיסקט המצורף, בקבציס שק616)1.6, ת.61601. כניסה ביומן כל כניסה ביומן מיוצגת על ידי המחלקה עז8ת10)0. בכל כניסה יש מחרוזת המתארת את המפתח ותיאורו (הסבר של המילה המתאימה). המחרוזאת ממומשת על ידי אובייקטיס מהמחלקה 518 שלמדנו בפרק קודם. 6 50 68068 6ם₪ 610068ת1 1116 פ1מץך // 6 ם1 ץע6ת6 תת .866 57 סַם1פט צץ82ת610610 // .ת610ק608021 6ת8 צ6א% 0% 00020860 18 ץ85ת6105810 // // "ת.561/86%" 61066ת1+ "ת.0ם5621" 66ג010ם1+ ] ץע%םע0%ס1כע 01858 ץעססת 618 0% צ6א 6םס // ;ץ6א 06ם5601 מס1נסףק6650?1 7'58ץ6א% 6םם // 2 ₪%ם1ע56 :טס (0* 082 008% ,א%* עאםתס 856ם0ס) ץע6םתט6סנ1כ [+ (83686)8 ,(6)8א% % ()67א 666* ע8ת0 00856 [;()08602 867.66 מעגוס6ע ] % ()060850 666* ע8ת0 00856 [ ;()0802 0680.866 מעגוס6ע + (0* ע8ת0 86ם06580)00 566 16סע ]ל 6 6 ;ן 6 ++-+6 ו-009 למתכנת המקצועי פונקציות עזר אנו משתמשים בקבוצה של ,511 (ולא בקבוצה מתמטית) ולכן יש להגדיר יחס סדר בין האובייקטיס בקבוצה. נגדיר את יחס הסדר כיחס לקסיקוגרפי בין מפתחות האובייקטיס במילון. כדי לממש את יחס הסדר נגדיר אובייקט פונקציה ץת6 106 16588 המשתמש בפונקציית הספרייה קותסש5, כדי להשוות בין מפתחות האובייקטיס השוניס. 8 0000820 ₪0 86% 6ם5 0%+ 021606 מ0ס661םט+1 // ] ץע6ם6 0106 16858 562006 1 עטשעסתטססנ1ע 5856ת628602)(')00קס %ם1 % (60602 צץע%ם210%8 0086 ,; ()7ץ%6 401.96%) ק86200) םע660ת2 ] [ ;(0 > (()ע%6 062.666 2 כדי לאפשר הצגת כניסות במילון נגדיר אופרטור ">> המקבל זרס פלט (((050708), ואובייקט המדפיס את האובייקט לזרס פלט. ץעהתס010%1 6םתם ת1 שְל5ם6 ת8 פטקפטס סם עסס8ע62קס תא // (806 ץע%םע10%0כ 5%8ת00 ,80 ת602628%602>>)085%208 ת(05%6268 ;'ת' >> ()8680 66.86% >> "סם" >> ()צ6א% 66.066 >> 0 ;0 תעגו6ס6ע ו בעזרת )170060 אנו שולטים על סוג הקבוצה שמפעילה התוכנית. משפט ההגדרה מגדיר את המחלקה %% פעם אחת כמילון עס פרמטרים של כניסה ביומן ואובייקט הפונקציה, ובפעם אחרת כקבוצה כפולה. שאר חלקי התוכנה אינם תלויים בסוג הקבוצה. גישה זו יעילה כשרוציס לשנות מבנה נתוניס בעורת הגדרה אחת, ללא כל צורך לשנות את ההתייחסות אליה בכל התוכנה. 8 תת 067/60 86ם028 ₪0 צץ688 18 16 5850 56061 6פט // 2 <צעש6ם6 0108 1688 ,צע6ם1080כ56%>2 66061 // 2 <ץע6ת6 64106 10688 ,ץ%2ם10%0כק>161586%גות 6661קץ6 הפונקציה 8150189 פועלת בצורה המקובלת של פונקציות .511 ופונקציות גנריות. היא מקבלת שני איטרטורים כפרמטרי תבנית. האיטרטור הראשון משמש להגדרת התחוס שרוציס להציג, והאיטרטור השני מייצג את הפלט. הפלט יכול להיות מנותב אל הפלט הסטנדרטי (המסך), קוב, או כל איטרטור אחר התומך באופרטור ">>/. %טקפטס תפט1 8 0ם 6ת11 8 םתס 1668 ג680 6180187 // <6מק6ט0 01888 ,10052 018558> 66801866 (8009 06ק00% ,0ם6 1862 ,86826 7)16652ץ8315018 %הנ1בסט (0ם6 =! %ע5682) 116םתט פרק 12: מבניס שאינס סדרתיים ב-.1ז5 | 317 ;++5%82%* >> סגטוס ] הפונקציה 60 מעתיקה מחרוזת אחת לאחרת. העתקת מחרוזת המקור (טצא) נמשכת כל עוד לא מגיעים לתו סוף המחרוזת (0), או לתו המסמן רווח. הפונקציה מקדמת את המצביע למקור עד לתחילת המילה הבאה ומחזירה אותו. אפשר לשפר את יעילות הפונקציה, ואני משאיר ואת לקורא, כתרגיל. 8 תעט65ת 6ת8 ת8610ת069%1 %0ם1 6ם1ע58% 06עט50 צְקסס // 1 05 66 6ם5 6ת1ת6ס 6ת106ע2 500006 6ם₪ 0ם ש6סת1סק // (סעפ5* 028% 5%ת00 ,086* צ8ם0) ץקסס* עאםת0 ספםסס ((20ע806)*8ק1550! 88 0ע85*) 116תט ל ;02 = 086* ((20ע18590806)*5 66 0ע52*) 116תט ;800++ ;0 מתעוססע ו הפונקציה 8611186 היא פונקציית תבנית המאפשרת קבלת שורת קלט ממחלקות התומכות בפעולה )86, אשר מחזירה את תו הקלט העוקב. השורה נקראת עד לתו הזיהוי של שורה חדשה, המוכנס לחוצ> שהארגומנט 5מו1 מתייחס אליו. תו הזיהוי של שורה חדשה מוחלף בערך המספרי אפס, המציין את סוף מחרוזת. 16 חספם 8 11סתט סטקת1 6ם6 268869 מתס1ססםתט1 18ם6 // 18 ע10+טס סטקם1 6םת6 11סתט עס עהַת6 // .0 1889 6ם11 חסםת 112856 6םך7 // <פ%מקת1 018558> 66001866 (8126 %ת1 ,6םת11* עהםת0ס ,ם81 6טקת6)1ם66611 בנ1סע ;'ת' = 1ת 8%ת0 600956 72 - 5126 + 6ם11 = ם8* עַַַם0ס ; (6מ66%)*11.ם1 (נםת =! 6םת11*) +1 7+ ] (0ם8 > 6ת11) 116תט ; (6מ66%)*11.ם1 (1ם == 6₪ם11*) 15 ;268% 16 7+ ] 7 = 6ם11* 8 ++-+6 ו-009 למתכנת המקצועי פונקציית התבנית ץזוחס )+טסםו, בצירוף פונקציות נוספות, מאפשרת קבלת קלט שבו מילת מפתח אחת, ומספר מילות הסבר למילת המפתח שנגמרות בשורה חדשה. הפונקציה מחוירה אובייקט שמייצג כניסה אחת ביומן. פונקציית תבנית זו מחזירה אובייקט אל מחסנית התוכנית, וכך האובייקט המוחזר מועתק לתוך האובייקט המבוקש. העתקה אינה פעולה זולה וניתן למנוע אותה על ידי העברת אובייקט לפונקציה זו, שתאתחל אותו. % פתעגטססע 6ם8 צץ2ע8ת010010 6ם₪ 05 שְ55ם6 6תס 5ס6טסם1 // .0% 6 מס // <פוקת1 018558> 66801866 (ם61 6טקת1)ץע62ם6 סטסם1 צְצ6םמ%ס1כ ו 72 = 689126ת11 ,256 = 055126 6ת1 00856 ,[8650]0018126 , [0018126] 867 עַַַםס ;[68126ת6[]11םת11 ; (68126ת11 ,6ם11 ,ת6)1ם46611 ;(6ת11 ,צץ86)צק0ס0ס = 0סעפ* ע8ם0 ספתסס ; (0ע 52‏ -,0650) 562007 ; (8680 ,7ץ6א) ץע%2ם10%8כ מעגו6%? ו פעולה אחרת, הנדרשת במילון היא עדכון של תיאור מילת מפתח. תיאור מילת המפתח ניתן לשינוי, ללא ביטול המילה והכנסה של מילה אחרת למילון, כי תיאור זה אינו משתתף ביחס הסדר. לעומת זאת, אסורה פעולת שינוי של מילת מפתח. הפונקציה מחפשת את הכניסה המתאימה בעזרת פונקציית החיפוש של הקבוצה ומחזירה איטרטור. אס האיטרטור שונה מהאיטרטור המוחזר על ידי הפונקציה 6מס של הקבוצה, הרי שהכניסה המתאימה נמצאה, ואפשר לעדכן אותה. אחרת, לא קיימת כניסה כזו. % 10סק1ע6680% 6תם 08668ק₪ 16 .צע%ת6 פםס 6866קט // 8 טססםע6 00001168 8 866 18טסח טסצ .שְע6ת6 6םס // 6 500 027606 8%ת00 8 פתעט60ץ 1628602 6םס // .0% 18 16 צ8א 6ם6 6868קט פסם 60 שח 06םת81 .מספ658ק0 * // (80 410%6)210% 68%66ק90 בנסע ; (ת1ס) ץע6ת6 סטקם1 = 646 צע6תתפסנכ ; (06)₪מם0.51 = 1 ע160%::1802860%כ (()0ם3.6 =! 1) 15 ;(()00680 0080)06.066 866. (1*) 16 ;801 >> "תטמס ססם צְע6םת6" >> סטסס פרק 12: מבניס שאינס סדרתיים ב-.1ז5 | 319 הפונקציה המבטלת כניסה מהמילון משתמשת במילת המפתת כדי לעשות ואת. באמצעות מילת המפתת שמכניס המשתמש, בונה הפונקציה כניסה ביומן (עס תיאור ריק), ומשתמשת בפונקציה 67986 כדי לבטל את הכניסה המתאימה. ץצ8תס810%1 6ם₪ מסע+ שְע5ת6 תה פסטסתסץ // (80 210%)%ת6 60076ע2 16סע ו ;[7]64ץ6א עַַם0 ;":0076ת26 0סם צץ%8 עססתמת" >> סגוסס ;צסא << םת1ס 12 >> 0006 ; ("" ,ץ6א)06 צְע6םתט6סנכת ; (06) 0.62886 ו הפונקציות 6166 1086 ו-6106 )מש משתמשות בפונקציה שא 116 8 כדי לקבל את שס הקוב שממנו יש לקרוא, או שלתוכו יש לכתוב. הפונקציה )6106 )וזאי פשוטה, משוס שהיא משתמשת בפונקציה 418018 כדי לכתוב את המילון לקוב נתון. הפונקציה 15018 משמשת לכתיבה לקובצ ולהצגת אובייקט על הפלט הסטנדרטי. הפונקציה מיישמת את רעיון התכנות הגנרי, עבודה על תחום הנתון על ידי איטרטורים, ולכן היא טובה לכל תחום. הפלט אף הוא פרמטר של התבנית שלה, ולכן ניתן לשנות אס את סוגו! עספט 6םם 0+ סתהם 1116 8 666 // () סתהת 2116 666* ע8םת0 ספתסס ;[128]+טס עַת0 568610 ;":סתהת 1116 ע6סםת6ת" >> 006 ;טס << מ01 12 >> 0006 ;+גוס ת02ו266 .1 8 ססת1 צץע8ת610%10 6םת₪ 166מח // (80 010%)210% 166עח בנ1סע ; () סתהת 5116 96% = סתהת 116?* עהאםס 6056 ; (6ת8ת 00%)2116 ת018%208 ;(סטס ,()0מם8.6 ,()ם4.6001) 4150187 ] הפונקציה 616 2086 מסובכת יותר מהפונקציה = 016 6אי. הפונקציה מגדירה אובייקט מסוג ‏ 18₪69₪. אם האובייקט תקין (כלומר, קיים קובצ מתאים), הפונקציה מנקה את המילון בלולאה שבה היא מקבלת כניסה אחר כניסה מהקוב הנתון בעזרת הפונקציה ץשת6 )טסםג. הפונקציה 026 וטקפ משמשת לקבלת כניסה ביומן, 0 ++-+6 ו-009 למתכנת המקצועי מהמשתמש או מקלט. השימוש בפונקציית תבנית מאפשר שליטה על סוג הקלט, ללא צורך בשינוי פונקציית התבנית, או כתיבת פונקציות נוספות. מסט1נס 6ם6 11 .1116 8 תסע+ צ82ת010%610 8 2686 // מסתס 86 צץ2ע8ת010%10 6ם₪ 628868 156א< 1 // 8 8 6ם₪0851 1116 66 0פם1 סטקם1 26868 // סקססן1 // (80 410%)210%6 2686 16סע ו ; () סתהת 2116 06% = סתהת 1116* עהאםס 60586 ; (ס6תהת 5116)ם1 מת1585%268 + (מיב). ]ה ;(()0ם8.6 ,()ם4.62886)0.06001 + (ם1) 16נ1תט ; (ם1) ץע%2ם6 סטקםת1 = ₪6 צְע6םמ6ס1כ (ם1) +1 ; (06) 862%6ם4.1 ו הפונקציה תסו 615018 מציגה למשתמש תפריט פעולות אפשריות, ומקבלת ממנו את הפעולה המבוקשת. מספר הפעולה המבוקשת מוחזר לפונקציה שקוראת לפונקציה זו. ,סתס צץ3158018 ,סתס 6ע62פת1 ,תס 16א6 + 08תאתתסס תטתס ,תס 6ס1עח ,תס 6טסת6ע2 ,בתס 68%6קג ;( תס 26806 סתהתתסס ₪26 פתעט60ת 6ת8 ע6פט 6ם6 60 גומסת 8 815801879 // ()טתסת ץ815018 6ת1 ו ;תס 6816 = 68ע 6ת1 ;"ת.1%א6 (" >> 006 16א6% >> 6וסס ;"ם. צע6ם6 חס6ם 8 8626ם1 (" >> 0מס 6ע562ם1 >> סגוסס ;"ת.68מ66ת00 צע8ת610%10 615018 (" >> חס צ015018 >> סטסס ;"ת.ץ6א% 8 0866ס₪ (" >> 0מ0 0866ק₪ >> 6גוסס ;"ת.ץ%6 8 6טסת6ע2 (" >> 0מ0 6טסמ6ע >> 0006 ;"ת.1116 8 0סם1 166עטח (" >> 006 166עח >> סטסס ;"ת.5116 8 00סע+ 2680 (" >> 06 2686 >> 0006 0 7 << ם1ס 7 תמעשט66ע פרק 12: מבניס שאינס סדרתיים ב-זז5 | 321 הפונקציה הראשית מגדירה אובייקט מסוג מילון ופועלת על אובייקט זה בלולאה. היא מקבלת את הפעולה המבוקשת מהפונקציה טפסג 618018 ומבצעת את הפעולה הדרושה בעזרת קריאה לפונקציות העזר, ובאופן ישיר על המילון. הפונקציה יוצאת מהלולאה כשמתקבלת פקודת היציאה מהמשתמש. 2 בת גמותפת 6םת5 8180218798 70856 תסנ1ססםתט+ ת1את 6םס // עספט 6ם6 תסע+ פתהתתסס 6םת% 600%658א₪ // ()מ1נהת %ם1 6%נ1ס ; ("" ,"")36 עעסתמפסנקת ;תס 6ם1 ]) (6ת0ס 816א6 =! (()גמםתפת 0158018 = 6תס)) 16ותש 1 (0ת0ס) םמ5160 :תס 6ע6פת1 08856 ;":ת%10ק1ת6650% 6םת8 צ%8 ע66תמת" >> סגוסס ; (ת1ס)ץע%62ת6 6טקם1 = 66 ; (06) 562%ת010%6.1 268%; :תס צ615018 , () ם410%6.0601) צ015018 ; (16ו00 ,()8ת010%.6 000% >> 601; 268%; : סתס 6866סג ; (610%) 6106 68%6ס0 ;268% : תס סטסתסע ; (610%) 66 6טסת6ע2 268% ; :תס 166עח ; (010%)010%6 166עח 268% ; :תס 680ע2 26806 010%)010%6( ; ++6 ו-009 למתכנת המקצועי 268% ; נ תס 16א0 :1 268% ; 0% 0% 0% 0% 0% 0% 26600 02 ז | 12.5 | מפות (סְבּח, כבּהוו+!טח) המחלקות ₪30 ו-קְ3מ !וו נקראות מפות, מילונים, או בעגה המקצועית: מערכים אסוציאטיביים (114/8ה 8550010146). העיקרון העומד מאחורי מחלקות אלו הוא קישור בין מילות מפתח לערכים. כל כניסה במכולה מסוג זה היא של זוג (ע66, 6). מבני נתוניס אלה אידיאליים עבור בעיות כמו המילון שראינו בסעיפים הקודמים. מפה (כְ3) המחלקה שגמ מאפשרת לחבר בין מפתח לערך, וגם לגשת במהירות לערכים לפי מפתחות. במפה יכול להיות מפתח אחד בלבד. מפתח בעל ערך מסוים יכול להופיע פעם אחת בלבד והחזרות אסורות. מפה היא מחלקת תבנית, וכשמגדירים מפה יש לספק את פרמטרי התבנית הבאים: סוג המפתח, סוג הערכים ופונקציית סדר בין המפתחות. פונקציית הסדר יכולה להיות אובייקט פונקציה שמספקת פונקציה זו. המפה מעתיקה לצמתיס שלה את הערכיס הנמסריס לה, ולכן היא מכילה העתקיס של המפתחות והערכיס שנמסרו לה. המפה גס אחראית להקצאה ושחרור של אובייקטיס הנמצאיס בה. ניתן להגדיר מפה של מצביעים. במקרה כזה, מוטלת עלינו האחריות להקצאת ציכרון למצביעים ולשחרור הציכרון. [12.5.1.1 | פונקציות חשובות הפונקציות החשובות ביותר של מפה הן בנאי המחלקה, פונקציות הכנסה וביטול של אובייקטיס ופונקציות חיפוש של מפתח. הבנאי הראשון הוא בנאי ברירת המחדל, שמקבל אובייקט המציין את יחס הסדר בין המפתחות. לבנאי יש ברירת מחדל, שהוא אובייקט יחס סדר שנוצר ללא פרמטרים. הבנאי השני מאפשר לאתחל את המפה מתחוס של ערכים נתוניס, שבמקרה וה הס זוגות המוגדריס בעזרת המבנה זוגא שלו שני שדות, ראשון ושני, המהוויס את הזוג. השדה הראשון הוא המפתח, והשני הוא הערך. (()0000826 = קתסס 000085268 ס6פמםסס) קהת ,188% *סקץ6 08106 6פתסס ,11286 *סקץ6 6מ81ט 6פתסס)סאת (()0000826 = קתסס 8266קת060 ספמסס (8< 0000826<8 ,7 ,ץ6א2>קהת 6פ5מסס) קאת 661866 >01885 711, 01888 7?1< פרק 12: מבניס שאינס סדרתיים ב-.1ז5 | 323 ] ע81ק 56206 ;150 ה ;0 72 [) (2ט)6ם8600 ,(1ט)51286 : (2ט60 72 ,1ט6 2)11נ1הס ;ן במקור, קיבל הבנאי של זוגא ייחוס קבועיס לאובייקטים. כתוצאה מכך, אס יגדירו את הזוג בדרך הבאה - ;6 6ט810ט <סַת1ע56 ,סַם1ע5% 86ם812>00 לא יוכל המהדר להסתדר עס ההגדרה הכפולה של +פחסט. לכן, צריך להמיר את הגדרת הבנאי כפי שמתואר כאן. הבנאי האחרון הוא בנאי ההעתקה שמאפשר להגדיר מפה כהעתק של מפה אחרת. בנוסף לבנאי ההעתקה, מסופק גם אופרטור העתקה המאפשר להעתיק מפה אל מפה. שניהס מוגדרים תמיד לכל מחלקה. אם המתכנת אינו מספק אותם מייצר המהדר בנאי ואופרטור העתקה. כאשר המהדר מייצר אותם, הוא מבצע העתקה רדודה, שבמקריס רבים (כמו במקרה וה) אינה מספקת. כאשר יש מצביעים, יהיו האופרטוריס שמספק המהדר אינס מספקיסם בדרך כלל. במקריס שמחלקה מכילה מצביעים, ו/או שהסמנטיקה של העתקה רדודה אינה מספקת, צריך להגדיר אופרטור השמה ובנאי העתקה. (8 2826<6ת1,00,ץ6א2>ק8ת 6פםסס)=628602קס 826<6קת1,00,ץ6א>קהת למחלקה יש מספר פונקציות המספקות איטרטורים. כאן, האיטרטוריס שמקבלים אינס מאפשרים לשנות את המפתח. הסיבה לכך היא שבמקרה של שינוי במפתח צריך להשתנות מיקוס הצמד (081) בעצ. כלומר, יש להוציא את הצמד מהעצ ולהכניסו שוב. אנו מקבלים שני איטרטוריםס. הראשון הוא כזה שמאפשר לעבור על המפה בכיוון חיובי (ממפתח קטן לגדול יותר), והשני מאפשר לעבור על המפה בכיוון השלילי (ממפתח גבוה לנמוך יותר). הפונקציה מ81ַסט מחזצירה איטרטור לתחילת המפה, והפונקציה 6926 מחזירה איטרטור לאובייקט אחד אחרי האובייקט האחרון במפה. מכיון שהאובייקטים אינס מסודרים בויכרון רציף, אין אפשרות לבדוק אס אופרטור אחד קטן מחברו, כמו שאנו נוהגיס במצביעים רגיליס. ()ם691ע 16628602 % ()ם06081 186286058 6פ5ת0ס0ס ()0ם6 16628608 % ()0ם6 18628608 6פ5תסס ()ם1ס6סע2 16628602 266286 5 ()ם20671 16028602 2006286 ס6פתסס ()0ם6ע2 16628602 266286 0% ()6ם26 16028608 20060286 ס6פתסס 4 ++-+6 ו-009 למתכנת המקצועי הפונקציה עקותס מחזירה ערך בוליאני אמת אס המכולה (המפה) ריקה, ואחרת (המכולה אינה ריקה) - ערך אפס, השקול ל-198186. % ()עסקת0 001סס הפונקציה, המכניסה צמד אובייקטיס למפה, מחזירה צמד: איטרטור וערך בוליאני. אס ההכנסה הצליחה, כלומר, לא קייס צמד עס מפתח זהה במפה, הערך הבוליאני הוא אמת (השדה השני בצמד), ואחרת הערך הוא 1186. במקרה של הצלחה - הערך הראשון הוא איטרטור המקוס בקבוצה שאליו הוכנס הצמד. פונקציית ההכנסה השנייה מאפשרת להכניס תחוס נתון לתוך הקבוצה. התחוס נתון על ידי שני מצביעים לצמדים (או זוגות). כשהמצביע השני מצביע למקוס אחד אחרי האובייקט האחרון שרוציס להכניס למפה. 2 160028000 מגה <0001ס ,812>1%628%02 6661קץ6 4טס 1162קתסס התטסעה8 8606 סם 8406 6661סצ6 // (א8 66קץ6 08106 8%ת562%)00ת1 0001 10628605 תעגה (1880 *6קץ6 6ט1הט 56ת1128%,00 *6סץ6 6מ1אט 86ת626)00פ8פת1 בנ1סט פונקציות הביטול (61950) מאפשרות לבטל אובייקטים מהמפה. פונקציית המחיקה הראשונה מוחקת את הצמד המוצבע על ידי האיטרטור הנתון לה. פונקציית המחיקה השנייה מוחקת צמד שהמפתח שלו זאהה למפתח הנתון. פונקציית המחיקה השלישית מוחקת את כל האובייקטיס בעלי מפתחות זהים לאלה הנתוניס בתחוס (11180, 18%6. (תס1נף1פסק 62856)1₪628%02 1בסט [ ;(612886)8.% תעטססע + (א 66קץ6 צ6א% ס6פתסס)62886 6סץ6 5126 (188% ע166₪28%0% ,5129% ע₪2896)1%02860 ב1סע הפונקציות הבאות מנצלות את מהירות החיפוש הגבוהה של עציס מאוזניס ומספקות פעולות שכיחות על מפה. הפונקציה ₪856 מוצאת זוג המתאיס למפתת נתון ומחזירה איטרטור המצביע אליו. אס האיטרטור המוחזר והה לאיטרטור המוחזר על ידי הפונקציה 6מ6, פירוש הדבר שנמצא זוג שמתאיס למפתח הנתון. הפונצקיה +פטסס מאפשרת למנות את מספר המופעים (אפס או אחד) של מפתח נתון במפה. הפונקציה 6מטספ ז6שס1 מחזירה איטרטור לאובייקט הגדול ביותר שקטן מהמפתח הנתון לה. הפונקציה 6מטסט זסקקט מחזירה איטרטור לאובייקט הקטן ביותר שגדול מהמפתח הנתון לה. הפונקציה 18286 60081 מחזירה צמד איטרטוריס שהראשון הוא כמו האיטרטור המוחזר מ-6פטסט זסשס! והשני הוא כמו וה המוחזר מ-6מטספ זס6קקט. :9 9 סאה // (8 68קץ6 צץ%6 86ת0)00םת51 16628605 5 (א 68סץ0 צ6א 86ם00)₪מם11 166286028 60086 % ((9א 07066 צץ6א 586ת6)00תטסס 6סץץ6 5126 (א 66קץ6 צץ%6 8%ת00)בתטסס ע6חאס1 16628602 פרק 12: מבניס שאינס סדרתיים ב-.511 | 325 0% (א 68ס0ץע6 צ6א% 86ם6)00מגסס ע6חס1 16628608 60086 (א 66קץ6 צץ%6 8%ת00)בתטסס מעסקקט 106286052 0% (א 68ס0ץע6 צ6א% 86ם6)00מגוסס עסשססט 16628602 60086 7 מ0 106020800 8128 <18628%02 ,812>16628%02 6661קץ6 פס 00001162 תטסעה8 8606 60 606 6661סע₪ // (א 66קץ5 צ6א% 8%ת06)00ם28 60081 10028602 10628605 ענהאס האיטרטור האיטרטור מתנהג כמצביע לזוגות. זוג כזה מכיל, בשדה הראשון את המפתח, ובשני את הערך. כשמשתמשים באיטרטור אסור לשנות את ערך המפתח, כי שינוי זה גורס להתנהגות בלתי מוגדרת באלגוריתמי הכנסה והוצאה של זוגות מהעא. איטרטור המפה הוא איטרטור דו-כיווני, אך אינו איטרטור גישה אקראית. לכן, איטרטור ה אינו תומך בפעולות "> או *'<יי, והוא איןו אפשרות לקדס אותו בקפיצות השונות מאחד. הקידוס של האיטרטור אפשרי רק לצמד הבא, או לצמד הקודס לנוכחי. מפה כפולה (ס3ּחז!טח) מפה כפולה (קגמגו[טם) היא מחלקה המאפשרת לקשר בין מפתחות לערכים. גם מחלקה זו היא מחלקת תבנית, כשפרמטרי התבנית מגדירים את סוג המפתחות, סוג הערכים ופונקציה (או אובייקט פונקציה) המגדירה את הסדר בין המפתחות. במפה כפולה אין הגבלה על מספר המפתחות הזהים, כלומר, מותר להכניס למפה כפולה מספר רב של צמדיס עס מפתחות זהים. כמובן שאפשר להכניס מספר צמדיםס עס אותו מפתח, אך עס ערך שונה. | 12.5.2.1 | פונקציות חשובות הפונקציות של מפה כפולה והות לפונקציות של מפה רגילה, ולא נחזור עליהן כאן. השוני הוא שבמפה כפולה אפשר להכניס מספר לא מוגבל של צמדיס הכולליס מפתח זהה. פעולת ההכנסה אינה נכשלת גס אס קיים במפה צמד בעל מפתח הזהה למפתת הצמד המועמד להכנסה למפה, ומחזירה איטרטור לצמד שהוכנס לקבוצה. האיטרטור איטרטור המפה הכפולה הוא דו-כיווני, המאפשר לסרוק את המפה בשני כיוונים: ממפתח קטן לגדול, או להיפך. האיטרטור אינו איטרטור לגישה אקראית ולכן אין אפשרות לקדס אותו, או להפחית ממנו מספר השונה מאחד. האיטרטור מאפשר להתקדם או לסגת בצעד אחד בלבד. 6 ++-+6 ו-009 למתכנת המקצועי אסור לשנות את ערך המפתח של הצמד עליו מצביע האיטרטור. שינוי ערך המפתת משפיע על מיקוס הצמד בעצ. האיטרטור אינו מונע ואת, אך במקרה של שינוי ערך המפתת תהיה התנהגות בלתי מוגדרת לפונקציות ההכנסה, או הביטול של אובייקטיס. האיטרטור מתנהג כמו מצביע, וכשמפעילים עליו את האופרטור יי*יי הוא מחזיר ייחוס לצמד הנוכתי. דוגמה - שימוש במפה כעת נציג דוגמה לשימוש במפה ובמפה כפולה. הדוגמה נמצאת בדיסקט המצורף בקוב פק61612.6. הדוגמה אינה תלויה בסוג המפה בה נשתמש. כשנרצה לשנות את סוג המפה עלינו לתקן את הפקודה 326660 כנדרש. הדוגמה עוסקת במילון (כמו הדוגמה הקודמת) שבו יש תיאור של מילות מפתח. במקרה זה, ההתאמה לדוגמה היא ישירה, מכיון שהמפה מכילה צמדים. איננו צריכים להגדיר כניסה במילון, כי היתרון של מפה על קבוצה הוא בכך שאין צורך להגדיר מחלקת עזר המייצגת כניסה במילון. המפה מבוססת על עצ בינארי, ולכן עלינו לספק פונקציה, או אובייקט פונקציה, לביצוע ההשוואה הדרושה בין אובייקטי המפה. כלומר, השוואה בין המפתחות הנמצאיס במפה. נספק אובייקט פונקציה שיבצע את ההשוואה הנדרשת. זהו אובייקט עס אופרטור הקריאה לפונקציה יי;()'י. קהתוסוטת בת8 קהת טסת1פט מתהעסס2ק 7צ82ת810%10 :12 מִססקםס // 8 0000820 ₪0 86% 6ם5 0%8+ 001606 מס661םט+ // ] ץע6ת6 0106 1658 562006 7 8מ1ע5960 56םת0ס0) () 0628602 6ם1 % (852 6ם1ע5% 0086 (()0802 82.06% ,()08%2 51.866) קת8620) םע600ת ] [ ;(0 > ;ן כדי לאפשר שינוי של התוכנית מסוג מכולה אחד לאחר, נגדיר את סוג המילון בעזרת 1 כמו כן, נשתמש בהגדרת המילון של הסוג 06ץ1 6ט1גץ כדי להגדיר בו כניסות. בדרך זו, כשמשתנה סוג המילון, משתנה גס הגדרת הכניסה במילון. כדי לשנות את שני הפרטיס האחרונים, עלינו לשנות את הגדרת סוג המילון בלבד. דבר וה נעשה על ידי הפיכת אחת משורות 106661 להערה, וביטול ההערה בשורה האחרת. כדי לאפשר פלט של אובייקטים מסוג 8חוזז5, מוגדר האופרטור הגלובלי '>>יי המקבל ייחוסיס לאובייקט מסוג 050632 ולאובייקט מסוג 8תו5₪. האופרטור מחזיר ייחוס לאובייקט הפלט, כדי שאפשר יהיה לשרשר בין פעולות פלט. פרק 12: מבניס שאינס סדרתיים ב-.1ז5 | 327 8 תת 067/60 02886 0ם צץ688 18 16 50 56061 6פט // 2 <ץע6ת6 6106 1688 ,סַת5021 ,סַת1ע5%>ק8ת 66461קץ6 2 א<צעעם6ם6 0106 16885 ,סַם1ע56 ,הַם1ע596>ק8ת1%1טת 6865סץ6// ;ץעסתס 0106 6סץעץ6 6ט1הט::106ק 6661קץ6 ץעהתס010%1 6םתם ת1 שְלפםת6 ת8 סטקפטס סם עסם8ע62סס םתא // (85 06ם1ע5%2 0086 ,80 ת(602628602>>)09%208 (05%6268 0 >> 8.066 08602)(; ;0 תע660ע ו הפונקציה 615018 מאפשרת להדפיס תחוס המוגדר בעזרת איטרטורים. הפונקציה מניחה שתכולת האיטרטוריס היא צמדים, ולכן על איטרטוריס שאינס מכיליס צמדיס נקבל שגיאה מהמהדר במהלך הידור תוכנית המקור. כעיקרון, עדיף לקבל שגיאת הידור על פני שגיאת זמן ריצה, מכיון שיותר קשה לגלות ולטפל בשגיאת זמן ריצה. %טקפטס תפט61 8 0ם 6ת11 8 םתס 1668 ג680 6180187 // <סמק6ט0 018858 ,1002 01855> 66801866 (800% 06ק006 ,0ם6 ע10₪6 ,86826 7)166%2ץ8315018 בנ1בסט ] (0םת6 =! 56826) 16נ1תט "ףףם" >> 11286. (%ע568*) >> סוס ;'ת' >> 6ם585682%6(.85600*) >> 2+ [12.5.3.2 | פונקציות קלט מספר פונקציות משמשות לקלט. הפונקציות עקסס, 60186 ו-₪1מ0 וטקמו מאפשרות קבלת כניסה ביומן מהמשתמש בתוכנית. הפונקציות עקסס ו-6ם8001 זהות לדוגמה הקודמת, ולא נרחיב עליהן את הדיבור. הפונקציה ץ₪ת6 +טקפו מקבלת אובייקט פלט, שסוגו הוא פרמטר של התבנית, קוראת שורה שלמה מהקלט, ומכניסה את השורה לשני אובייקטי המחרוזת שהיא מקבלת. 8 תעט685ע 6ת8 ת8610ת0659%1 %0ם1 6ם1ע8% 08עט50 צְקסס // .1 05 66 6ם5 6ת1ת6ס 6ת10ע2 5800206 6םת₪ 0ם ע6סת1סק // (סעפ5* 028% 5%ת00 ,086* צ8ם0)ץקסס* עַםת0ס ספםסס ו ((20ע806)*8ק155! 88 8520*) 116תט =-05017* 8 ++-+6 ו-009 למתכנת המקצועי *0856 = 0; ((18990806)*520 66 0ע52*) 116תט ;806++ 2 תעג60ע עאת6 6ת11 חס6ם 8 11סתט סגמקת1 6ם5 268695 מתס61ס6סםתט1 18ם6 // 1 18 %108טס סטקםת1 6ם6 11סתט עס // .0 1889 6ם11 חסםת 112856 6םך7 // <פ%וקת1 01855> 66801866 (8126 %ת1 ,6םת11* עהםת0 ,ם81 6טקת6)1ם66%11 בנסע ;'ת' = 1ת 8%ת0 60056 72 - 5126 + 6ם11 = ם8* עַַַם0 ; (6מ86%6)*11.ם1 (נם =! 6ם11*) +1 +7 )]) (0ת8 > 6ת11) 116תט ; (6ם86%)*11.ם1 (1ת == 6םת11*) +1 ;68%תס 1-6 ;6ת11++ ] ;0 = 6ת1ך* ץעה8תס010%1 6םם 0% צְ55ת6 6תס פס6טסת1 // .4 ₪6 תס 16 8םע2600 תה // <פוקת1 01855> 66801866 (80 6ם1ע56 ,88 סַם1ע5% ,ת81 6טסת1)ץ62ם6 סטסת1 בנסט 2 = 68126ת11 ,256 = 55126טס פסת1 שפתסס ;[66850]0018126 ,[18126טס]צ86 עַַַם0 ; [68126ת6[]11ם11 םס ; (69126ת11 ,6ת11 ,ם6)1ם06611 ; (6ת11 ,ץ6א)צקסס = 0ע5* 82ם0 005% ;(820 ,7)0680ץ56200 = 6; 6 = 02 > פרק 12: מבניס שאינס סדרתיים ב-1ז5 | 329 פונקציות עדכון למילון הפונקציות 6106 6816קט ו-+םס 6טסגוסז מעדכנות את המילון. הראשונה, מעדכנת את ההסבר הצמוד למילת מפתח נתונה, והשנייה מבטלת כניסה המתאימה למילת מפתח נתונה. הפונקציה 6166 6806קט משתמשת בפונקציית הקלט ץ6006 )קתו כדי לקבל מפתח, ותיאור שלו. אס המפתח כבר נמצא ביומן, מחזירה הפונקציה 56 איטרטור המצביע על הכניסה המתאימה, ואחרת היא מחזירה איטרטור הפונה לסוף המילון. סוף המילון הוא איטרטור אחד מעבר לאובייקט האחרון שנמצא במילון. אם נמצאת כניסה מתאימה במילון, מעודכנת הכניסה בהתאסם לתיאור הנתון. 6 01 ם610ק0690?1 6ת6 68668קט 16 .שְעפת6 6תס 6866ק0 // 68 6סת81 08עע62 ע0000116% 8 66% 18טסח טסצ .צץע6ת6 // .9 * 6 10% 02[606 96ת00 8 פםתעט68ת 16678%0% // .0% 18 16 צץ%6 6םם 6ס8קט ססם 00 ששח 06ם81 // (80 410%6)210% 68%66ק0 בנסע 27 ,צ60א 6מם5621 ;":ת610ק0089021 0םת8 צץ6א% 8 עססםת" >> סגוסס ;(₪0680 ,7ץ%6 ,ת01)ץע%2ם6 ס6טסםת1 ;601 >> 0006 ; (צ0)%6ם8.51 = 1 10%::1₪028%02כ (()06ם0.6 =! 1) +1 ; ()0852 00680.06%5 = 6ם8600. (1*) 16 ;01ת >> "תטמס ססם צְע6ם6" >> סטסס ] הפונקציה 606 6טסגת16 מקבלת מהמשתמש מחרוזת שמתאימה לכניסה עס מפתת אשר והה למחרוזת הנתונה, ושיש להרחיק (למחוק) מהיומן. ץצ8תס810%1 6ם₪ מסע+ שְע5ת6 תה פ6טסת6ץ // (80 210%)%ת6 60076ע2 16סע ;[7]64ץ6א% עַ8ם0 ;":0076ת6ת 0סם צץ%8 עססתמת" >> סגוסס ;צסא << םת1ס 12 >> 00806 ; ("" ,ץ₪6)%86 06ם1ע56 ; (06) 0.62886 0 ++6 ו-009 למתכנת המקצועי [12.5.3.4 | קלט ופלט מקבצים קלט ופלט מקבציס מתבצע בעזרת הפונקציות סמגם 1116 801, 6101 1080 ו-6101 -106/ו. שתי הפונקציות הקוראות וכותבות לקובצ משתמשות בפונקציה סגַַאּם 1116 8%, כדי לקבל מהמשתמש את שס הקובצ המבוקש. הפונקציה 6161 6וו משתמשת בפונקציה ץ8ו, כדי לכתוב את המילון לקוב. הפונקציה 016 2086 מסובכת יותר. אס הפונקציה מצליחה לפתוחתח את הקובצ המבוקש היא מבטלת את כל האובייקטיס במילון. לאחר מכן, באמצעות הפונקציה ץת6 6+טקםו נקראות הכניסות, זו אחר זו, ומוכנסות למילון. לאחר קריאת כניסה נבדק אובייקט הקלט, אם הוא עדיין תקין. הדבר נעשה כדי למנוע הוספה של אובייקט לא מוגדר, כשמגיעיס לסוף הקוב. עספט 6םם 0+ שתהם 1116 8 666 // ()סתהת 2116 666* ע8ת0 ספתסס ן ; [128]ן5טס 0282 568610 ;":סתהת 1116 ע6סם6ת" >> 006 ;+טס << םמ01 12 >> סטסס ;פטס תעט660? .1 8 ססת1 צע8ת610%10 6םתם 166מח // (80 010%)210% 166עח 16סע ; () סתהת 5116 666 = פתהת 5116* פאתס 0086 ; (6ת8ת 00%)5116 ת018%208 ;(סטס ,()20ם8.6 ,()ם601כ.4) 4150187 86 מסט61 6ם6 11 .1116 8 תסע+ צ8%ת010%10 8 2686 // פטסת1 26808 תפםם 6םת8 צץ82ת610510 6ם₪ 628868 186א6 // ססס1 1186םח 8 6ם1פט 1116 6םם 60ם1 // (80 410%)210%6 2686 בנ1סע זָ ; () סתהת 5116 966 = סתהת 5116* עהאםס 56םסס ; (סת8ת 5116)ם1 מת158%268 ,+ י(מ1) ד ;(()0ם86.6 ,()ם4.62856)0.06012 ]+ (ם1) 16נ1תט 2 ,צ860א 6ת1ע562 ; (8680 ,צץְ%6 ,ת1)ץע%2ם6 סגוסםת1 ;(0680 ,7ץ81)%6ט צְ62ם6 4106 פרק 12: מבניס שאינס סדרתיים ב-זז5 | 331 (ם1) +1 ; (81ט) 562%ת0.1 | 12.5.3.5 | פונקציות הניהול פונקציות הניהול מציגות למשתמש תפריט ומבצעות את הפקודה המבוקשת על ידו. הפקודות שהמשתמש יכול להכניס (לבחור) מפורטות בפקודה ותטתס. הפונקציה טומסגת 618018 מציגה את תפריט האפשרויות ומקבלת את האפשרות המבוקשת על ידי המשתמש. אפשרות זו מוחזרת כערך שלם לפונקציה שקראה לה. הפונקציה הראשית מוגגו קוראת לפונקציה טמסות 81813 כדי לקבל את הפקודה המבוקשת על ידי המשתמש. הערך השלסם המותזר הוא אחד הערכים המפורטים ב-ומטתס, ולפיו מתבצעת הפעולה המתאימה. כדי לבצע את הפעולה המבוקשת משתמשת הפונקציה הראשית במשפט ג8116. ,סתס צץ015018 ,סתס 6ע62פת1 ,תס 16א6 + 08תאתתסס תטתס בתס 26086 ,תס 6ס1עח ,6תס סטסת26 ,בתס 68%6סג ל סתהתתסס ₪26 פתעט60ת 6םת8 ע6פט 6ם6 60 גטמסת 8 81801879 // ()טותסת ץ815018 6ת1 זָ ;תס 16א6 = 68ע ס6ת1 ;"ת.16א6 (" >> 006 16א6% >> 0006 ;"ם. צע6ם6 חס6ם 8 8628ם1 (" >> 0מ0ס 6ע562ם1 >> סוסס ;"ת.68מ66ת00 צע8ת610610 צץ615018 (" >> חס צ015018 >> סטסס ;"ת.ץ6א% 8 0866ק₪0 (" >> 0מ0 0866ק₪ >> סוסס ;"ת.ץ%6 8 6טסת6ע2 (" >> 0מס 6טסמס6ע >> 0006 ;"ת.1116 8 0סם1 166עח (" >> 006 166עח >> סטסס ;"ת.5116 8 00סע+ 2680 (" >> 006 2686 >> 0006 0 7 <<< ם01 2 מתעגטספע בת ותפת 6ת5 018021878 10856 תסנ1פסתט+ ת1את 6םס // ע6פט 6ת₪ מסל%+ פ0תהתתסס ‏ 66 600668א6 // ()מ1נהת %ם1 2 1050 2 ,867 שת1ע56 2 ++6 ו-009 למתכנת המקצועי 0 ]1 (6תס 16א6% =! ;סתס 6ם1 ; (06850 ,7ץ81)%6ט צְע6םת6 64106 (()גמותסת 0158018 = 6תס)) 16נםתט 1+ (6תס) ם5₪160 :מס 18626 0886 "סת8 צץ%6 מססתתת" >> 0% ;":ת610ס1ע065902 " >> סגוסס 0650( ; , ()86ת010%6.6 ,ץצ%6 ,ת01)ץע62ם6 סגוסםת1 ;ץ6א = 1.51286[אע 02 = 0ת1.5600אע ; (81ט) 562%ת6106%6.1 ;68%עס :תס 015850187 0886 , () ם601. 410%6) ץ5018 1 ;01ת6 >> ; 6 0% 8 :תס 6866ק0 08586 ; (410%) 6106 6ם 6 ; סג 8 : מס 6טסתסע 0 ; (6410%) %מ6 6טס0ת20 ; 6 : חס 8 088986 6 ; (310%)0106 166עש 6 ; 8 :תס 2680 08586 > 6106 )410%( ; 6; 6 8 :תס 16א6% 0886 6 ; 1: 8 ו ;0 תמגו6%ת פרק 12: מבניס שאינס סדרתיים ב-511 3 סיכום בפרק זה למדנו על המכולות של הספרייה הסטנדרטית .511 שערוכות כעץ חיפוש בינארי. המכולות יעילות במיוחד לפעולות חיפוש שסיבוכיות הזמן שלהן היא (ם)8ס1. המחיר ש'יימשלמיס'י ביציירת עצ כזה הוא שלושה מצביעים לכל כניסה, ולכן אס הכניסות קטנות, התשלום גבוה יחסית. דבר נוסף שחייביס להגדיר הוא יחס סדר של האובייקטים שבמכולה. יחס הסדר ניתן להגדרה בעזרת פונקציה, או אובייקט פונקציה. אובייקטי הפונקציה שהגדרנו, זהיס לאובייקט הפונקציה 16858 שמסופק על ידי הספרייה (.611). המכולות המייצגיס קבוצה הן: 560 ו-16₪860שמז. הן מקבלות אובייקטים שעליהן להכניס למכולה. המכולה הראשונה אינה מאפשרת אובייקטיס כפולים (אוסף ללא חזרות), והשנייה מאפשרת חזרות של אובייקטים. המכולות המייצגות מפות הן: קְגמ ו-0ג1₪גו!ומ. הראשונה מייצגת מפה ללא חזרות והשנייה מייצגת מפה עם חזרות. מפות הן מכולות המאפשרות להחזיק צמדי אובייקטים. הערך הראשון בצמד הוא המפתח שקובע את מיקוס הצמד במכולה, והשני הוא הערך הקשור למפתח. במקרה של מילון מילים, זה תיאור המפתח. בדוגמאות שראינו היו שתי גרסאות של מילוניס. במקרה זה, האובייקטיס המייצגיס מפות קלים יותר לשימוש. גם למדנו כיצד לכתוב פונקציות גנריות המאפשרות לקרוא, או לכתוב אובייקטיס לכל פלט. הגישה הגנרית היא גישה סטטית. כלומר, הכול נבדק ונוצר על ידי המהדר בומן ההידור, בניגוד לפונקציות וירטואליות, שנקראות על פי סוג האובייקט בומן הריצה. קוד המשתמש בתבניות גדול יותר וצורך יותר ויכרון. לעומת זאת, קוד כזה מהיר יותר מקוד המשתמש בפונקציות וירטואליות. ++6 מאפשרת לנו לבחור באחת משיטות אלו, או בשתיהן. תכנות גנרי מאפשר יעילות גבוהה במהירות ויעילות סבירה בזמן. כשעובדיס בשיטה זו, יש לאכור שהמהדר יוצר קוד לכל מחלקת תבנית ופונקציית תבנית בזמן השימוש בהן. לכן, אס אפשר להגדיר חלק מהעבודה במחלקה רגילה או בפונקציות רגילות - הרוות גדול. - | 12.7 | שאלות ממש טבלת ערבול יעילה וממש את המחלקה 5% בעזרת טבלת הערבול. 2 שנה את הדוגמאות בפרק זה כך שלא יהיה צורך להגדיר בעזרת 260661 את סוג המילון. 3 שפר את יעילות הפונקציה עְכ0ס (רמז: התייחס לפעולות קידוס המצביעים). 4. ממש את הפונקציה עק60 כפונקציית תבנית. 4 ++-+6 ו-009 למתכנת המקצועי פרק 13 שילוב סוגי תכנות בפרק וה נלמד שני נושאים עיקריים: שילוב בין תכנות גנרי לבין תכנות מוכוון אובייקטים, ומתאמים (000ק808) בספרייה הסטנדרטית. בדוגמאות ששלפנו מהספרייה הסטנדרטית (.'581) עד כה, ראינו תכנות גנרי המבוסס על תבניות ++6. השילוב בין תכנות גנרי לבין תכנות מוכוון אובייקטיס הוא כלי רב עוצמה. מתאמים (408+01%) הס מחלקות המשתמשות במחלקה אחרת כדי להתאים אותה לפונקציונליות נדרשת. בספריית התבניות הסטנדרטית יש מתאמים כאלה. המונת מתאם מקובל כיוס בתכנות מוכוון אובייקטים, ולכן חשוב להכירו. בפרק זה נראה דוגמה המשלבת מתאמים, תכנות גנרי ותכנות מוכוון אובייקטים. | 13.1 | מתאמים (5וס%ק03) המתאם (%0ק808) הוא אובייקט המתאיס לממשק של אובייקט אחר כדי לממש פונקציונליות נדרשת. בדרך כלל, הוא אינו מכיל אלגוריתמיס רבים, אלא משתמש באלגוריתמיס של אובייקטיס אחרים כדי לממש את הפונקציונליות שלו. מתאמיס דרושיס לנו במספר מקרים: מקרה אחד הוא תיאוס בין ספריות שונות ומקרה אחר הוא המרת ממשק של אובייקט כדי לקבל פונקציונליות נדרשת. בסעיף זה נלמד על שני מקריס אלה. תיאום בין ספריות שונות אחד המקרים בהם נפעיל מתאמים הוא כאשר צריך לתאם בין ספריות שונות. כאשר יש שתי ספריות שונות שמצפות לקבל ממשק שונה, אנו יכולים לכתוב מתאם שממיר קריאות פונקציונליות של ספרייה אחת לאחרת. פרק 13: שילוב סוגי תכנות | 335 נניח למשל, שיש פונקציה כלשהי בספרייה קלט-פלט שקוראת קובצ ומכניסה את האובייקטים שלו לרשימה נתונה. נניח שהספרייה מגדירה מחלקה בסיסית מופשטת של רשימה, באופן הבא: ] 1018% 01858 :טס 102186)( +[ [+ ()102156-> 81ט6ענ1ט ; (* 60%[ך88₪0)1000 ב1סט 81ט6ענט ;ו ;(8 102186 ,פַתַהת1* ע8ת0 6פ5פת5116)00 2680 10 בנסט עוד נניח, שנתונה לנו ספרייה של מכולות (כמו .511) המספקת רשימה. ידוע שהרשימה בספרייה הסטנדרטית אינה מספקת פונקציה כזו. נוסף על כך, הפונקציה שקוראת קובצ מצפה לקבל ייחוס לאובייקט מסוג +,101, או אובייקט שנגזר ממחלקה זו. במצב זה אין אנו רוציס לכתוב רשימה חדשה, כי הדבר יצרוך מן כתיבה וניפוי. ניתן להגדיר את המחלקה הבאה: ] 10218% 110סמטס : 2186 018558 %2 <%*1186>61000[606 :טס 1186)( +[ (ברמס* 760%ך888)1000 בנסט [ ;(ר080%)00 ב8ט0ק.118% ) ;ן המחלקה 14% יורשת מהמחלקה 10148%, ולכן נשתמש במתאם (148) כארגומנט לפונקציה 116 1686 10. איננו כותבים קוד נוסף, אלא משתמשים בקוד הקיים. אם נרצה להוסיף פונקציונליות של הרשימה 116, עלינו להוסיף זאת בממשק המחלקה שלנו. למשל: ] 10218% 110סמטס : 2186 018585 %2 <%*1186>1000[60% :טס 1156)( +[ (ברסס* 760%ך888)1000 פנסט [ ;(ר080%)00 ב8ט0ק.1186 ) (נספס* 0806%)1000[606% פטס ב1סע [ ;((0806%)00 ב08ק.118% ) (נסס* 5202%)1000[60% מפטס 16סעט [ ;(כסס)6ת0ת5+ םמפטקש.118% ) 6 ++6 ו-009 למתכנת המקצועי הוספת פונקציות לממשק הרשימה מחייב קריאה לפונקציה המתאימה ברשימה של .1. כדי למנוע קריאות לפונקציות אלו, ניתן לשנות את המחלקה המתאמת כך: ) <*60%[ך118%>1000 110סטס ,10218% 116סטס : 2186 01855 :טס [+ ()1186 (בכעס* 760%ך888)1000 הנסט [ ;(ר806%)00ס םמפטם::<*1185%6>1000[60% ) ;ן במקרה זה, אין צורך לפרט את הפונקציות של <*11%>1000[60 בממשק של 1/18%, מכיון שהמחלקה האחרונה יורשת בצורה ציבורית מ-<*10000[90>+11. כך אנו מנצליס את העבודה בתבניות ואת עקרונות תכנות מוכוון אובייקטיסם. כשמשתמשיס באובייקט מסוג 1.1% אפשר לקרוא בעזרת הפונקציה 116 1086 10 את האובייקטיס מקובף אל הרשימה, ואפשר גס להשתמש בכל הפונקציונליות של הרשימה <*1)02020[60%>+118. ירושה מרובה יעילה כאשר אין פונקציות בעלות אותו שס לשתי המחלקות הבסיסיות. אס לשתי המחלקות הבסיסיות יש פונקציות הזהות בשמן, מוטל על המחלקה היורשת להגדיר את הפונקציה המתאימה לכל זוג פונקציות כאלו. במיוחד נכון הדבר עבור פונקציות וירטואליות. [13.1.2 | המרת ממשק אובייקט לקבלת פונקציונליות אחרת נניח, שיש לנו רשימה וכעת אנו רוציס לממש מחסנית. מחסנית (540%) היא מבנה נתוניס המכיל אובייקטים אחריס, שבו אובייקט שנמצא בראש המחסנית, הוא וה שהוכנס אליה אחרון. האובייקט שנמצא בראש המחסנית הוא גס הראשון שיוצא ממנה. נקודת כניסה וגם נקודת יציאה 2 פרק 13: שילוב סוגי תכנות | 337 שימוש ברשימה ניתן לכתוב מחסנית ללא שימוש בכל מחלקה אחרת. דבר זה נוגד את רוח תכנות מוכוון האובייקטיס. הפתרון המתבקש למצב זה הוא שימוש במחלקה אחרת, תוך כדי צמצוס הקוד שעלינו לכתוב עד למינימוס האפשרי. ניתן להשתמש במחלקה רשימה כדי לממש את המחסנית, באופן הבא : 66801866 >01858 ?1< 01858 5680% )] 2 <1186>66 :טס 5680%)( +[ (ט8 7 ספתסס)םפטס פנסט [ ;(ט)80%ס ם8טש.118% ) ()ססס 7 [ ;()א80%מ ססס.118%6 ) ;ן אם כן, אנו מממשיס את המחלקה מחסנית בעזרת המחלקה רשימה. הפונקציונליות הנדרשת ממומשת כפונקציות של שורה אחרת, הקוראות לפונקציות המתאימות של המחלקה 118%. הרשימה נמצאת בחלק הפרטי של המחסנית, ולכן אין למתכנת שמשתמש במחלקה זו כל אפשרות להשתמש בפונקציות אחרות מהפונקציות המוכרוות בממשק המחסנית. במקרה זה, שימוש בפונקציה כמו )10 בפטק יפר את תנאי המחסנית. לכן, חשוב להגדיר את האובייקט בו משתמשים, בחלק הפרטי של המתאם. גמישות במימוש המחסנית בפתרון שהצגנו יש עדיין בעיה, כי המחסנית ממומשת על ידי הרשימה בלבד. פתרון יותר טוב הוא לאפשר למשתמש לקבוע את המחלקה שמשמשת את המחסנית. בסעיף זה נכיר שתי דרכיס להשגת גמישות כזו, שימוש בירושה ושימוש בתבניות. שימוש בירושה כדי להשיג את הגמישות המבוקשת, ניתן להשתמש בירושה ובפונקציות וירטואליות. אפשר להפוך את אובייקט המחסנית למחלקה בסיסית אבסטרקטית, שיהיה לה הממשק הבא: <1? 01858> 66801866 1קת5580%1 01855 :טס [+ ()01ת5586%1 72 = (ט8 71 8%ם00)םפגס ב1סט 81ט26נט 8 ++6 ו-009 למתכנת המקצועי 2 = ()8000 7 81ט6ע1ט ?ןז <1? 01858> 66801866 ) 5080% 01888 ; [קשת1* <1>71קת5680%1 :טס (ע%ס 1סת1* <5680%)5680%1021>1 [ ;מסס 1קת1 = 1סת1 ) (צ8 71 0028%)םפגקם 18סע [ ; (ט) םפגוס<-1סח1 ) ()ססס 17 [ ;()ססס<-1קת1 םעט66ת ) 2 כדי לחסוך מקוס בדוגמה, התעלמנו מבדיקת שגיאות (למשל אס המצביע [קתג למחלקה הבסיסית אינו 11ח). כשמשתמשיס במחסנית, יש לתת לה אובייקט שיורש מהיישוס הבסיסי של מחסנית, כלומר, אובייקט היורש מהמחלקה הבסיסית ו 66801866 >01858 ?1< <1>1קת5%80%1 110סגמס : 1סת15%1ת2 01855 2 <11856>7 :טס [+ ()1סת61ספ1ת1 (ט8 7 ספתסס)םפטס פנסט [ ;(ט)א080% ם8טק.186 ]1 ()ססס 7 [ ;()א80%כ קסק.18% מעגטס6ע ) ;ו ;[קת1 <118561021>00[760% ; (1קת560%)81 <760%ך5680%>00 לפני שימוש במחסנית, יש להגדיר אובייקט היורש מהמחלקה הבסיסית המופשטת 1קנ]510, ולהעביר למחסנית מצביע לאובייקט זה. המחסנית משתמשת באובייקט כדי לממש את הפונקציונליות של המחסנית. סידור זה מעט מגושס מבחינת המתכנת המשתמש במחלקה א8180. נוסף לכך, הפונקציות מקבלות את ערכיהן בזמן ריצה, ולכן יש שימוש במנגנון הפולימורפי לקריאה לפונקציות. למרות שמנגנון זה יעיל כמעט כמו קריאה רגילה לפונקציה, עדיף לפתור ואת בצורה אחרת, אס ניתן. פרק 13: שילוב סוגי תכנות | 339 שימוש בתבניות ניתן להשתמש בתבניות כדי לממש מתאמים. בפתרון הקודם היתה לנו מחלקה בסיסית שקבעה את ממשק המחלקות שיכולות לשמש כמימוש המחסנית. כאן, נשתמש במנגנון התבניות כדי לקבוע את ממשק האובייקט שמשמש למימוש המחסנית. אס האובייקט אינו ממלא ממשק זה, נקבל שגיאת הידור. בהתאם לזה נגדיר כעת מחלקת תבנית, והאובייקט שמשמש למימוש המחלקה יהיה הפרמטר שלה. <%ע6ת%81ת00 01855> 18%66קת66 ] 5680% 01858 ;6סץם 8106ט 6קץ6 6ט810ט::עסת%81ת60 6061קץ6 ;1קת1 6%ם%681ת00 :טס [+ ()5680% (ט8 6קץ6 8106ט 58%ם00)םפטס ב1סעט [ ;(ט)86%ס םתפטקם.1סת1 ) ()ססק 6קץ6 6ט1ט [ ;()80%8ס ססס.1קת1 םע2660 ] ו המחלקה מחסנית היא מחלקת תבנית, שפרמטר התבנית שלה הוא המכולה שישמש למימוש המחלקה. סוג האובייקטים המוכנס למחסנית נקבע על ידי סוג האובייקטים שיכולה המכולה ([קגתו) להכיל. לכן, נשתמש במשפט 6061כץ1 כדי להגדיר את סוג האובייקטיס המוכנסים למחסנית, כזהה לסוג האובייקטיס של המכולה. כעת, השימוש במחסנית אלגנטי יותר ונעשה בצורה הבאה: < 12‏ <115%>00[760% >5680% 7 < <60802>600[606ט >56806% ;רפס 7606%ך00 ; (רסס) בפגוס. 51 ; (רסס) בפגוס. 582 מצב זה נוח מאוד למתכנת המשתמש במחסנית. הוא אינו צריך להגדיר אובייקט למימוש המחסנית, אלא רק להגדיר אותה. השימוש בתבניות כאן דומה מאוד לשימוש בירושה ובפונקציות וירטואליות כדי לקבוע ממשק של מחלקה בסיסית. בשני המקרים, המחלקה שאנו מפתחים משתמשת בממשק כדי לממש פונקציונליות. כשמשנים את האובייקט המשמש למימוש, אנו משנים, באופן אוטומטי, את מבנה הנתוניס ואת האלגוריתמים (הפונקציונליות של האובייקט). 0 ++-+6 ו-009 למתכנת המקצועי המחלקה א5)80 ב- 1ד5 לאחר הדיון הקודסם אפשר לראות את המחלקה מחסנית (50000) בספרייה הסטנדרטית, ולהיווכח שהיא מבוססת על העקרונות שתיארנו בסעיף הקודם. המחלקה מחסנית היא מחלקת תבנית שפרמטר התבנית קובע את מימוש המחלקה. הצהרה של מחלקה זו נראית כך: <%ע6ת%81ת00 01855> 18%66קת66 ] 8680% 01858 :טס ;6 8106ט 6סץ6 6ט810ט::62ת681ם00 6661קץ6 ;6 8126 ססץ6 62::8126ת%81ת00 6061קץ% :0 2 68ם%81ת00 :טס [ ;()עץסקת0.0 תעטסספץ + ספתסס ()צס6קת6 1ססס [ ;()0.8126 תעט60ע + 0086 ()8126 6סץ6 5126 [ ;()א0.080% םע600ע2 + ()קסס 686קץ6 6ט1אט [ ;()8א0.280% םתעט6%ע2 + 8%ת00 ()קסם 6768 8106ט 56םת0ס0 [ ;(א)8א80%ס םפטק.6 + (א 668סץ6 6ט1אט 56ת0ס0)םפטס בנסע [ ;()806% ססק.ס + ()פסס 16סצ ;ו הפונקציה ע)קנוס מחזירה ערך אמת אס המחסנית ריקה, ואחרת - ערך שקרי. הפונקציה 8126 מחזירה את מספר האובייקטים במחסנית. הפונקציה 100 מאפשרת לבדוק את ראש המחסנית, ללא ביטול האובייקט הזה. את שאר הפונקציות הסברנו בסעיף הקודס. כדי לממש מחסנית אפשר להשתמש במחלקות אלו: ז0וס6ט, +115, או 46006. לכל אחת מהמחלקות יש יתרונות וחסרונות. נזכור שווקטור הוא המתאים ביותר למימוש מחסנית. כדי להבין את הטענה האחרונה, נסביר את החסרונות של כל אחד ממבני הנתוניס למקרה זּה. למקרים אחרים כמו תור, יכולה רשימה להיות מבנה הנתוניס המועדף. לכל צומת ברשימה מוחזקים שני מצביעים, לפנים ולאחור. כשמכניסיס אובייקט לרשימה, יש להקצות צומת המכיל את האובייקט ואת המצביעיס האלה. בנוסף, יש לתחזק את המצביעים כשמכניסים אובייקט לרשימה, או כשמבטליס מהרשימה. לכן, קייס בזבוז של מקוס וזמן במימוש זה. היתרון של הרשימה בא לידי לביטוי כשצריך להכניס אובייקטים באמצע הרשימה ולא בקצוות. מבנה הנתוניס רשימה מועדף למקריס בהס יש הרבה הכנסות אובייקטיס באמצע הרשימה. תור כפול (9טף66) דומה לווקטור, אך יש לו פונקציות המאפשרות הכנסת אובייקטים משני צידיו. יש לטפל בשני המקריס (הכנסה בתחילת התור או בסופו), ולכן יש צורך בעבודת ניהול נוספת, לה איננו וקוקים במקרה המחסנית. במחסנית מכניסים פרק 13: שילוב סוגי תכנות | 341 אובייקטיס רק לסופה ומבטליס אובייקטיס רק מסופה. בנוסף, לתור כפול יש מפת בלוקיס (ראה פרק 11), דבר שאינו קייס במחלקה וקטור. תור כפול מתחזק את מפת הבלוקיס, יש על כך תשלוס (קטן אמנס) בזמן, ולכן מבנה הנתוניס האידיאלי הוא וקטור. המחלקה וקטור יעילה מאוד בהכנסה והוצאה של אובייקטים לראש הווקטור. למחלקה זו אין מפה, ולכן אינה וקוקה לזיכרון נוסף כלשהו. מבנה הנתוניס המועדף למחסנית הוא וקטור. | 13.2 | דוגמה - ניהול משימות (3565)) בסעיף ה נראה דוגמה המשתמשת במחסנית ומשלבת ירושה ופונקציות וירטואליות. הדוגמה תכלול אוסף פעילויות אותן יש לבצע. כשניתנת הוראה לבצע את הפעילויות האלו הן מתבצעות, והאוסף שמכיל את הפעילויות מנוקה (הפעילויות בו נמחקות). הדוגמה עצמה מופיעה בקבצים : קְט6.6מְג6ג, קק35%.6+, [.88%+. היררכיית הפעילויות כדי לאפשר גמישות למערכת התוכנה המטפלת בפעילויות אלו, נגדיר מחלקה בסיסית שמייצגת פעילות בסיסית, 188%. קוד המחלקות המייצגות פעילויות נמצא בקבציס 88%.[1+, ק88%.0). המחלקה אפג8ד המחלקה 198% היא מחלקה מופשטת שמשמשת להגדרת ממשק שינוצל על ידי שאר חלקי התוכנה. בהגדרת מחלקת ממשק כזו אין צורך ששאר חלקי התוכנה ידעו על סוגי פעילויות שונים, כלומר, על אובייקטיס היורשיס מ-188%. הדבר מאפשר למתכנת אחר להוסיף סוגי פעילויות אחריס מבלי לשנות את החלק העיקרי של התוכנה. המחלקה 19%% מגדירה פונקציה 40% המשמשת לביצוע פעילות ה-198%% הנוכתי. המחלקה מגדירה פונקציות לכתיבה, או קריאה, של פעילות מאובייקט פלט, או קלט מסוג נ0517168 או בת180708, בהתאמה. פונקציה נוספת המגדירה מחלקה זו היא הפונקציה 16806ס, המכונה לעיתיס בנאי וירטואלי (5000000תס6 081וו). כזכור, השפה אינה תומכת בהגדרת בנאיס וירטואליים, ולכן, כדי ליצור אובייקט בצורה וירטואלית עלינו להשתמש בפונקציה וירטואלית, היוצרת אובייקט שזהה בסוגו לאובייקט קיים. כשנשתמש בפונקציה כזו לא נצטרך לדעת את סוג האובייקט, אלא רק להשתמש בפונקציה כדי ליצור אובייקטיס. 2 ++6 ו-009 למתכנת המקצועי 01858 88% ] :טס [+ ()785% 2 = ()0016 סת1 81מ6ע1ט 72 = (6006 ת166)08%268עח ב1סט 81ט6ע2נט 2 = (ם61 ת880)15%208ת2 ה1סט 81מ6ת1ט 7 = ()020806* 788% 81מ6ע2 בט המחלקה 600/51!6785% מחלקה היורשת מהמחלקה הבסיסית ומייצגת פעילות כלשהי היא המחלקה %, אשר מעתיקה קוב מקור לקוב יעד כלשהו. המחלקה מכילה שני אובייקטיס מסוג 8מו5₪ המכילים את שמות הקבצים שעליהם היא פועלת. בנאי המחלקה מקבל את שמות הקבציס אלה, ומאתחל את האובייקטיס 86 ו-680 לשמותיהם. % 5116 צְ600 // ]) 788% 110סטס : 116185%עץ002 01855 סתהת 5116 808206 // 2 ש6ם5621 סוהת 1116 מתס1פא8ת368%1 // 7 ש6₪ם5601 :טס ;(8* 028% 58%ת00 ,0* ע8%ם0 56ת00ס)116185%עץ000 ;()₪016 6ם1 ; (0%6ו 860‏ ת166)08%2068עח ב1סטע ; (מ61 ת26806)15%268 בנ1נסט [ ;("" ,"")א116785%תץק00 חסם מעטספע + ()026866* 785% ל הפונקציה 601% מגדירה שני אובייקטי קלט/פלט, ו ו-+שס, המייצגיס את הקבציס המבוקשיס. היא מעתיקה תו אחרי תו מקובצ המקור לקובץ היעד. פעולה זו יקרה (כי כל תו נקרא ונכתב) כאשר היא מופעלת על קבציס ארוכיס במיוחד. אני משאיר לקורא את חיפוש הדרך לשיפור פעולה זו. % ססםס 6ע5 05 צְ000 806081 6ם6 60 // ()116788%::001%ע7ץ000 %6ם1 ;(()0862 820.06%)ם1 מ158%268 ;(()0852 0₪6)08%.86%6 ת(68ע055%62 ;7 שפםס (%טס 8668 ם1) 15 ((86%)0.םת1) 116תט ; (0) סגוסן. >גוס 12 תעמ6ס6ע2 פרק 13: שילוב סוגי תכנות | 343 הפונקציה שו מאפשרת לכתוב את האובייקט לקוב, כך שאפשר יהיה לשחזר ממנו את אוסף הפעילויות במועד מאוחר יותר. הפונקציה כותבת את שמות הקבציס המעורבים בפעולת ההעתקה. ת68ת5ה תסט1 6םת6 0ספםת1 688% 66 1668סח // (6009% ת2166)05%208א::116788%ע0007 הנ1בסט ()08%2 08%.06%6 >> 580806 >> ()0882 8520.06% >> סגטס ;1167 שסם >> ו הפונקציה 1686 קוראת את שמות שני הקבצים מתוך אובייקט הפלט שניתן לה. תחילה היא קוראת את המחרוזות לחוצצ בגודל מתאים, ולאחר מכן היא מעתיקה אותו לאובייקט חיעד. גם פעולה זו ניתנת לשיפור, אשאיר ואת לקורא כתרגיל. %טסתו 1208 688% 66 26868 // (ת81 ת116788%::26806)15%208ע0007 %נ1בסט ;[512]+טס 6088 ;טס << ם1 2 = 0ע5 ;טס << ם1 ;פטס = 686 המחלקה א85ד6/ המחלקה 01898%/ מאפשרת לספור את מספר התווים, מספר המילים ומספר השורות בקובץ נתון. מחלקה זו מבצעת פעולה דומה לפקודה 6 ב-א1א11. המחלקה שומרת באובייקט מסוג 8ת1ז50 את שס הקובצ שעליו יש לפעול. % שת1סתטסס הפס // ]) 788% 110סטס : 67858%א 01855 סתהת 1116 // ;סתהת+ 0מם5621 :טס ; (ם1* 028% 6פת0785%)00ח₪ ;()₪016 6ם1 ; (6090% ת166)08%268עח 16סט ; (ת61 ת680)15%2068ע2 ב1ס [ ;("")א6788%חא חסם םע2660 + ()026₪866* אפַ7 ;ן לא נראה את קוד הפונקציות של המחלקה. הקורא מוזמן לבחון את הקובף קק85%.6+ שבדיסקט, כדי לקבל פרטיס מלאים על הפונקציות שלה. הפונקציה ‏ 401 סופרת את התוויס, המיליס והשורות בקובץ המבוקש. הפונקציות 1080 ו-סואי כותבות וקוראות אובייקטיס של מחלקה זו. הפונקציה 610806 יוצרת אובייקט חדש מסוג 6788%/ט. 4 ++-+6 ו-009 למתכנת המקצועי מנגנון יצירת האובייקטים כשכותבים אובייקטים לקוב משתמשים במצביע לאובייקט נוכחי ובפונקציה וירטואלית כדי לכתוב אותו. מצב זה אינו קיים כשקוראים אובייקט מקובצ. כשקוראיס את הקובץ, נתון רק שס המחלקה של האובייקט. לפי שס המחלקה יש ליצור אובייקט מתאיסם ולקרוא אותו בעזרת הפונקציה 1084 של האובייקט החדש. אס תיצור התוכנה אובייקט לפי שס אובייקט נתון, היא תכיר את האובייקטים ולכן לא תהיה גמישה ואי אפשר יהיה להרחיב אותה. לכן, עלינו ליצור מנגנוו שיאפשר הוספה קלה של סוגי אובייקטיס חדשים. המנגנון ליצירת אובייקטיס ממומש על ידי המחלקות 1/161806:1888 ו- 60101 01888. המחלקה 6%4801!355 מחלקה זו מאפשרת לקבל מידע אודות האובייקט וליצור אובייקטים חדשים מסוג האובייקט שאליו היא מתייחסת. כוכור, המחלקה 1/0 6+ מחזירה את שם המחלקה של אובייקט נתון. היא מוסיפה את שירות ייצור אובייקטים של אובייקטים ממחלקה נתונה בזמן ריצה. מחלקה זו שומרת מצביע לאובייקט מסוג 145% שבעזרתו היא תיצור אובייקטיס חדשים בעת הצורך. בנוסף, נשמר שס המחלקה של האובייקט בשדה סַַאמ[ס. שס המחלקה של האובייקט מתקבל על ידי הפעלה של האופרטור 7616 המחזיר ייחוס לאובייקט מסוג 10חו 6כע. קריאה לפונקציה סַתִגּת של אובייקט זה, מחזירה את שס המחלקה של האובייקט 14%8%. ] 650801888 0185855 % + 785% ; 6ת8ת01 06מם56%21 :טס ) 801855 סא ;: = 088% ] () 66801858 [ ;0 = 688% ) [ ;(0 : ()020866<-6885% ? 688%) מעטס6ע + ()0260866* 785% (()סתהת. (610)*%6סץם) פתַת01 : (6>* 788% ] % (()פת8ת* ע8םת0 0056 [ ;()0862 6.066ת(8ת61 מעגוס6ע 1 לן שס המחלקה של האובייקט משמש אותנו בקריאה ובכתיבה. בכתיבה, כדי להוסיף לכל אובייקט את שס המחלקה, לפני תכולת האובייקט. בעת קריאת אובייקטיס משתמשיס בשם המחלקה כדי ליצור את האובייקט המתאיס בקריאה. פרק 13: שילוב סוגי תכנות | 345 המחלקה זס)ס6ע 0|355 מחלקה זו היא מכולה של אובייקטים מסוג 16)861858א. האובייקטים שנמצאיס בווקטור ה הס אלה שהתוכנית מכירה ויכולה לכתוב, או לקרוא מקבציסם. מחלקה זו מכילה וקטור של ,511 המשמש להחזקת האובייקטים 1/61801858. ) עססס6שט 01888 01888 2 <60%02>16680188589ע ;()01888068 16ת1 16סט :טס [ ;()60188868 1%ם1 + ()602ס6ט 018588 ; (תםת* 0282 8%6ת020866)00* 785% (ק%* 01885)7188% 806 16סע [ ;((ק0806%)6%801855)5 םפגק.60 - ) ;ו הפונקציה 01888 18 מוגדרת כך לשס הנוחות. היא יוצרת שני אובייקטיס מסוג א ו-א0785)/, ומכניסה אובייקטים מסוג 16401888 הקשורים אליהם. היינו יכוליס לוותר על פונקציה זו, ולאפשר למשתמש בתוכנה להוסיף את המחלקות שהתוכנית משתמשת בהן בעזרת הפונקציה 01888 800. ()01888568 16ת02::1ס6ס6ט 01888 בנסע ו ;"" = 11גמת ספתסס* 0282 ס6פמתסס ; (11טם ,11טת)72116188%ץ002 חסם = ס>* 785% ; ( (ס5) 658061888א) 086% מפגוק. ססט ; (11גות) 0185%א שסם = סם ; ( (ס5) 6%8061888א) 086% מפגוש. ססט ו הפונקציה 0208466 מאפשרת ליצור אובייקט חדש לפי שס המחלקה שלו. הפונקציה מקבלת את שס המחלקה של האובייקט החדש המבוקש וסורקת בלולאה את הווקטור ויוצרת את האובייקט הראשון בעל שס מחלקה המתאיס לשס הנתון לה. אס לא קייס אובייקט כזה מוחזר אפס, כלומר, מצביע ריק. 8 6שעט61 8 01% 001606 ם8 0268668 // (6תהת* 0282 86ת2::026866)00ססס6ט 01858* 785% ו ;()ם60.0601ט = 1 ע760602>06%801855<::1662800% + (()6ם6.ס6ט =! 1) 16נותשט (0 == (ס6תהםת ,()פתַם. (1*)) קת5620) +1 ;()1(.026866*) תעט6ס6ע ל ] ;0 ת6%00ע2 6 ++6 ו-009 למתכנת המקצועי לב המערכת - אוסף המשימות לב המערכת והמנהל שלה הוא המחלקה [18%%601, שמכילה את המשימות (4888)) שיש להפעיל. לעיתים מכניסם את המשימות בשס תהליכים. מחלקה זו מכילה אוסף משימות מסוג 5/80%. בנוסף, מכילה המחלקה וקטור של 64801888]/א, כלומר 01888. המחלקה [188%001 יורשת מ-188% ולכן ניתן להגדיר אוסף פעילויות לביצוע, ולהכניס אותן למחלקה 18860011 אחרת! דבר ה מאפשר להגדיר, בצורה רקורסיבית, פעילויות שמכילות פעילויות אחרות. צורה זו של ירושה היא תבנית עיצוב (מזס)וק מ40818). שיטת עבודה זו טובה כשצריך להגדיר מחלקות המכילות מחלקות בסיסיות, ויחד עם ואת יורשות ממחלקה בסיסית. דוגמה לתבנית עיצוב יכולה להיות תפריט, שבו יכולות להיות שורות שהן תפריטים אחרים. לכן, ניתן להגדיר שתי מחלקות: ומ6טםס]/ ו-טתס]א. המחלקה האחרונה יורשת מהמחלקה 16001663 ומכילה מספר רב של מחלקות מסוג 1)6טגות6]ש. דוגמה אחרת לתבנית עיצוב היא קובצ וספריית קבציסם. ספריית קבציס היא קובצ המכיל קבציס אחרים. אני משאיר לקורא המעוניין את פתרון בעיית הקבציס והספריות. ) 788% 110סמטס : 7188%0011 018588 5680%>060602>188%*< < 88%8; 27 מ6000₪ 01888 :טס 788%0011)( +[ ;()₪016 6ם1 ; (600% ת166)05%208עח בנ1נסט ; (ת61 ת2686)18%20608 ב1סטע [ ;()185%80011 חסת מעטס6ע + ()026866* 785% (ק* %85%)785% 806 16סעט [ ;(ס)בפוק.688%5 ) ; (תם* ע8ת0 86ם5116)00 166עח ב1סע ; (תת* 0282 5%ת5116)00 26806 6ת1 ;ן הפונקציה 80% מבצעת את כל הפעילויות שבאוסף הפעילויות. היא פועלת בלולאה על מחסנית הפעילויות עד שהמחסנית מתרוקנת. בכל שלב של הלולאה נשלף אובייקט אחד מהמחסנית ונקראת הפונקציה 60% של האובייקט, ולאחר מכן משוחרר האובייקט. הפונקציה ק%0 מחזירה ייחוס לאובייקט שבראש המחסנית, ולכן יש לבדוק שהמחסנית אינה ריקה לפני שמשתמשים בפונקציה. הפעלת הפונקציה על המחסנית ריקה אינה מוגדרת ובמקרה הטוב התוכנית תופסק. במקרה הרע, תמשיך התוכנית לפעול, אך בצורה מוזרה ובלתי מוגדרת. פרק 13: שילוב סוגי תכנות | 347 ()7185%0011::9001%6 6ם1 7 = ם שם1 + (()עץ6קת5₪85%5.6!) 116תט ; ()00ס.685%8 = סם* 785% ; () 1%ססף<-60 ;ת++ ;סקס 061666 ; () ססס. 588%8 ] ;םת מע%ע660%0ת2 ו הפונקציה פוש מאפשרת לכתוב את הפעילויות המבוקשות לתוך אובייקט קלט. כמו הפונקציה הקודמת, כך גס זו פועלת בלולאה על כל פעילויות המחסנית. בכל שלב של הלולאה נשלף האובייקט בראש המחסנית ונכתב לאובייקט הקלט הנתון לפונקציה. כשנכתב אובייקט לקוב, נכתב תחילה שס המחלקה של האובייקט, ולאחר מכן האובייקט עצמו. שס המחלקה של האובייקט משמש לאחר מכן בעת קריאת הקוב, ליצירת אובייקט מתאים. .ת68ת55 ת6ט61 8 0סם1 ת001160810 588% 6ם6 1668מח // (800% ת168)08%2068עח::7185%0011 ב1סטע + (()עצ6קת5₪85%88.6!) 116תט ; () סס0ם.685%5 = סם* 785% 7 >%6>> ()פתאם. (ס+*)618סץ6 >> סגוס ; (6גו0ס) ₪6 1משט<-ס6 ;סק 061666 ; () ססס. 588%5 ו הפונקציה 116 16זאו מכינה את אובייקט הפלט ומחברת אותו לקובץ המבוקש. אס פתיחת הקוב הצליחה, נקראת הפונקציה הקודמת עם אובייקט הפלט. (תם* ע8ת0 86ם5116)00 2166ח::1785%0011 בנסעט ; (תם) 6ס ת058%2068 (סטס) +1 ; (6ג01) 66 נעשט ו הפונקציה 16806 פועלת בלולאה כשבכל שלב היא קוראת את שס המחלקה של האובייקט הנוכחי. הפונקציה בודקת אס יש מחלקה עם שס המתאים לשם שנקרא מהקובץ. אס אכן מוחזר מצביע לאובייקט חדש שנוצר כתוצאה מקריאה לפונקציה 6 של 6000 01855, נקרא האובייקט מהקלט ומתוסף לאוסף הפעילויות לביצוע. 8 ++-+6 ו-009 למתכנת המקצועי (מ61 ת185%0011::2680)15%268 1בסט ]+ (ת1) 16נתט ; [128] סתאת שַַַת0ס ;סח8םת << ם1 (ם1!) 15 ;268% ; (סַתַהַת) 60.0268%60ט0ס = סם* 785% 1 |( ד ; (ם2680)1<-ס6 ; (ק%)%685% 800 ו הפונקציה 416 1086 מגדירה אובייקט קלט הקשור לקוב הנתון. אם האובייקט תקין, כלומר, הקוב המבוקש קיים והאובייקט הצליח לפתוח אותו, אזי הפונקציה משתמשת בפונקציה 68 כדי לקרוא את הקוב. (תם* ע8ת0 86ת00ס)5116 785%0011::2680 6םת1 ; (תת) 1 ת1+8%268 07 = 2659 6ם1 + (ם1) +1 2 = 68ע2 ; (ם1) 268086 ] 2682 מעגו66ע פונקציות הניהול פונקציות הניהול כוללות את הפונקציה הראשית של התוכנית ופונקציות עזר, המאפשרות לקרוא פרטים מהקלט הסטנדרטי של התוכנית. הפקודות שהתוכנית מאפשרת הן: הוספת פעילות, ביצוע אוסף פעילויות, כתיבה או קריאה של אוסף פעילויות מתוך קובץ. פקודות אלו מפורטות בפקודה נעטפס הבאת: ,הבמס 4016 ,6ת0ס סט 860 ,תס צקסס 8600 ) 58תהתתסס תותס ;[ שתס 16א6 ,6תס 166עח ,תס 2680 הפונקציה טמסו ץ18013 מציגה תפריט למשתמש הכולל את הפקודות שמבצעת התוכנית. פקודות אלו מפורטות בפקודה גוטתס הקודמת. הפונקציה מחוירה את האפשרות שנבחרה בתפריט. פרק 13: שילוב סוגי תכנות | 349 ()טותסת 315018 6םת1 ָ 2 סת1 ".688% 5116 צשְקסס 8 8686 (" >> תס צקסס 800 >> סטסס ;116 שסם >> ".688% שְַם1סתטסס בעסט 8 860 (" >> בתס סש 860 >> סטסס ;116 שסם >> ;1 שסם >> ".688%88 מע250סק (" >> תס 8016 >> סטסס ".5116 8 תסעא5 688%8 2086 (" >> תס 2086 >> סטסס ;116 שסם >> ".5116 8 0סם 688%8 166עש (" >> 6תס 166עש >> סטסס ;6ת11 שסם >> 12 שסת >> ".16א6% (" >> 6ת0 16א6% >> סטסס וס 87 << ם01 162 שסם >> 0006 87 מעשט6סע ו הפונקציה 885% צעקסס 8066 מוסיפה פעילות מסוג 7116195%/ק60 לאוסף הפעילויות הנתון לה. היא קולטת מהמשתמש את שמות הקבציס המבוקשים, יוצרת פעילות חדשה ומכניסה אותה לאוסף הפעילויות. (80011 6885%)7185%0011 צְקסס 800 בנסט ; [256] 62ת8ת , [256] נפתהם מַהַםס ;" :ת8510ת06₪561 6ם8 800206 ע6סתספת" >> סגטסס ;2סתת << 61ַת8ם << םת1ס ; ( (61ת8ת ,2סַתַהת)1167188%ע7ץ000 חסםת)א688% 0011.860 ] הפונקציה סמַַגת 86 מאפשרת לקלוט שס מהמשתמש, אל המערך ש6נמגם. מערך וה מוגדר כסטטי, כדי שימשיך להתקיים לאחר חזרת הפונקציה. אחרת היה המערך מוגדר במחסנית התוכנית, והיה נעלס כשהפונקציה היתה חוזרת. הגדרת מערך, או אובייקט אוטומטי כלשהו והחזרה שלו כתוצאה של פונקציה, היא באג שכיח של מתכנתיס רבים. תוכנית המבצעת פעולות כאלו מגלה התנהגות מוזרה בדרך כלל, כי באגיס אלה אינס קלים לגילוי וזיהוי. (6קתסעק* 0282 86םסס6)פת8ת 66ש* 0282 ו ;[512] פתהת ע8ת0 568610 2 סע >> 6ת11 חסם >> סטסס ;סתהת << מ01 ; סותהת מעגו60ע 0 ++6 ו-009 למתכנת המקצועי הפונקציה 188% סא 8066 מוסיפה פעילות מסוג 6198%/ לאוסף הפעילויות הנתון. שס הקובצ הקשור לפעילות זו מתקבל על ידי קריאה לפונקציה 6הזגח 8%. (80011 685%)785%0011 סח 800 בנסעט זָ ;(":סתהת 5116 מסס6םת6")סתהת 076% = סתהת* מַה8ת0 ; ( (סתאת) 0185%ח₪ חטסםת)%68585% 0011.860 1 הפונקציה הראשית של התוכנית פועלת בלולאה, שבכל שלב שלה מוצג למשתמש תפריט של פעולות אפשריות בעזרת טתסגג 818018. הלולאה מסתיימת כשהפונקציה טומסגת 18018 מחזירה את הערך 6מס 1א6. בשאר המקריס הפונקציה משתמשת בפונקציות אחרות שהוגדרו בקוב>, כדי לבצע את האפשרות שנבחרה מהתפריט. ()תנאת 6ם1 זָ ;68588 0011א788% ; סתהת* 08% ;מס סת1 1 60 ; () טתסת צ818018 = 6תס + (6תס) ם160א5 :תס א 800 08586 ; (688%)68888 סש 8006 ;2% :תס צ000ס 800 0856 ; (%8888)א685% שְק60 8006 ;2% :תס 0016 0886 688%8.001%6)( ; 28%; :תס 166ע 0886 ; (":סתהת 5116 ס6טקסטס ע6ס6םס")סתהת 766 = סתהת ; (סתהַת) 5116 166ע.6858%5 ;268% :תס 2680 0886 ; (":סתהת 5116 ס6גמקת1 ע6ס6םתס6")סתהת 766 = סתהת ; (סת8םת) 1116 688%8.2086 ;268% 1: 28%; ] ; (0ת6 1%6א6 =! תס) 16נ1תשח [ ;0 תעגו6%ע2 פרק 13: שילוב סוגי תכנות | 351 לסיכוס, התוכנית מאפשרת לבצע דבריס רביס: להוסיף פעילויות, לכתוב אותן לקוב, או לקרוא אותן מקובצ. התוכנה המטפלת בפעילויות היא גנרית, לכן אפשר להרחיב את המערכת בצורה קלה עס סוגי פעילויות אחרות (ראה תרגיליסם). כדי להרחיב את המערכת בפעילות נוספת יש לגזור את הפעילות החדשה מהפעילות הבסיסית ולהוסיף את האחרונה למחלקה 60101 01888. | 13.3 | סיכום בפרק זה למדנו כיצד לשלב תכנות מוכוון אובייקטים (8מונמנת8זפסזק 06)תס1זס 601[טס) עס תכנות גנר* (פהוותותגזפסזק 6110ת86) המבוסס על תבניות (18/05ק1ת9?). שני כליס אלה הס בעלי עוצמה רבה וכשמשלביס את שניהס מתקבלת האפשרות לכתוב מערכות גנריות שאינן תלויות בסוג האובייקטים עליהן הן פועלות. מונח אחר שלמדנו בפרק זה הוא מתאם (4040)0). מתאס מאפשר לשנות את הממשק של אובייקט מסויס לממשק אחר. כך אפשר להשתמש בפונקציונליות של האובייקט המתואס במערכת המצפה לממשק אחר. שימוש אחר של מתאמיס הוא יצירת ממשק חדש מפונקציונליות נתונה של אובייקט אחר. למשל, יצירת מחסנית יכולה להיות ממומשת על ידי רשימה, וקטור או תור כפול. אס נאפשר לממשה על ידי אחד מאלה, לא נצטרך לכתוב קוד נוסף של מחסנית. אפשר להגדיר את היישוס של המחסנית על ידי מחלקה בסיסית, ולהגדיר מספר מחלקות שונות לכל יישוס שהוא. כשמגדירים אובייקט מחסנית יש למסור לו את היישוס שמתכוונים אליו. אפשרות אחרת, עדיפה במקרה זה, היא לאפשר למתכנת המשתמש במחלקה מחסנית, לקבוע את המימוש על ידי פרמטר של תבנית. הדבר מבטל את המנגנון הפולימורפי, ואת הצורך בירושה. ראינו בפרק וה שילוב בין תכנות גנרי לתכנות מוכוון אובייקטיס. יצרנו מערכת פולימורפית שהשתמשה בפונקציות גנריות המבצעות אוסף פעילויות. המערכת גמישה וניתנת להרחבה על ידי הגדרת פעילויות חדשות, היורשות מהפעילות הבסיסית. - | 13.4 | שאלות ממש תור בעזרת מכולה אחרת כלשהי של ,511. האס אפשר לממש את המחסנית בעזרת וקטורז 2 למתכנת המשתמש בתור מהשאלה הקודמת, באיוה מבנה נתונים היית ממליצ להשתמש למימוש התור!י 3 שפר את הפונקציה 804 של המחלקה 771161885%ק00 (החיסרון של פונקציה זו הוא הקריאה של כל תו בנפרד, שפירושו קריאות רבות לפונקציה). 2 ++6 ו-009 למתכנת המקצועי 4 הפונקציה 1686 של א0007116185% גורמת לשתי העתקות. אחת לחוצצ מקומי ואחת לזיכרון פנימי של המחלקה 8פו5. שפר פעולת קריאה מהמחלקה 8מ5₪1 באופן כזה שלא תהיינה שתי העתקות. 5. ממש את התוכנית המטפלת ב-18%8%%8 בעזרת התור מהשאלה הראשונה. 6. הוסף פעילות של ספירת מספר הקבצים בספרייה נתונה למערכת של פרק וה. איזו פונקציה עליך להוסיף למחלקה [001א18%%, כדי לאפשר תוספת קלה של אובייקטיס, מבלי לשנות את הפונקציה 01858508 1816. פרק 13: שילוב סוגי תכנות | 353 נספח דיסקט התוכניות המצורף לספר מה בדיסקט בדיסקט המצורף תמצא : >= תוכניות שהדגמנו בספר * ספריית תבניות סטנדרטית של ++6 בשם .511 התקנה הכנס את הדיסקט לכונן 4 או ם. הפעל את קובא 51.41.1א1 מהדיסקט המצורף 1 <:8 או 125%411<:ס אס אתה נמצא ב- 95 0₪5ס4מו/ או ב-3.11 שסשמםנ/ - לחץ לחיצה כפולה על שס הקוב> ,51/41.1א1 (בסייר 8שס6מו/ או במנהל הקבציס, בהתאמה). ההתקנה פותחת את הספרייה 672706 בדיסק הקשיח ומעתיקה אליה את התוכניות ואת הספרייה ,511 שבדיסקט. הרצה - כללי אפשר להריץ את התוכניות במהדר בורלנד מגירסה 4 ומעלה, או במהדר מיקרוסופט ++6 1031/ גירסה 4.2 ומעלה. את התוכניות שבספר, ואשר חלקן נמצאות בדיסקט, ניתן להדר ולהריצ תחת חלונות, או בסביבת העבודה של 505. נספה | 355 שפת ++6 אינה תלויה בסביבת העבודה, ולכן התוכניות שבספר זה יוכלו לפעול בכל סביבה שבה יש מהדר ++6 מתקדם מספיק. לתכנות והידור התוכניות השתמשנו בשני מהדרים: במהדר בורלנד גירסה 4.5 והשתמשנו גס במהדר של סאן (פט5) גירסה 4.2. בנספח זה נסביר כיצד אפשר להדר את התוכניות בשתי סביבות העבודה האלו בעזרת כלים המסופקים על ידי חברת בורלנד. הידור והרצה תחת חלונות עבור ל-11608/. כדי להיכנס לסביבת העבודה של בורלנד בחר בעזרת העכבר את הסמל המתאיס במנהל היישומיס או בשולחן העבודה. מו הגדרת פרויקט בסביבת הפיתוח של בורלנד בחר מתפריט 10[60/ את הפריט 210[6 ששאאז. כתוצאה מבחירה זו מתקבל תת-חלון שבו יש להקליד את שם הפרויקט המבוקש. נניח שאנו רוציס להריצ תוכנית פשוטה, כמו זו: <םת.ת1085%208> 61006ת1+ ()מ1נהת %ם1 | 12 >> "16עסח חאס611םם" >> סטסס 12 תעג66ת ו נניח ששס הפרויקט שלנו הוא 1610. לפיכך, שס הפרויקט המלא (כולל שס הנתיב) יהיה למשל: 6 ;20 סקס : 6 שם ה-19786 מתעדכן באופן אוטומטי כאשר תקליד את שס הפרויקט, ובמקרה זה הקלד 1610. בתת-החלון בחר את סוג המטרה (06ץ1 18786). מכיון שזו תוכנית פשוטה שאינה משתמשת בספריית האובייקטיס לחלונות, בחר: םנ/ץ88ת. את שאר האופציות ניתן להשאיר לפי ברירת המחדל. לאחר מכן בחר ע1קק84 בעזרת הלחצן השמאלי של העכבר. תת-החלון יעלם ויופיע חלון הפרויקט, שיכיל את השם 6110.0. ניתן לבטל או להוסיף קבציס לפרויקט על ידי בחירה של פריט בחלון הפרויקט ולחיצה על הלחצן הימני של העכבר. כתוצאה מלחיצה זו יופיע תפריט שקיימיס בו מספר פריטים וביניהסם פריטיס שמאפשריס להוסיף או לבטל קובצ: 66סצ1 4.06, 6 1261606 כדי לבטל את הקוב 16110.6 בחר את הפריט 66סא 61666. כדי להוסיף את הקוב קכס.16110 לחץ על הלחצן הימני של העכבר בתוך חלון הפרויקט. לחיצה זו 6 ++6 ו-009 למתכנת המקצועי תעלה תפריט שיכלול 66סצ1 66/. בחירה של פריט וה מאפשרת להוסיף שם קוב, למשל ססס.16110. לאחר הוספת הקוב יופיע פריט בשס מס16110.0 בתת-חלון הפרויקט. שתי לחיצות מהירות על הלחצן השמאלי יפתחו חלון עס עורך שבו תוכל להקליד את התוכנית. לאחר עריכת התוכנית תוכל לפנות להידור התוכנית. הידור התוכנית לחץ על הלחצן השמאלי של העכבר כשהסמן נמצא על תפריט 0[600זע. כתוצאה יוצג תפריט המכיל את הפריט [41. 80116. בחירה של הפריט האחרון תבנה את הפרויקט. הרצת התוכנית בחר בתפריט 26008 והפריט מות. לחילופין, תוכל להריצץ את התוכנית על ידי פניה לחלון 888807 נתגזפסיוק, בחירה של תפריט 716 ופריט ...פטח מתוכו, תקבל תת-חלון שבו יש להקליד את שס התוכנית והארגומנטיס שלה להרצה. לאחר מכן לתצ על לחצן 0% לאישור הפעולה. הידור והרצה בסביבת 208 5 להרצה בסביבת 2005 תמצא בדיסקט את הקוב 8%61116ו₪, אשר מכיל פקודות לבניית יישוס (₪8%06). חוקים בסיסים של ₪366 . שים לב! החוקיס המתואריס כאן הס עבור היישוס 38%6/ של בורלנד! בקוב 886 אפשר להגדיר מקרו בצורה הבאה: 6ט1אט = סתהת-0ע60את כלומר, שס המקרו מוגדר ומקבל ערוצ. במקרו כזה אפשר להשתמש בכל מקום בקוב, בצורה הבאה: ( סְהַ8ת-620ַַת) 5 יש להוסיף את התו 5 בתחילה, ואת שס המקרו יש לכתוב בין סוגריים. בעזרת המקרו אפשר להגדיר את הסביבה בה עובדים, ולפיכך אפשר לשנות את ערך המקרו כשעובריס לסביבה אחרת, ללא שינוייס רביס בקוב 14%6. נספה | 357 בקובצי ₪486 יש מטרות שהן משימות שהתוכנית 886 יודעת לבצע. מטרה היא שס כלשהו ואחריו מופיע התו *':יי. המטרה תלויה ברשימה המופיעה אחריה באותה שורה. בשורה שבאה לאחר מכן מוגדר מה לעשות במקרה והמטרה אינה מעודכנת. למשל בקובצ אשר מצורף לספר מופיעה המטרה הבאה: [עס.118% :6.688 1186 [118%.05 ססס. 118% (5)0012058 (25)2185019- (5)00 במקרה זה, המטרה 6א6. 44ו1 תלויה בקוב> [118.09. אם הזמן האחרון שהקובצ (1186.00 השתנה מאוחר מאשר הזמן של הקוב> 86א0.ו118,. יחשב הקוב האחרון כלא מעודכן, ולכן תבוצע הפקודה בשורה לאחר מכן. בשורה השנייה משתמשים בערך של המקרו 66 כדי להדר את הקבצים שיוצרים את התוכנית 1.086 1180. בשורה זו יש שימוש בשני מקרו נוספיס המכילים דגלים למהדר: 671,408 ,1185018. כמו בשורה זו מופיעיס שמות הקבצים שיש להדר. לאחר שראינו את החוקיס הבסיסים, אנו יכוליס להבין מספר מקרוס שנמצאיס בקוב ₪4%6 בדיסקט המצורף. המקרו 6018=0:504 מגדיר את המיקוס של המהדר. אם המיקוס של המהדר שברשותך אינו מתאיס לנתיב הזה, עליך לרשוס את המיקוס הנכון שלו. מקרו אחר שיהיה עליך לשנות הוא המקרו המגדיר את דגלי המהדר: 1 (עמפס0א) פת- ט- = 0702085 מקרו זה מגדיר את המיקוס של ,511 (הספרייה הסטנדרטית של ++6 שנמצאת בדיסקט זה). במחשב שבו הרצנו את התוכניות, שס הספרייה הוא 86. הגדרת מיקוס הספרייה מופיע בצמוד ל- "1-*. עליך לספק את השס המלא (כולל שם הנתיב) של הספרייה, אם היא אינה נמצאת כתת-ספרייה של ספריית התוכניות. בדוגמה זו 88 נמצאת כתת-ספרייה של ספריית התוכניות ולכן אפשר לכתוב את שמה בלבד. הערה: בהתקנת הדיסקט יצרנו את הספרייה ,511 בתוך הספרייה 02260 שבה נמצאות התוכניות. הידור והרצה כדי להדר הוספנו מטרה 311 בקובף 6א4ות. מטרה זו תלויה בכל התוכניות המצורפות. לפיכך, כדי להדר את כל התוכניות במערכת הפעלה 05כ, צריך להקליד: 811 886. כך יתקבלו התוכניות בקבציס בעלי סיומת 6א6, כמו למשל, הקוב 6א6. 118 (מפרק 5). את התוכנית ניתן להריץ על ידי הקלדת השס בלבד בשורת הפקודה, ובמקרה זה: 1 8 ++6 ו-009 למתכנת המקצועי אינדקס עברי 119 אפסוו‎ א8%חם - 45 - עז8זסו | 866|קהח6 ד 0זה08ח8וס 273, 287 זחוט 18 זהחסט 8[ א אובייקט - 66[סס | 62 75,69, 93 97 114 119 וח568ו 120 234 10 12 וו 120 ב 3 1 123 בנייה 1% בסיסיים 134 הגדרה - ח08000ח518ח1 152 המרת ממשק | 337 חיתוך (פָחוסוו5) | 158 מורכבים %8 פונקציות - חסווסחטז 2, 207, 284, 300, 327 155 קוריפ‎ שדות | 97 אוסְפיס 1, 278 (ראה מכולות) אופרטור 8 0 8 / 8 % 8 + 204 ++ %6 += %6 = 86 ,3 [ אינדקס 359 אזור 86 7 > או< 31 =< (-=> 31 << 1|8 >> 255 סחףּ 8 172 ,145 93,711 86 + סווח8חץ | 257 262 ,0 9800 1 שפח 1 185, 223, 229 זס 8 % %070:0%הו6 261 86 שסזחז 232 251 0 סזחו 6סץז 21 זסא (זס 6צו0!05א6) 8 222 ,1 [ '!י! (וסח, '"לא'י) 38 אונרי - ץהחט - 83,28 בחירה ''::" (חסט|950ז 50006) 86, 149, 265 בינארי - עזהחום 28 83 בנאי - חסטסטז81חסס ‏ 93 גלובלל '>>" 207 השוואה - חספוזהקוחסס 55 המרה - חסופזפטחסס 1, 157, 258, 269 העתקה - עְקסס 85, 94, 98 השמה - 7600 ח0ו855 5, 98, 229, 324 חיבור- השמה - %ח6וח8550-פטום 95 חיסור "--" 28, 137 המקדיס "--" אוז6זס 137, 143 המצביע '*" - 0670101006 28, 143, 304 רזולוציה - חסוזט|850ז 107 סופי - אפס ++ 28, 137, 145 סיביות 38 גישה | 131,101,69 מוגן - 0+90660זס 131 איחוד - חסוחט | 103 00 ++6 ו-009 למתכנת המקצועי איטרטור - זסזהזסוו | 136, 186, 199, 274, 276, 289, 294 גישה אקראית - 800855 וח00ח38 277 281, 287 דו-כיווני - |600%008זו0ו 291,277 מפה כפולה - ס8וחט!טח | 326 מתקדס - 0זאווזס- 277 נסוג - 080080 277 קלט - +טסח!ו 207 תוויות - 1805 208 איטרציה - חסַַ8ז6זו 59 אלגוריתמים, סיבוכיות ‏ 184, 274 אפליקטור - זסזפסווס9 255 הדפסה 206 פירוק 207 ארגומנט 6, 64 אתחול מחלקה 70, 150 רשימה 98 ב ביטוי לוגי 7 בית - פוַּעס 6, 106 בדיקה הגדרה, 1861 2 טוותח 226 בנאי - זסזסטז51ח00 3, 65, 70, 93, 98, 172, 269 ברירת המחדל - )06090 | 70, 199, 248, 290, 323 העתקה - שְקְסס ‏ 73, 85, 229 וירטואלי - |שזוצ | 342 פונקציית אתחול | 70 פרמטריס 1 רשימה 139 ברירת מחדל - חסוזקס )69190 | 70, 99, 102, 199 ג גישה - 800686 אוזור | 131,101,69 אקראית -‏ חססח8ה ‏ 277 281, 287 ציבורית 102 גנרי - 0וז6ח96 מתאמים 218 361 סקדניא‎ תכנות - פָחווחוח8זססזק | 179, 184, 273, 304 גרף ירושה 11 ד דריסה - פבַחו00ו6עס ‏ 130 ה הגדרה - חס0וח068 אובייקט 12 אופרטוריס 15 ירושה מרובה 8[ מקוננת - 68160 100, 2623 קבועיס 52 קבוצה 307 רקורסיבית - 6ו8זטס6ז - 210 תבנית פונקציה ‏ 53 תת-אובייקטיס 97 הדפסת אפליקטור 26 הטרוגנית, רשימה - !| 6005ח006ז616ח 203 הומוגנית, רשימה - 8%ו! 8008ח86סוחסח 202 הורשה ציבורית 134 הֶכָלָה - 1ח6וחו9ח60 12 המרה - 0חו0851 34, 125 דינמית - סווחהחץ 207 המבטלות קביעות - 0881 00081 | 260 חוזרת - 685% 66זסזס1חו6 261 סטטית - 685% 91806 29 המרות - פחסו9זסטחסס 7, 160 בסיסית - 0ו088 158 מוגדרות על ידי המשתמש - 80ח0811 זספט 157, 159 מחלקות 188 ממשק אובייקט 337 מצביעיס 159 סוגי בסיטים 17 סטנדרטיות - 080ח 9)8‏ 157 הסתרת מידע - פַחו0וח הסוזהח וסזחו 61, 80, 92, 95 העברה לפי ערך - 6טופצ עס 5 העמסה - פַחוסאסוזפטס 6, 92, 113, 118, 130, 145 העתקה - צץ00סס אופרטור 5 2 ++6 ו-009 למתכנת המקצועי בנאי 3 85 רדודה - שסו|8ח5 73, 85 הערה - +חפוחוחסס ‏ 27 75 הפעלה וירטואלית (פולימורפית) 169 הפרד ומשול - זטףסחסס 800 ₪106 187 ו וקטור 287 ז ציכרון - עזסוח6וח דינמי | 75 טיפול 236 ניהול | 145 עריכת נתונים | 122 רגיל - 288 זליגת זיכרון - 68%! עץזסוחפוה 76 236 ח חבר - סחסוזז 2, 95, 107 חיתוך - פַחוסוו 5‏ 134, 158 ט טבלת ערבול - 6|פ89ד ₪850 2008 טווח, בדיקה - 80%ח0 6פַחז 206 , ידית - 6|סח8 11 יחס סדר - חס8|80] ז06זס 210 ייחוס - 61010006 35, 73, 76, 94 113, 183 קבוע | 78 משתנה ייחוט 7 ירושה - 6סח8זוחפחחו 7, 179 גרף 11 וירטואלית 11 יחידה - סופָחופ | 128 מוגנת - 0100160ז ‏ 133 מחלקה שְאזוה - 214 מרובה - 6|קו טח 128, 148, 154 פרטית - 816צוו 132 אינדקס 363 ציבורית 11 רשימה 141 תבניות 213 כ כתיבה - 6זח/צ בינארית - עזהחופ 118,117 עס עריכה - 8060חזסז 7, 118 ל לוגי, ביטוי 7 לולאה - ססס| - 40 40,316 118 מ מאקרו, פקודה - 0ז0ס8ח ‏ 82 מבנים - 5170010766 6, 56 מערך | 208 נתוניסם 287, 295, 307 מהדר - זפ!וקוחסס 79 מוד בינארי - 006 עזחופ ‏ 119 מודוליס - 0010/85 6, 58, 61 מחלקה - 018585 62, 84 ץְאזזה | 214 ]0 0|355 26 5% דועס | 343 68 295 341 10 15 ו 21 חח 3 5 25 ה !טוח 223 הס 12 5% 27 0% 283,245 341 9חחוס 97, 316 5% 342 סזחו 6סץז 23 זסזספט ‏ 241 5% דועס | 344 4 ++6 ו-005 למתכנת המקצועי אתחול 150 בנאי 23 בסיסית - 5888 153,127 195 בסיסית וירטואלית - 5858 |פטזוצ 152 הגדרה מקוננת ‏ 100 חיצונית 100 מופשטות טהורות - 8051801 סזטס 173 מטַפְלָל - זסז8!טוסוחוח 124 מקוננת - 85160 101, 109, 198 נגזרת - 80צו087/ 127, 129 127 500670!885 - על‎ פנימית 100 פונקציות חבר - חסווסחט1ז זססוחפוח 79 רשומות 101 רשימת המחלקות הבסיסיות - | חסו28ו|08וחו שדה - 88!0 199 תבנית - 816|קח0ז | 190 תת- 177 מחסנית - 51806% 144, 217, 244, 541 מחרוזת 39 מטַפָלָל - זסז8!טוקוחוח 7, 128 00 5 0ח6 4, 125 686 125,124 חפט - 125 אס 15 0% 15 מיון - 50 מהיר - אסוטף 187 פונקציה 21 מיכל (ראה מכולה) מילון - עְזהּחסוזסו 216 מילת מפתח 56| 5 ח08%0 - 225 +00 (קבוע) 1 79 % 005% 200 86 66 0 44 6 (י''אם לאיי) ‏ 42 18 אינדקס 365 זסו|קָאס 269 הפו 92 א (ייאס') 12 6סחו 2 6חז|חו 1 6|ס זור 208 זז (פרטי) | 70 131,102, 148 0 1, 148 סווספטק ‏ 69 131,102 148 0 895 1 47 חסזופ 5 6+ 11 פותז 900 שסזוץ | 224 ץז 225 0 ופחט 5 פופ 265 |הטחוצ ‏ 152 169 חש - 44 מכולה - 60191081 1, 219, 220, 274 מנגנון 6חווחו - 81 חבר - 0ח8ח1 | 92 מניפולטור 14 מעטפה - סס|8עח6 9 283 מערך - עְפזוף 6, 29, 33, 56, 70 אסוציאטיבי - 6צו 85500/81‏ 323 בטוח - 5816 5, 226 כפול 20 מבנה 208 מטריצות - 8110865 20 של מערכים 20 מפה | 323 כפולה - ספחוט!וטוח 226 מפרק - 065100001 3, 65, 74 וירטואלי - |שחוצ 122 מפתתח סוופטס (ציבורי) ‏ 63 5 2 6 ++6 ו-009 למתכנת המקצועי בי 7[ מצביס חריגים | 246 258 מצביע - זסוחוסן 26, 32, 71,353 135 6 2 33 אוטומטי - סוט 237 חכם - +58 207 לפונקציות מחלקה 106 לשדות 106 מרחב השמות 650806חַַ8ח 1, 251, 263 מקונניס - 85160 266 משאבי מערכת ‏ 75 משימות, ניהול ‏ 342 משפט 56 5 86 52,500 6ווחש-60 ('ייבצע כל עוד...") - 44 זסז (''עבגריי) 3+ זו 2 6 וסחו 25 6-ו 142 הזז 5, 34 חסזוצופ (ימְַתָג'', או 'ימיתוגי) | 45 בי 7[ בקרה ‏ 40 ברירת מחדל - +ו08680 - 45 התניה זו 142 לולאה ססס| - 43, 82 משתניס - פִומְהְּ8/ 7 ז 0 7 28 8 27 וו 7 +חו 9 119 טָחסו 7 [סתפ | 27 חסרי סימן - 60ח8ופחט | 28, 39 שלם - 45 מתאמיס - 80801018 216, 283, 335 גינריים 218 מתארי הקבציס - 8ז0זקו0650 16 75, 241 367 סקדניא‎ נ ניהול זיכרון 145 משימות 342 פונקציות 219 ניפוי - ז6קָטס06 83 ניקוי, פונקציה ‏ 7% נתוניס סדרתייס, מבנה 287, 295, 307 עריכה בויכרון | 122 ל סיבוכיות - עוא6!קחחסס זמן - סח 14 מקוס - 50806 | 184 סיביות אופרטוריס 8 שדה - 8!0ו8ופ - 105,103 ספירה בתים ‏ 51 שורות ‏ 51 תוויס ‏ 50 ספרייה ססו|8ח | 60, 64 ו 23 סטנדרטית 11 תבניות סטנדרטית - !זפ 273 ע עִירוּר | 224 עצ - 86זך בינארי - עזהחופ 310 חיפוש בינארי מאוזן - ח0ז568 060ח08!8 עזהחוס 207 עץ מאוזן - 1106 060ח58|8 311 ערבול - ₪858 טבלה - 190|8 308 ערך - 6ט|8/ 209 פונקציה - חסטסחט1ז 209 עריכה כתיבה 118 נתוניס בויכרון ‏ 122 8 ++6 ו-009 למתכנת המקצועי קריאה 115 ערך מוחזר 0 | 120,050 ותו 4, 104 וצ 120 אמת - 6טזז שקר - 1856 17 7 ערך ערבול - 6ט|פּצ 3850 309 פ פולימורפיזם - וחפוחסזסוחץוסס 7, 163, 168, 179 סטטי - 51816 פונקציה 281 68 248=- 8 6 25% חופ6 | 289 0 209 8 290 6 907 הסקסז 111 זז 50 :000 120 0 115 6חווחו | 92 [ספחו 290 הוח 123 60| 97 שסח 6 חסקס | 115 קסס 207 6% ססס אחוזס - 25, 26 הפטק | 248 6% תפטס :חסזז תהפטס 0 97 ץססז 5‏ 40 9 1211 ספ 23 21 200 200 23 אינדקס 369 פלט סווּ 11 6וחט 293 אובייקט - 606[טס 192, 207, 284, 300, 327 אתחול 70 גלובלית - |88ס| 63 64 השוואה 209 וירטואלית - |פטזזו/ 9, 215 טהורה - פוט 173 חברות - 615סוח6וח 2 טיפול שגיאה - 225 מחלקה ז08ח 8‏ 79 מיון לרשימה - 201 מערכת שסח 4 060 56% 224 ;סט 208 35 עיבצמ‎ ניהול | 349 סטטיות 90 ערבול - ח88 - 309 פירוק - זסזסטז 0951‏ 74, 76 קבועה - +5%98₪ח60 9 ראשית ()חוח ‏ 24 רקורסיביות - 8ופזטססז ‏ 49 שינוי ארגומנט ‏ 34 שילוב פלט/קלט 123 תבנית - 886|קח6ז 180 אופרטור "<<" 118 סטנדרטי (0וו5%) 25 , 111 פעולה - חסוז8ז6סס אריתמטית 27 הזזה - 501% 8 לוגית - ופּסוּפָס! | 38 מאוחרת - אופסק | 36 מוקדמת - אזסזס | 36 פקודת מאקרו ‏ 82 צ צומת ברשימה | 135, 199 200 ++6 ו-009 למתכנת המקצועי ק קבוע - חסוזסחטז +ח918הסס ‏ 52, 79 קבוצה - 58% 212 הגדרה 207 כפילויות - )056!₪ח | 315 קדס מהדר - 06865501ז6-0ז 2 קובצ - 86 כותר - ז6808ח | 59 ממשק - 06 97806:חו 59 מקור - 1|6 500106 59 קינון - 0ח850ח 100 קישורים - >אחו| 56 רשימה מקושרת - +8%ו! 60אחוו 7 קלט/פלט 1, 114 שילוב ‏ 119 קריאה לבנאי ‏ 129 לקוב 119 ללא עריכה - זטסחו 8160חזסזחט - 116 לפונקציה 6 עס 8 86 עס (לפי ערך) 7 ר רב-צורתיות 3, 168 רשומות 46, 199 מבניס - 5170010765 6 רשימה - 86 8, 138, 200 אתחול 98 150 בנאי 19 הטרוגנית - 86008ח006ז6+9ח 203 הומוגנית - פטספחספָסוחסת | 202 ירושה 144 כפולה ‏ 291 מבנה ‏ 291 מעגלית כפולה | 135 מקושרת - 60אחו| 57, 194 פונקציית מיון לרשימה ‏ 201 צומת 135 199 שורש - זססז 22 371 סקדניא‎ ש שגיאות, טיפול ‏ 221, 225 שגרת טיפול שגיאה - זפ|טחאח זסזו ‏ 225 שדה - 88|0 אובייקט 97 מחלקה - 0!885‏ 89 מצביע 107 סיביות - 86!0ז51 3, 105 סטטי - 81810 9 91 214 שורש הרשימה (ססז) 22 שלס ללא סימן 48 שפה - שִהְַבִּטַפָחבּ| תכנות משולבת - סוזפץ 274 תכנות מוכוונת אובייקטיס טהורה - 60זחפוס 601[פס פזטוס - 274 ת תבניות - 8165|מוח6+ מחלקות - 0|85595 פונקציות 10 תבנית עיצוב - חזסזהס ח085!0 תו בקרה 134 0 658 124 תוויס (זהּחס) 9, 50 תווית - 180 208 איטרטור 29 תוכנית - וחהזפָסזס מודולרית - זהּ!טססוח ניפוי - זַסהָטס06 83 תור - 00806 4, 216 כפול - 341,293 תכנות - פָחוהחחחהזפסזס גנרי - 968100 שילוב ‏ 335 תנאי לוגי - חסטוסחסס ופסופָסו אמת - 6ז 17 שקר - 1856 7 תת-אובייקטים 97 12 ++6 ו-009 למתכנת המקצועי 179 9 100 27 1 9, 188, 273, 304 מוכוון אובייקטיס - 160ח8וז0 60%[ פונקציונלי - |הּחסוזסחטז 127 5 3 7 אינדקס לועזי 4 00005 9 131,101 8 2 סווסטס 7, 281, 287 והססתגז 6, 283, 335 8080105 8 870ח00 205 זז וו 8 8006585 131 01 9 0 11 6, 66 1הסו טסה 6, 29, 33, 56, 70 צְהזזהּ 3 855001806 20 5 5, 226 10 350|!| 9 8 9 6ססח ץזהחוס 3, 105 80]6וס 5 068% 068 6 עס 5, 77 6ט|צ עס 6, 106 6ועם 6 4, 125 089008 200 % 00095 207 סוההחץ 1 085% 0%ז670+ח|6ז 29 % 91800 373 סקדניא‎ 24 9, 50 ז חס 2, 84 | 0|]855 4 עצפה 7, 153, 195 | 0856 26 0855 13 %*000/18785 3, 341 06006 7, 129 0671/60 0 >99 15 150 8 55%5!! חסוז28ו!8 םוחו 21 ו 4 זס:3%!וס!ח8וח 3 קוח 9 חסוזסחטז ז6ס השרוח 25 65 223 כ חחוז! טוח 1, 109, 198 659%00ח 12 הס 113 6זטם 27 וב 5, 285, 341 | 961806 7, 316 8חוזפ 5-05 127 5% 222 +600|3:% 0 23 סזחו 6סץז 1 60%0%/ 12 6 |8ט)זוצ 7 75 )ה8חוחסס 9 זסווקחזסס ץזוא6!סח סס 4 90806 1464 6חוז 2, 79 חסטסחטז 1ח8ז5 00 3, 65, 70, 93, 98, 172, 269 0 3 85, 229 | צ000 0, 199, 248, 290, 323 ]|06180 2 |פט]זוש 005 274 ,1 ++6 ו-009 למתכנת המקצועי 112 הוח סס 7, 160 וזח 00 8 859506 7 08%ח918 7, 159 060060 ז50ט עס 5 00678%0 3, 85 ששסו|8ח5 פ 3 זז 0, 99, 102, 199 חסחסס ]061801 החסוזוחו061 2 00 0, 263 68100 2 00[60 15 סוס 20 6 085100 8167₪₪ 7 3, 65, 74 וי 2 |ט)זוצ 107 זט חס 0חה 06ועו0 5 14 ו0ח6 805 4 9, 283 סס|8/ח6 0 120 ,0 5 0!6%₪ַחהּח זסזז9 ב 7 6 0 3, 105 סוס 9 0!855 7 00[80 9 1 214 | 96800 6 5 261 5 6806 9 375 סקדניא‎ 206 ++6 ו-009 למתכנת המקצועי 9 6 806 1סזחו 59 6 5006 4, 104 107 ,95 ,2 80/8706 1 8|!)0608%46%6 8 4 006%107₪ 9 חו0ף6ס 79 00 4, 76 065170060 209 0 0 01856 1 הספסס1 6 7 0 %חט00 001008] 0 91008! 63 ,3 6006 5 9 335% 2 שחווחו 0 +ספח!ו 13 חו8וח 4 ()חווח 7 8|!06ח 9 0!355 061 6וח 2 ור 6 ששסח 2, 207, 284, 300, 327 00[60% 5 חססס 207 ססס 200 6% ססס 5, 26 זחחס 8 חפט 200 אסהם חפט 203 +חסזז הפטס 7 00ו|68ז 6 [49 56660 1 23 ספ + החפחז חסוזסחטז 0 עססז9 ה6ז9ץ5 4 שפח 4 0600600א8חש 56% 24 זט 11 קוו 0 %:0|]3ח0+ 3 סנטסוחט 9, 215 |8ט)זוש 3 6טס 6 9, 184, 273, 304 9 רהוזה סזס 96610 ה 1 פוחח 35 9 חסטסחטז 8 80₪6) 9 6נט|8/ 203 1 6008ח086ז616ח 202 68008 סוחסה ו 2 זו 1, 80, 92, 95 8חוסוח הסוזהחזזסזחו 7, 179 6זו סח הו 4 | +88 8, 148, 154 6!ס0!טוח 2 סזהעוזק 323 ₪|01606ז 8 0!6ח|9 1, 114, 119 וסט סז סח 6, 186, 199, 274, 276, 289, 294 זס831זסזו 20 2300 7, 291 |008וז60ז01ו₪ 7 סזעסת 7 %טסח| 226 חחוז! טוח 1, 287 8006585 וחססתפז 377 סקדניא‎ |08 58 208 9 חסוזפז6זו 4 סזסצ 66 5 006 5 חת08%0 2 0-05 1 79 005% 200 % 000595 6 00|06 44 00 12 56| 9 ו%סו!קא9 2 סחסשח1 12 ז 2 6 וסחו 1 6חווחו 2008 6זטות 1, 148 זו 0, 102, 131, 148 6זהעוזס 9, 102, 131, 148 | ס6ו!סטס 9 91800 7 91005 5 חסזו/פ 11 6 ו וס 00 וח 4 שוסזחץ 205 ץז 17 בי 5 0 ופחט 5 8חופט 2, 169 |8ט)זוש 4 6וחש 0 6 רסחב 4 סחפעץה 24 0 00[60% 6זוס ++6 ו-009 למתכנת המקצועי 56 5אחון 7 1 660אחוו 7 חסוסחסס |8סופָסו |86 7 7 6 10 סססן 1, 40, 118 | 6ווח/צ ₪ 2 8070 0, 63% ₪8|!06ח 7, 128 זסזה טק וח וח 5 00 4, 125 0 4, 125 | 6605 5 חתפטת 15 אס 5 0% 5, 122, 145, 236, 288 עץזסוחסוח 6, 236 88%| 6, 58, 61 5 226 8 ווח א 1, 251, 263 6" הח 6 65%1600%ח 0 650008ח 0 2, 69, 75, 93, 97, 114, 119 60%[סס 1323 1 2, 207, 284, 300, 327 הסטסחתג1ז 0, 234 1576 12 הווחו 12 1515708 120 וי 8 פחוסו|פ 1323 בוב חסוז9ז6קס 8 |סופס! 379 סקדניא‎ 6 אפס 6 אתס6זק 8 ו הס 8 / 8 / 8 % 8 + 204 ++ 9%6 =+ 9%6 = 3, 86 ז 7 86 1 < ז0ס > 3 => 806 =< 38| << 5, 327 >> 1, 222 [ 8 וו 6), 189, 265 ":" 8 סחףּ 5, 94, 229, 324 ו 355 8, 83 +זהחוס 55 הספוזה ו סס 3 ח50000ח00 1, 157, 258, 269 הסופז6שח 00 000 | 98 ,94 ,5 1 93, 145, 172 06|8%6 7 685% סוחהחץ0 1 1895, 223, 229 שסח 8 זס 55 1 ח6-855וס 1 685% 16]0:0%ח!6ז 107 חסוזט|650ז 5|!2060% 6 0, 265 900 2 שסזח 1 סוססץץ 21 סזחו 6סץז 8 זסא 0 ++6 ו-009 למתכנת המקצועי 0 חסח6|]8ז ז06זס טס 8 "<<" 5 900 0 >חו00ופעס 6, 92, 113, 118, 130, 145 פֶחו80ס!ז6/ס כ 6, 32, 33, 71, 135 זסזחוסס 7 8000 2 33 6 7 החפ 7, 163, 168, 179 ותפותקזסוהץוסס 1 96800 2 006550ז6-0ז0 החאזססזס 3 זט 1 זה טסוה טחוחוחהזטסזס 3 |החהסוזסחטוז 9, 184, 273, 304 6ו61ח06 5, 127 %60ח218) 0[60% 0 0 00606 216 ,4 5 226 0% 06ח8ז 5, 73, 76, 94, 113, 183 06ה01076ז 0% 22 9 6 5 0006 5 +!1ו0618 0, 52 06886 4 פווח/ש-00 3+ זסז 12 ז 2 6!56-! 381 סקדניא‎ 2 2 וביו 5 6נט|סחו 3, 82 סססן 5, 34 חז90ז 5 ח9/110 7 06008 212 5% 5 156%!וח 4, 158 פחוסו|9 7 +50 4, 217, 244, 341 | 9)806 3, 287 ץזהזסו | 866|קה6 ד 0ז08ח8ז6 - 571 6, 56 4-8 ך 208 0 9, 179 5 0 0!85855605 100 5חסססחטז 6זז 1 60 060ח08!3 0 עזפחוס 7 ח56870 08/3060 עזהחוס 7 סז ט 8[ זהחסט 8[ זחוט 116 זוסחו 81160 זסזחט 2 חסוחט צ 7 5 7, 28 חס 7 000086 7 יו 9 119 +חו 7 פחס! 7 סחת5 8, 39 0 ופט ++6 ו-009 למתכנת המקצועי 118 7 /80)0- 7 6 10 צ 6 7, 118 עזהחוס סז אינדקס 383 הראובני 6, ת.ד. 6108 הרצליה 46160 טלפון: 09-9564716 פקס: 09-9571582 |ו.סס. ורח00-8ח6סזחו |ו.סס. וחה8-ססח. צשעצשש קטלוג אוקטובר 2000 אוהתההתתמהקהתהמתהקהקהההקקקוו''''חחדדד .₪ ה-א 8 05082000 ה הרהה הרהה | | | 00| | קוראים > יודעם 2000 זאוסקהפ/וסק | | 108 | | | 39 | 000 אס שרולעמין 8 | 98 | | | 99 | 00 05910 ושרולעמטן | | 386 | | | 99 | 19 > | אינטרנט/גרפיקה באינטרנט ‏ 0 כ | | | 00| )א למפתתיאתרים באינטרנט | | בקטב ‏ | | 00 | 149 | 842 למפתהיאתרים באעטרנט | | 935 | 9012 למפתחיאתרים באעטרנט | | | ג | 3 50 ובניית אתרים ב- ט6כז6!ח! 15031 סדנת לימוד קצ ₪3 מוסיקה באינטרנט עם קוחפהעט | | | 228 | 05 | 99 | פס | 6% | | לפטפט ברשת עם 80וו | 168 | מס | 350 | > | ששפותתכות ( ה ה ה | הכ | | 00| פס | 49 סדנת לימוד 6 ++6 |808ו/ | 992 | 00 | 219 19 שפת 6 - נושאים מתקדמים ומולטימדיה | 42 |05 | 139 > עמי | ₪ | מתיר' | המדריך השלס לשפת 6 + מהדר סטזטוד סחהוזסם מהד' 6 ו שפת6-תוכנמות ופתרונות | || || | || | מחדי 2‏ | 38 | 60 | 99 | שפת 0מעברלשיא -ספרלומוד | | בקטב ‏ | | | 00 | לג | שפת 6 מעברלשיא-ספרתרמלים | || | | בקטב ‏ | | | 65 | 99 | שפת אסמבלילמתשב האושה | || || | מחדי2 | 392 | 60 | 8% | פסקלמהצעד הראשון | 2% | הכ | 99 | > | 76 חומרה, תוכנה וניהול כ[ | | 0 | ב הס -7777- ד | המדריך השלם לטכנאי ₪0 - חומרה ותוכנה (ורוןסוף | | | 496 | ם | המדריך השלם לטכנאי 80 - רשתותתקשורת (ווןסטף | | | 552 | ם חמדרוך הלה לכאי 60 -רעתות תקשורת וריו - הד 41085 ב 115-מ ה מ | 98| ם חכה לטב הלכה 85 ו 3 5% ם 0 | מילון הוד-עמי למונחי מחשב בשיתוף מכון התקנים | 65 | 768 | ם פריצה! 0 במחשב שלי! -. | מהולאיכות תוכנה | | 3 | | סדות לימוד00198סזק | | 58 | ם 0% 6 ספרהתמיכה | | 288 | >= מחוללי "שומים ובסיסי נתונים 00999 ראה בעמוד קודם) | | | | | מחסמנתומם 0 | 3 | | ארגון נתונים וקנצים ‏ ו | 6 | | בסיסי נתונים טבלאיים ושפת 601 - עקרונות ועצוב | | | | 675 | ם | בסיסי נתונים טבלאיים ושפת 801 | 580 | > תקשורת 000000000 כ | | | תקשורת מחשבים - פרוטוקולים וארכיטקטורות רשת | | | 496 | ם | רשת נובל- 5 69/6 - מדריך הפעלה ושירות | | | | 58% | ם ושתטבל-6000641א || כרךאי 0 | 36 | ה 000897 00| | | קוראום > טדים 0800697 | 672 | ם 777777 רש 8 | 200 | | 2 | 75 סכ 9/9'0/מ/מ. 97 |66א 2900 9/9'0/מ/מ מה חדש ב - 97 זוסצש כסלכק כַ'יִיכָּוֶמימ, 97 %+חוסק וס /שסק 7 6זס/צ תכליס (למתחילים) 7 |66אם תכליס (למתחילים) 7 600655/ ישר ולעניין סדנת לימוד 84 97 600655 200 בי | ,ו | ירי ה | מערות הפעלה ה | | | 00| קונצאצתה | | 9 | | 20 | | פשססאן הה ה | הכן| | 00| חטוהחסווןת 8איס0חו/ הסדרה הידידותית | || ;67 | 146 | | | 49 | 98 פאסטחו למשתמשיגרסאות קודמות | | | | | 416 | 60 | 5% | מהולמערכת 98 פאסהזא)- פיטר ורטון | | | 660 | 60 | 99 | 98 8א60הוישרולעממן 0 | ג | | | גג | 98 פאוסטחוא תכליס (למתתילים) | || | 260 | ₪ | 69 | | 95 הו תכילט (למתתילום) | | | 200 | ₪ | כסלכק כַיִיל/מימ 95 פ/טסחו/צ מהד' 2 | 528 | -- | 155 | הואצוקתהקותות המו תור הק כו העשמ | תוכנות 08006 לחלמת311 ו- 0/0087 | | | מספכס יליו ית 95 פשוססחו/\ זסז 7 ₪זס + 00 מבחן אישי | סל ית 95 00 )זו 80017 8 | 666 | | | | סק לומת 95 הזו 8 5067 | | 466 | | | 8607 מהצעד הראשון + תוכנת 610082 | | 240 | ₪ | | 007 במטרד הממותטב | | 8 | ₪ | -6סבבית-הספר 8 000000 | 4 | ₪ | 3 | 6 ₪זס/ למד להצלית - באישור משרד התעוך | | | | | | 36 | ₪ | 49 | ביוגיליון - ביולוגיה בעורת אקסל | 288 | ₪ | 49 | * המחירים בעו"ח כולל מע"מ ומעלוח חינם קטלוג מעודכן באתר האינטרנט וו.ס6.וַרחה3ּ-1001].שעש מרכז הזמנות טלפוני - 09-9564716 ימים א'-ה' בין השעות 8:30 ועד 17:00