מושגי יסוד: מחלקות ואובייקטים
כשאתם מתחילים לצלול לעולם התכנות, אתם ודאי נתקלים בגישות שונות לכתיבת קוד. עד כה, אולי התרגלתם לכתוב תוכניות באופן ליניארי, צעד אחר צעד, בדומה למתכון. אבל ככל שהתוכניות הופכות למורכבות יותר, גישה זו עלולה להפוך למסורבלת וקשה לניהול. כאן נכנס לתמונה תכנות מונחה עצמים, או בקיצור תמ"ע (OOP – Object-Oriented Programming), גישה מהפכנית שמשנה את הדרך שבה אנו חושבים על בניית תוכנה. היא מאפשרת לנו לארגן את הקוד בצורה שמחקה את העולם האמיתי, עם ישויות עצמאיות שיכולות לתקשר זו עם זו. גישה זו הופכת את הקוד למודולרי, קל יותר להבנה, לתחזוקה ולהרחבה.
בבסיסו של תכנות מונחה עצמים עומדים שני מושגים מרכזיים: מחלקות ואובייקטים. דמיינו לרגע שאתם מתכננים לבנות בית. לפני שאתם מתחילים להניח לבנה אחת, אתם זקוקים לתוכנית אדריכלית מפורטת – שרטוט שמגדיר בדיוק איך הבית ייראה, כמה חדרים יהיו בו, היכן ימוקמו החלונות והדלתות, ומהם החומרים שיידרשו. תוכנית אדריכלית זו היא למעשה "מחלקה" (Class) בעולם התכנות. מחלקה היא תבנית, שרטוט או תוכנית שמגדירה את המבנה וההתנהגות של ישויות מסוימות. היא אינה יחידה קיימת בפני עצמה, אלא רק מתווה ליצירת יחידות בפועל.
לאחר שיש לכם את התוכנית האדריכלית, אתם יכולים להתחיל לבנות בתים בפועל. כל בית שאתם בונים על פי אותה תוכנית הוא "אובייקט" (Object). כל אובייקט הוא מופע (instance) ספציפי של מחלקה. כלומר, למרות שכל הבתים נבנו מאותה תוכנית, לכל אחד מהם יכולים להיות פרטים ייחודיים משלו – צבע שונה לגג, גינה בגדלים שונים, או ריהוט פנים מותאם אישית. האובייקט הוא הישות הקונקרטית והמוחשית שקיימת בזיכרון המחשב בזמן ריצת התוכנית, והיא פועלת על פי ההגדרות שנקבעו במחלקה שלה.
אם נחזור לדוגמת הבית, ה"מחלקה" (התוכנית) מגדירה שלכל בית יהיו קירות, גג, דלתות וחלונות – אלו הן ה"תכונות" (Attributes) של הבית. היא גם מגדירה שניתן להיכנס ולצאת מהבית, או לפתוח ולסגור חלונות – אלו הן ה"פעולות" או ה"מתודות" (Methods) שהבית יכול לבצע. בצורה דומה, מחלקה בתכנות מגדירה אילו נתונים (תכונות) יהיו לאובייקטים שלה, ואילו פעולות (מתודות) הם יוכלו לבצע. זהו לב ליבו של תכנות מונחה עצמים: לאגד יחד נתונים ופונקציות שפועלות על הנתונים הללו, בתוך ישות אחת הגיונית.
קחו לדוגמה מחלקה בשם "מכונית". מחלקת "מכונית" תגדיר שלכל מכונית יש תכונות כמו צבע, דגם, מהירות נוכחית ומספר דלתות. בנוסף, היא תגדיר פעולות שהמכונית יכולה לבצע, כמו "התנע", "סע קדימה", "בלום" או "צפור". כאשר אנו יוצרים אובייקט של "מכונית", למשל "המכונית שלי", "המכונית של השכן", או "אוטובוס", כל אחד מהם יהיה מופע ספציפי של המחלקה. ל"מכונית שלי" יכול להיות צבע כחול, ול"מכונית של השכן" צבע אדום, אך שתיהן עדיין יהיו מכוניות בעלות אותן תכונות בסיסיות ואותן יכולות פעולה.
היתרון הגדול בגישה זו הוא שהיא מאפשרת לנו לבנות תוכנות מורכבות בצורה מסודרת ומאורגנת. במקום לכתוב קוד "שטוח" וארוך, אנו מחלקים את הבעיה לישויות קטנות יותר, מודולריות ועצמאיות. כל מחלקה אחראית על חלק מסוים בפונקציונליות של התוכנה, מה שמקל על הבנה, תיקון באגים ושינויים עתידיים. בנוסף, קוד שנכתב כמחלקה ניתן לשימוש חוזר בקלות בחלקים שונים של אותה תוכנה, ואף בתוכניות אחרות, מה שחוסך זמן ומאמץ רב בפיתוח. זוהי דרך יעילה לבנות מערכות חזקות וגמישות.
כעת, כשיש לכם הבנה בסיסית של מהי מחלקה ומהו אובייקט, הגיע הזמן לצלול עמוק יותר לפרטים. בחלק הבא, נלמד בדיוק כיצד מגדירים את ה"תכונות" (הנתונים) ואת ה"מתודות" (הפעולות) בתוך המחלקות שלנו בשפת ++C. נראה איך כל אובייקט שנוצר מהמחלקה מקבל עותק משלו של התכונות, וכיצד הוא יכול להפעיל את המתודות כדי לשנות את מצבו או לבצע פעולות שונות. המשיכו איתנו, כי הבנת מושגים אלו היא המפתח לשליטה בתכנות מונחה עצמים.
תכונות ומתודות
אחרי שהבנו מהי מחלקה ומהו אובייקט, הגיע הזמן לצלול לעומק ולהבין מה בדיוק מרכיב אותם. דמיינו לרגע מחלקה כתוכנית בנייה מפורטת לבית חלומותיכם; התוכנית הזו לא רק מגדירה את קווי המתאר הכלליים, אלא גם מפרטת בדיוק ממה הבית יורכב ומה הוא יוכל לעשות. בדומה לכך, מחלקה ב-++C מגדירה את הנתונים שאובייקטים מטיפוסה יכילו, ואת הפעולות שהם יוכלו לבצע. שני המרכיבים העיקריים הללו הם התכונות והמתודות, והם אלו שמעניקים לאובייקטים את משמעותם ואת יכולתם לתפקד בעולם התוכנה.
נתחיל עם ה'תכונות' – או בשמן המקצועי יותר, 'חברי נתונים' (data members). פשוט תחשבו עליהן כמאפיינים או כנתונים שכל אובייקט מהמחלקה הזו ישמור בתוכו. אם ניקח לדוגמה מחלקה בשם 'מכונית', תכונותיה יכולות להיות 'צבע', 'מהירות נוכחית', 'מספר דלתות' או 'דגם'. כל אובייקט מסוג 'מכונית' שיצרתם, כמו 'המכונית הכחולה שלי' או 'הטנדר האדום של אבא', יחזיק בתוכו את המידע הספציפי שלו עבור כל אחת מהתכונות הללו. התכונות הן למעשה הזיכרון הפנימי של האובייקט, המאפשר לו לשמור על מצבו הייחודי.
עכשיו נעבור ל'מתודות' – המכונות גם 'פונקציות חברות' (member functions). אם התכונות הן מה שהאובייקט 'יש לו', המתודות הן מה שהאובייקט 'יכול לעשות'. אלו הן הפעולות, ההתנהגויות או הפונקציות שאובייקט יכול לבצע על עצמו או על נתונים אחרים. בהמשך לדוגמת ה'מכונית', מתודות יכולות להיות 'התנע מנוע', 'האץ', 'בלום' או 'שנה צבע'. כאשר אתם מפעילים מתודה על אובייקט מסוים, היא מבצעת פעולה ספציפית, שלעיתים קרובות משנה את ערכי התכונות של אותו אובייקט או מציגה אותן.
הקשר בין תכונות למתודות הוא קריטי ומהותי להבנת תכנות מונחה עצמים. המתודות כמעט תמיד פועלות על התכונות של האובייקט שהפעיל אותן. לדוגמה, כאשר אתם קוראים למתודה 'האץ' על אובייקט ה'מכונית' שלכם, המתודה הזו תגדיל את ערך התכונה 'מהירות נוכחית' של *אותה* מכונית ספציפית. בכך, המתודות מספקות את הלוגיקה והכללים שבאמצעותם האובייקט מתנהג ומגיב לאירועים חיצוניים או לשינויים פנימיים. הן מאפשרות לנו לשלוט על מצב האובייקט בצורה מסודרת ובטוחה.
חשוב להבין שלא כל התכונות והמתודות חשופות לעולם החיצוני באותה מידה. לעיתים, נרצה שתכונות מסוימות יהיו נגישות רק מתוך המחלקה עצמה, כדי למנוע שינויים לא רצויים או לא מבוקרים בנתוני האובייקט. לשם כך קיימות רמות גישה, כמו 'פרטי' (private) ו'ציבורי' (public). תכונות פרטיות נגישות רק למתודות בתוך אותה המחלקה, בעוד שתכונות ומתודות ציבוריות נגישות מכל מקום בתוכנית. זהו עקרון חשוב הנקרא 'כימוס', ונדון בו בהרחבה בהמשך הספר.
לסיכום, תכונות ומתודות הן אבני הבניין המרכזיות של כל מחלקה ואובייקט ב-++C. התכונות מגדירות את המצב והנתונים של האובייקט, ואילו המתודות מגדירות את ההתנהגויות והפעולות שהוא יכול לבצע. יחד, הן יוצרות יחידה שלמה וקומפקטית שמייצגת ישות בעולם האמיתי או ישות מופשטת שאתם רוצים למדל בתוכנה. הבנה עמוקה של שני המושגים הללו היא המפתח לכתיבת קוד מונחה עצמים יעיל, ברור וקל לתחזוקה, והיא תאפשר לכם לבנות תוכניות מורכבות בצורה מסודרת והגיונית.
ירושה (Inheritance)
דמיינו לרגע שאתם בונים עולם של תוכנה, ובו אתם צריכים ליצור מגוון רחב של אובייקטים דומים אך שונים. למשל, יש לכם מכוניות, אופנועים ומשאיות – כולם סוגים של כלי רכב, אבל לכל אחד מהם יש תכונות ייחודיות משלו. כאן נכנסת לתמונה הירושה, שהיא אחד העקרונות החשובים ביותר בתכנות מונחה עצמים (OOP). היא מאפשרת לנו לבנות היררכיה של מחלקות, שבה מחלקה אחת יכולה לרשת תכונות והתנהגויות ממחלקה אחרת. זה קצת כמו עץ משפחה, שבו ילדים יורשים תכונות מסוימות מהוריהם, אך גם מפתחים תכונות משלהם.
בליבת רעיון הירושה עומדות שתי מחלקות עיקריות: מחלקת הבסיס, שנקראת לעיתים גם מחלקת אב או מחלקת על (Base Class / Parent Class), ומחלקת הבת, או המחלקה היורשת (Derived Class / Child Class). מחלקת הבת היא זו שיורשת את התכונות והמתודות ממחלקת הבסיס, ובעצם מרחיבה אותה. הקשר בין השתיים מתואר לרוב כקשר 'הוא-א' (is-a): למשל, 'כלב הוא חיה' או 'מכונית היא כלי רכב'. זהו קשר מהותי שמגדיר היררכיה לוגית וברורה בתוך הקוד שלכם.
היתרון הראשון והבולט ביותר של הירושה הוא שימוש חוזר בקוד. במקום לכתוב שוב ושוב את אותן תכונות ואותן פונקציות עבור מחלקות שונות שיש להן דמיון, אנחנו פשוט מגדירים אותן פעם אחת במחלקת הבסיס. כל מחלקת בת שיורשת ממנה מקבלת באופן אוטומטי את כל מה שהוגדר במחלקת האב. זה חוסך המון זמן, מקטין את כמות הקוד, ומפחית משמעותית את הסיכוי לטעויות. דמיינו כמה קל יותר לתחזק קוד כזה, שבו שינוי אחד במחלקת הבסיס משפיע על כל המחלקות היורשות.
יתרון נוסף ומשמעותי הוא היכולת להרחיב ולהתאים. מחלקת הבת לא רק יורשת את תכונות מחלקת הבסיס, אלא גם יכולה להוסיף תכונות חדשות משלה או לשנות את אופן הפעולה של מתודות קיימות. לדוגמה, אם יש לכם מחלקת בסיס 'כלי רכב' עם מתודה 'סע', מחלקת 'מכונית' יכולה לרשת אותה ולהוסיף מתודה 'הדלק מגבים', ומחלקת 'אופנוע' יכולה להוסיף 'הטיה בפנייה'. כך, אתם בונים מערכת גמישה שניתן להרחיב בקלות מבלי לפגוע בקוד הקיים, וזהו עקרון מפתח בפיתוח תוכנה מודרנית.
כשמחלקה יורשת ממחלקה אחרת, היא מקבלת גישה לתכונות ולמתודות הציבוריות (public) והמוגנות (protected) של מחלקת הבסיס. תכונות ומתודות פרטיות (private) של מחלקת הבסיס אינן נגישות ישירות למחלקות היורשות, וזה חשוב להבנת רמת הכימוס. כלומר, יש דברים שההורה שומר לעצמו ואינם עוברים בירושה. הבנה זו של רמות הגישה חיונית כדי לתכנן היררכיות ירושה בצורה נכונה ויעילה, תוך שמירה על עקרונות אבטחת המידע והפרדה בין רכיבי הקוד.
ניקח דוגמה פשוטה כדי להמחיש את הרעיון: נניח שיש לנו מחלקת בסיס בשם 'חיה'. למחלקה זו יש תכונות כמו 'שם' ו'גיל', ומתודות כמו 'אכול' ו'ישן'. כעת, אם נרצה ליצור מחלקה 'כלב', אין צורך לכתוב מחדש את כל התכונות והמתודות הללו. במקום זאת, מחלקת 'כלב' יכולה לרשת מ'חיה'. היא תקבל באופן אוטומטי את 'שם', 'גיל', 'אכול' ו'ישן'. בנוסף, מחלקת 'כלב' תוכל להוסיף תכונות משלה, כמו 'גזע', ומתודות ייחודיות, כמו 'נבח' או 'רדוף אחרי כדור'.
הירושה בעצם מאפשרת לנו לבנות מודלים מורכבים של העולם האמיתי בתוך התוכנה שלנו בצורה מסודרת והגיונית. היא יוצרת קשרים ברורים בין ישויות שונות, ומאפשרת לנו לחשוב על הקוד שלנו במונחים של היררכיות ומשפחות של אובייקטים. זה לא רק עניין של נוחות, אלא גם של עקרונות תכנון נכונים שמובילים לקוד נקי, קריא וקל לתחזוקה לאורך זמן. ככל שהפרויקטים גדלים, חשיבותה של היררכיה ברורה וירושה נכונה הולכת וגוברת.
לסיכום, ירושה היא כלי עוצמתי שמחולל פלאים ביעילות הפיתוח ובתחזוקה של קוד. היא מאפשרת שימוש חוזר חכם, גמישות בהרחבת מערכות, ובניית היררכיות לוגיות שמקלות על הבנה וניהול פרויקטים גדולים. כמו בכל כלי, גם כאן חשוב להשתמש בה בחוכמה ולא להגזים, כדי לא ליצור קשרים מורכבים מדי. עם זאת, כאשר משתמשים בה נכון, הירושה הופכת את הקוד שלכם לאלגנטי יותר, חסכוני יותר במשאבים, וקל יותר לשינוי ולהתאמה לצרכים עתידיים.
פולימורפיזם (Polymorphism)
לאחר שהבנו את עקרון הירושה, הגיע הזמן לצלול למושג עוצמתי לא פחות בתכנות מונחה עצמים: פולימורפיזם. המילה 'פולימורפיזם' מגיעה מיוונית ומשמעותה 'רב-צורתיות' או 'צורות רבות'. בתכנות, היא מתארת את היכולת של אובייקטים שונים להגיב לאותה קריאה לפעולה בדרכים שונות, בהתאם לסוגם הספציפי. דמיינו שלט רחוק אוניברסלי שמפעיל טלוויזיות, ממירים ומכשירי DVD – כל כפתור מבצע פעולה דומה, אך התוצאה הסופית שונה בכל מכשיר. זוהי בדיוק המהות של פולימורפיזם, והיא מאפשרת לנו לכתוב קוד גמיש, אלגנטי וקל לתחזוקה.
כדי להבין זאת טוב יותר, בואו נחזור לדוגמת חיות המחמד שלנו. נניח שיש לנו מחלקה בסיסית בשם `Animal` (חיה), ובה מתודה בשם `makeSound()` (השמע קול). באופן טבעי, חתול וכלב, למרות ששניהם 'חיות', משמיעים קולות שונים לחלוטין. הכלב ינבח ('וואף וואף') והחתול יילל ('מיאו מיאו'). באמצעות פולימורפיזם, אנו יכולים להגדיר את המתודה `makeSound()` במחלקה `Animal`, אך לאפשר למחלקות הנגזרות כמו `Dog` (כלב) ו-`Cat` (חתול) לספק מימוש משלהן לאותה מתודה. כך, למרות ששם המתודה זהה, ההתנהגות בפועל משתנה בהתאם לסוג החיה הספציפי.
הכוח האמיתי של פולימורפיזם מתגלה כאשר אנו משתמשים במצביעים או הפניות למחלקת הבסיס כדי להתייחס לאובייקטים של מחלקות נגזרות. כלומר, נוכל ליצור מצביע מסוג `Animal` שיצביע בפועל על אובייקט מסוג `Dog` או `Cat`. כאשר נקרא למתודה `makeSound()` דרך מצביע ה-`Animal` הזה, C++ 'תדע' באופן אוטומטי באיזו גרסה של המתודה להשתמש – זו של הכלב או זו של החתול. זהו למעשה הקסם של פולימורפיזם בזמן ריצה, והוא חוסך מאיתנו את הצורך לבדוק ידנית את סוג האובייקט בכל פעם.
כדי לאפשר התנהגות פולימורפית כזו, עלינו להשתמש במילת המפתח `virtual` במחלקת הבסיס. כאשר אנו מכריזים על מתודה כ-`virtual` במחלקת הבסיס (לדוגמה: `virtual void makeSound();`), אנו למעשה אומרים למהדר של C++: 'שים לב, ייתכן שמתודה זו תמומש באופן שונה במחלקות נגזרות, ובעת הקריאה לה דרך מצביע או הפניה למחלקת הבסיס, עליך לבדוק את סוג האובייקט האמיתי בזמן ריצה'. זהו מנגנון קריטי שמבטיח שהקריאה למתודה הנכונה תתבצע, גם אם המצביע או ההפניה הם מסוג מחלקת הבסיס. ללא מילת המפתח `virtual`, C++ תבצע קריאה למתודה של מחלקת הבסיס בלבד, ללא קשר לסוג האובייקט האמיתי.
היתרון הגדול של פולימורפיזם הוא הגמישות וההרחבה שהוא מעניק לקוד שלנו. דמיינו שאתם בונים משחק שבו יש סוגים שונים של אויבים, וכל אחד מהם מתנהג אחרת כשהוא 'תוקף'. במקום לכתוב קוד נפרד לכל סוג אויב, או להשתמש בהרבה תנאי `if-else` מסורבלים, אנו יכולים להגדיר מתודת `attack()` וירטואלית במחלקת הבסיס `Enemy`. כל סוג אויב ספציפי (למשל, `Goblin`, `Dragon`) יממש אותה באופן ייחודי. כך, אם נוסיף סוג אויב חדש בעתיד, לא נצטרך לשנות את הקוד הקיים, אלא רק להוסיף מחלקה חדשה שתירש מ-`Enemy` ותממש את מתודת ה-`attack()` שלה.
פולימורפיזם גם משפר באופן ניכר את קריאות הקוד וקלות התחזוקה שלו. כאשר אנו כותבים קוד פולימורפי, אנו יוצרים ממשק אחיד לפעולות שונות, מה שמפשט את הלוגיקה העסקית. במקום לכתוב פונקציות שמקבלות סוגים ספציפיים של אובייקטים, אנו יכולים לכתוב פונקציה אחת שמקבלת מצביע למחלקת הבסיס, והיא תטפל בכל סוגי האובייקטים הנגזרים. זה הופך את הקוד למודולרי יותר, מפחית שכפול קוד מיותר ומקל על איתור ותיקון באגים. זוהי אבן יסוד בתכנון מערכות תוכנה מורכבות.
חשוב להבין כי פולימורפיזם אינו מוגבל רק למתודות וירטואליות בזמן ריצה. ישנם סוגים נוספים של פולימורפיזם ב-C++ המתרחשים בזמן קומפילציה, כגון העמסת פונקציות (Function Overloading) והעמסת אופרטורים (Operator Overloading). העמסת פונקציות מאפשרת לנו להגדיר מספר פונקציות עם אותו שם אך עם פרמטרים שונים, כשהמהדר בוחר את הפונקציה המתאימה על סמך סוגי הארגומנטים. העמסת אופרטורים מאפשרת לנו להגדיר מחדש את התנהגותם של אופרטורים קיימים (כמו `+` או `-`) עבור טיפוסים מוגדרים על ידי המשתמש, מה שהופך את הקוד לאינטואיטיבי יותר.
לסיכום, פולימורפיזם הוא אחד העקרונות המרכזיים והשימושיים ביותר בתכנות מונחה עצמים. הוא מאפשר לנו לכתוב קוד כללי ויעיל, המגיב בצורה חכמה ומותאמת אישית לסוגים שונים של נתונים. על ידי שימוש במתודות וירטואליות, אנו יכולים ליצור מערכות גמישות שקל להרחיב ולתחזק, תוך שמירה על קוד נקי ומאורגן. הבנה מעמיקה של פולימורפיזם תפתח לכם דלתות רבות בעולם התכנות ותאפשר לכם לבנות יישומים חזקים ומודרניים, שיכולים להתמודד עם שינויים ודרישות חדשות בקלות.
כימוס (Encapsulation) והפשטה (Abstraction)
כאשר אנחנו כותבים קוד, אנחנו רוצים שהוא יהיה מסודר, קריא וקל לתחזוקה. אחד העקרונות החשובים שעוזרים לנו בכך בתכנות מונחה עצמים הוא 'כימוס' (Encapsulation). תארו לעצמכם קופסה סגורה שמכילה בתוכה את כל החלקים הפנימיים של מכשיר מסוים. הכימוס עובד בצורה דומה: הוא מאגד יחד נתונים (משתנים) ופעולות (פונקציות) שקשורות לאובייקט אחד, ושומר אותם כיחידה אחת. המטרה העיקרית היא להגן על הנתונים הפנימיים של האובייקט מפני גישה ישירה ושינויים לא מבוקרים מבחוץ, מה שמבטיח את שלמותם.
למה זה כל כך חשוב לכמס? קודם כל, זה מבטיח את 'שלמות הנתונים' – כלומר, שהנתונים הפנימיים של האובייקט יישארו תקינים ולא ישתנו בטעות או בזדון. לדוגמה, אם יש לנו אובייקט של חשבון בנק, אנחנו לא רוצים שמישהו יוכל לשנות את היתרה ישירות, אלא רק דרך פעולות מוגדרות כמו הפקדה או משיכה. בנוסף, הכימוס מפשט את התחזוקה והתיקון של הקוד, כי כל יחידה אחראית על עצמה. הוא גם מאפשר לנו לשנות את המבנה הפנימי של מחלקה בלי להשפיע על שאר חלקי התוכנית שמשתמשים בה, כל עוד הדרך לתקשר איתה נשארת זהה.
בשפת C++, אנחנו מיישמים כימוס באמצעות 'מגדירי גישה' (Access Specifiers) כמו private ו-public. כאשר אנחנו מגדירים משתנה או פונקציה כ-private, פירוש הדבר שהם נגישים רק מתוך המחלקה עצמה, ואף קוד חיצוני לא יכול לגשת אליהם ישירות. לעומת זאת, חברים המוגדרים כ-public נגישים מכל מקום בתוכנית. הרעיון הוא להפוך את הנתונים ל-private ואת הפעולות (מתודות) שמאפשרות לנו לקיים אינטראקציה בטוחה עם הנתונים האלה ל-public. כך אנחנו שולטים באופן מלא על הגישה לנתונים ומונעים שינויים לא רצויים.
ועכשיו נעבור למושג קרוב אך שונה – 'הפשטה' (Abstraction). אם כימוס עוסק בלשים דברים בקופסה ולהגן עליהם, הפשטה עוסקת בלהציג רק את הפרטים החשובים והרלוונטיים, ולהסתיר את כל המורכבות הפנימית. תחשבו על נהיגה ברכב: אתם יודעים איך ללחוץ על דוושת הגז כדי לנסוע, אבל אתם לא צריכים להבין בדיוק איך המנוע עובד, איך הדלק נשרף או איך הגלגלים מסתובבים. הממשק (הגה, דוושות) מפשט את המורכבות ומאפשר לכם להשתמש ברכב ביעילות.
הפשטה היא כלי עוצמתי שמפשט את העולם עבורנו, גם בתכנות. היא מאפשרת לנו להתמקד ב'מה' אובייקט עושה, במקום ב'איך' הוא עושה זאת. על ידי הסתרת הפרטים הפנימיים והמורכבים, היא מפחיתה את העומס המנטלי על המתכנתים ומונעת טעויות. בנוסף, הפשטה מאפשרת גמישות אדירה: אנחנו יכולים לשנות את הדרך שבה משהו מיושם בפנים (למשל, לשפר את יעילות המנוע ברכב) מבלי להשפיע על הדרך שבה משתמשים בו מבחוץ (הדרך שבה נוהגים ברכב נשארת זהה). זה הופך את הקוד לקל יותר לתחזוקה ולשדרוג.
ב-C++, הפשטה מושגת בעיקר באמצעות מחלקות (classes) והגדרת ממשקים ציבוריים (public interfaces). כאשר אנחנו יוצרים מחלקה, אנחנו למעשה מגדירים סוג חדש של אובייקט עם התנהגויות ויכולות מסוימות, תוך הסתרת הפרטים הפנימיים. המתודות הציבוריות של המחלקה הן הממשק שדרכו אנחנו מקיימים אינטראקציה עם האובייקט, בלי לדעת את כל ה'סודות' הפנימיים שלו. למעשה, כימוס הוא טכניקה חיונית שמאפשרת לנו ליישם הפשטה: על ידי הסתרת הנתונים והצגת רק את הפעולות הרלוונטיות, אנחנו יוצרים רמת הפשטה גבוהה יותר.
כדי להבין טוב יותר, נדמיין מתג אור. הכימוס הוא כמו כל החוטים, המנגנונים והנורות שנמצאים בתוך הקיר ובנורה עצמה – הם ארוזים יחד ומוגנים. אנחנו לא רואים אותם או מתעסקים איתם ישירות. ההפשטה היא הפעולה הפשוטה של לחיצה על המתג כדי להדליק או לכבות את האור. אנחנו לא צריכים לדעת את כל הפרטים הטכניים של איך החשמל זורם או איך הנורה עובדת; אנחנו רק צריכים להכיר את הממשק הפשוט – המתג. שניהם יחד מאפשרים לנו לקיים אינטראקציה יעילה ובטוחה עם מערכות מורכבות.