C/C++ מדריכי
הצגה מזורזת :C++ הבנת
C++ הקדמה להיררכית מחלקות ב C הקדמה לתכנות ב דף הבית

שיעור 3 - אוצר המילים של ++C

השיעור האחרון התמקד באלמנטים של שפת ++C שמרחיבים את C או מתקנים בעיות שטבועות בה. שינויים אלו הם קלים למדי להבנה. החלק השני של ++C הוא ההרחבות של תכנות מונחה עצמים. תוספות אלו לשפה אינן קלות להבנה. בעוד שהיכולת cout היא פשוט דרך נוספת לטיפול בהדפסה -- דבר שאותו כבר הבנת -- הרבה מההרחבות של תכנות מונחה עצמים לא יהיו מוכרות. המטרה של פרק זה היא לתת לך חשיפה ראשונה לחלק מהרעיונות הכלליים. לאחר מכן נתבונן בתחביר של ++C שתומך ברעיונות אלו ואז נחזור ונבחן את הרעיונות שוב.

3.1 אוצר המילים של ++C

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

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

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

לספרים יש תכונות מסוימות שמשותפות לכל הספרים: יש להם כריכה, מספר פרקים, אין בהם פרסומות, וכן הלאה. כמו כן יש תכונות שמשותפות לכל הפרסומים באופן כללי: כותרת, תאריך פרסום, מוציא לאור, וכו'. יש להם תכונות שמשותפות לכל העצמים הפיזיים: מיקום, גודל, צורה ומשקל. הרעיון של תכונות משותפות הוא מאוד חשוב ב ++C.
++C מיישמת את המושג של תכונות משותפות על ידי שימוש בירושה. ישנם דברים מסוימים שעושים עם ולעצמים שונים, ופעולות אלו משתנות מעצם לעצם. לדוגמא, ניתן לקרוא ספר, וניתן לעלעל בדפיו. ניתן להתבונן בכותרת, למצוא פרק מסוים, לחפש משהו באינדקס, לספור את הדפים, וכן הלאה. פעולות אלו הן בעיקר מיוחדות לפרסומים: אתה אף פעם לא מוצא את עצמך מעלעל בדפים של פטיש, לדוגמא. אולם, יש פעולות שהן משותפות לכל העצמים הפיזיים, כגון הרמתם. ++C לוקחת בחשבון גם את העובדה הזו לגבי העולם, שוב על ידי שימוש בירושה.

הטבע ההירארכי של קטגוריות עצמים, יחד עם הארגון ההירארכי שלנו של תכונות ופעולות של עצמים, משובצים כולם בתחביר ובאוצר המילים של ++C. לדוגמא, כאשר תתכנן תוכנית אתה תפרק אותה לעצמים, שלכל אחד מהם יש "מחלקה". אתה "תירש" תכונות של "מחלקת בסיס" כאשר תיצור "מחלקה נגזרת". כלומר, אתה תיצור מחלקות של אובייקטים כלליים ואז תיצור מחלקות ספציפיות יותר מהם, תוך גזירת הספציפי יותר מהכללי. אתה "תסגור בבועה" את הנתונים שנמצאים באובייקט באמצעות "פונקציות חברות", וכאשר תרחיב מחלקה אתה "תגדיר מחדש" ו"תרמוס" את הפונקציות במחלקת הבסיס. מבולבל? בוא נתבונן בדוגמא קצרה כדי לראות מה בעצם המשמעות של כל המילים האלו.

הדוגמא הקלאסית של תכנות מונחה עצמים היא תוכנית גרפית שמאפשרת לך לצייר עצמים -- קוים, מלבנים, עיגולים וכדומה -- על המסך. מה משותף לכל האובייקטים האלו? לכל האובייקטים מיקום על המסך. ייתכן גם שיש להם צבע. כל צורה שמוצגת על המסך מחזיקה בתכונות אלו. לכן, כמתכנן תוכנית אתה תיצור "מחלקת בסיס" -- דרך נוספת לחשוב על זה היא "מחלקת אובייקט כללי" -- שמחזיקה בתכונות שיש בכל האובייקטים שמופיעים על המסך. מחלקת הבסיס עשויה להיקרא "צורה" כדי לזהות אותה באופן כללי. לאחר מכן "תגזור" אובייקטים שונים -- עיגולים, ריבועים, קוים -- ממחלקת הבסיס הזו, תוך הוספת תכונות חדשות שהן מסוימות לאובייקטים אלו. מעגל מסוים שמצויר על המסך תוך שימוש במחלקה עיגול יהיה "מופע" של המחלקה עיגול, שירשה חלק מההתנהגות שלה מהמחלקה הכללית יותר צורה.

ניתן ליצור הירארכיה מסוג זה עם מבנים רגילים ב C, אבל זה רחוק מלהיות כזה קל לעשייה כמו ב C++ .C++ מכילה תחביר לטפל בירושה. לדוגמא, ב C אתה יכול ליצור מבנה בסיס שמכיל את מיקום העצם על המסך ואת צבעו. ואז מבני העצמים הספציפיים יכולים להכליל את מבנה הבסיס הזה ולהוסיף עליו . ++C עושה את התהליך קל יותר, ואז הולכת צעד אחד קדימה. ב ++C, פונקציות יכולות גם להידבק למבנה וזה נקרא "מחלקה". כך שמחלקת הבסיס עשויה להכיל "פונקציות חברות", כפי שהן מכונות ב ++C, שמאפשרות להסיר עצם ולצבוע אותו מחדש. "המחלקות הנגזרות" יכולות להשתמש בפונקציות החברות האלו כפי שהן, או להוסיף פונקציות חברות חדשות כדי להגדיל את התפקודים, או לרמוס פונקציות חברות קיימות כדי לשנות את הפעילות. התכונה החשובה ביותר שמבדילה את ++C מ C היא הרעיון זה של "מחלקה", הן ברמה תחבירית והן ברמה תפיסתית. מחלקות מאפשרות לך להשתמש בכל התכונות הרגילות של תכנות מונחה עצמים --"סגירה בבועה", ירושה, ורב צורתיות -- בתכניות ה ++C שלך. הן גם המסגרת שעליה תכונות אחרות, כמו "הגדרה מחדש של אופרטורים" (היכולת להגדיר מחדש אופרטורים כמו "+" ו "<" לטיפוסי נתונים חדשים שיוצרים), נבנות. כל זה עשוי להישמע כמו קשקוש עכשיו, אבל לאחר שתכיר את הרעיונות ואת אוצר המילים תתחיל לראות את העוצמה של הטכניקות החדשות הללו.

3.2 ההתפתחות של מחלקות

בהינתן הכמות של העוצמה התפיסתית שגלומה ברעיון המחלקה, מעניין לציין שהתחביר נשאר ברור למדי. מחלקה היא פשוט הרחבה של מבנה C. באופן בסיסי מחלקה מאפשרת לך ליצור מבנה, ואז לקשור יחד לצמיתות את כל הפונקציות שקשורות במבנה זה. תהליך זה ידוע כ "סגירה בבועה". זהו מושג פשוט מאוד, אבל הוא הלב של תכנות מונחה עצמים: נתונים + פונקציות = עצם. מחלקות יכולות גם להבנות מעל מחלקות אחרות על ידי שימוש בירושה. תחת ירושה, מחלקה חדשה מרחיבה את מחלקת הבסיס שלה. לבסוף, מחלקות חדשות יכולות לשנות את ההתנהגות של מחלקות הבסיס שלהן, יכולת שידועה כרב צורתיות (פולימורפיזם).

זוהי דרך חדשה לחשוב על הקוד שלך -- זוהי חשיבה תלת ממדית. ניתן להתייחס לקטע קוד פשוט (כזה שאין בו פונקציות) כקוד חד ממדי. הוא מתחיל בהתחלה ונגמר בסוף וזהו זה. לאחר מכן אתה מוסיף לו פונקציות ומסיר חלק מהכפילויות ונותן שמות לחלק מהקטעים הגדולים. זהו קוד דו ממדי. כעת אנו הולכים להוסיף לזה ממד שלישי, קיבוץ פונקציות ונתונים יחד למחלקות כך שהקוד מאורגן עוד יותר. הירארכית המחלקות שנוצרת על ידי ירושה מוסיפה את הממד השלישי. וכמו שהרבה יותר קשה לרכוש מיומנות בטיסה מאשר בנהיגה כיוון שטיסה מוסיפה לתערובת ממד שלישי, כך יכול לקחת זמן לרכוש מיומנות בתכנות מונחה עצמים.

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

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

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

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

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

דרך טובה יותר לעצב את התוכנית היא להשתמש ב"טיפוס נתונים אבסטרקטי". בגישה זו, המתכנת קודם כל מנסה להחליט איך יעשה שימוש בנתונים. בדוגמת פני הקרקע שלנו, המתכנת עשוי לחשוב, "טוב, אני צריך את היכולת לטעון את נתוני פני הקרקע מכל מקום שממנו הם מגיעים, ולצייר את פני הקרקע על המסך, ולראות אם מסלול כדור התותח חותך את פני הקרקע." שים לב שזה נעשה בצורה אבסטרקטית -- אין שום אזכור למערך או רשימה מקושרת. לאחר מכן המתכנת יוצר פונקציות כדי ליישם את היכולות הללו. הפונקציות עשויות להיקרא draw_terrain ,load_terrain, ו check_terrain_intersection. משתמשים בפונקציות אלו במהלך התוכנית.

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

שפות רבות הופכות רעיון זה לפורמלי. בפסקל ניתן להשתמש ב "unit", ב C ניתן להשתמש בספרייה. שניהם מאפשרים לך ליצור ולהדר בנפרד קובץ שמכיל את מבנה הנתונים ואת הפונקציות שניגשות אליו. ניתן לציין שמבנה הנתונים יהיה נסתר ("hidden") , שפירושו שניתן לגשת למערך רק על ידי הפונקציות באותה unit. בנוסף, ניתן להדר את ה unit כך שהקוד בפנים נסתר גם כן: מתכנתים אחרים יכולים לקרוא לפונקציות בגלל הממשק הגלוי לכל, אבל הם לא יכולים לראות או לשנות את הקוד הממשי.

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

1. הכי חשוב, אין דרך קלה לשנות או להרחיב את ההתנהגות של ה unit לאחר ההידור.

2. טיפוסים אבסטרקטיים אלו לא משתלבים עם השפה המקורית כל כך טוב. מבחינה תחבירית הם בלגן, והם לא משתמשים באף אחד מהאופרטורים כמו שטיפוסים "רגילים" משתמשים בהם. לדוגמא, אם תיצור טיפוס חדש שבו פעולת חיבור היא טבעית, אין כל דרך שבה תוכל להשתמש בסימן החיבור לציין את הפעולה -- תאלץ ליצור פונקציה שנקראת add במקום זאת.

3. אם מסתירים מערך ב unit יכול להיות רק מערך אחד. לא ניתן ליצור מספר רב של מופעים של טיפוס הנתונים אלא אם כן משנים את הקוד ושוברים את עקרון הסתרת הנתונים בתהליך.

מחלקות ++C מסלקות את הליקויים האלו.

3.3 ++C והפשטת נתונים

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

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

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




לדף הראשון

<< לדף הקודם

לדף הבא >>