1 / 49

תרגול מס ' 7

תרגול מס ' 7. מבוא ל- C++ הקצאת זיכרון דינאמית namespaces const משתנים מיוחסים קלט/פלט ב- C++ מחלקות. מבוא ל- C++. C++. C++ היא שפת תכנות שנבנתה מעל C C++ מוסיפה מגוון רב של תכונות מתקדמות בעיקר עבור תכנות מונחה עצמים השלד הבסיסי של הקוד בשפה זהה ל- C

effie
Download Presentation

תרגול מס ' 7

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. תרגול מס' 7 מבוא ל-C++ הקצאת זיכרון דינאמית namespaces const משתנים מיוחסים קלט/פלט ב-C++ מחלקות

  2. מבוא ל-C++ מבוא לתכנות מערכות - 234122

  3. C++ • C++היא שפת תכנות שנבנתה מעל C • C++ מוסיפה מגוון רב של תכונות מתקדמות • בעיקר עבור תכנות מונחה עצמים • השלד הבסיסי של הקוד בשפה זהה ל-C • רוב הקוד של C ניתן לקמפול ישירות כ-C++ • נהוג ב-C++ לבצע דברים אחרת תוך שימוש ביתרונות השפה • לא כותבים ב-C++קוד בסגנון C! • לא נהוג להשתמש ב-printf, FILE*, void*ועוד ב-C++ - יש תחליפים עדיפים #include<iostream> usingnamespacestd; intmain(intargc, char** argv) { cout << "Hello world" << endl; return 0; } מבוא לתכנות מערכות - 234122

  4. C++ • כדי לקמפל קוד ++C נשתמש בקומפיילר g++ • אופן השימוש זהה ל-gcc, למעשה gcc הוא g++. • קבצי ה-header הסטנדרטיים של ++C הם ללא סיומת, למשל iostream • קבצים הנכתבים על ידי משתמשים הם בעלי סיומת h כמו ב-C • קבצי ה-source ב-C++ הם בעלי סיומת cpp, cc או C (גדולה) • כדי לכלול קבצי header של C מוסיפים c בתחילת שמם, למשל: #include<cstdio> • C99 ו- C11הם סטנדרטים חדשים של C אשר מוסיפים תכונות פופולריות מ-C++: • אתחול משתנים באמצע בלוק (ובתוך לולאת for או משפט if) • ערכים קבועים - const • שימוש בהערות של שורה אחת // • כל התכונות האלה קיימות ב-C++ ובדרך כלל חשיבותן גבוהה לסגנון השפה מבוא לתכנות מערכות - 234122

  5. הקצאת זיכרון דינאמית new delete מבוא לתכנות מערכות - 234122

  6. הקצאת זיכרון דינאמית • הקצאות זיכרון דינאמיות ב-++C מתבצעות בעזרת האופרטורים newו-delete • ניתן להקצות משתנה חדש (ולאתחלו) על ידי new: int* ptr = newint; // No explicit initialization int* ptr = newint(7); // The new integer is initialized to 7 • ניתן להקצות מערך של משתנים על ידי new[size_t]: int* array = newint[n]; • שחרור של עצם שהוקצה על ידי new מתבצע בעזרת delete: deleteptr; • שחרור של עצם שהוקצה על ידי new[size_t] מתבצע בעזרת delete[]: delete[] array; מבוא לתכנות מערכות - 234122

  7. new ו-delete - דוגמאות int* ptr = newint(5); int* array = newint[*ptr]; // No need to check for NULLs deleteptr; delete[] array; C++ • int* ptr = malloc(sizeof(int)); • if(!ptr) {// handle errors ...} • *ptr = 5; • int* array = malloc(sizeof(*array)* *ptr); • if(!array) {// handle errors ...}free(ptr); • free(array); C • אסורלהתבלבלבין delete ו-delete[] • אסור לערבב את new ו-delete עם malloc ו-free • למשל להקצות עם new ולשחרר עם free • אין צורך לבדוק את ערך המצביע המוחזר מ-new • new אינה מחזירה NULL • טיפול בשגיאות ב-++C מתבצע בעזרת מנגנון החריגות (תרגול 10) מבוא לתכנות מערכות - 234122

  8. הקצאת זיכרון דינאמית - סיכום • ב-C++ משתמשים ב-new ו-new[size_t] כדי להקצות זיכרון חדש • האופטור new מחזיר מצביע מהטיפוס המתאים • אין צורך לבדוק את הצלחת ההקצאה כמו ב-C • ב-C++ משתמשים ב-delete ו-delete[] כדי לשחרר זיכרון • new משחררים עם delete ו-new[size_t] עם delete[] • לא משתמשים ב-malloc ו-free (מלבד המקרה של חיבור קוד C ישן) מבוא לתכנות מערכות - 234122

  9. Namespaces מבוא לתכנות מערכות - 234122

  10. namespace • ב-C++ניתן לאגד מספר פונקציות וטיפוסים בצורה לוגית תחת namespace • בדומה לארגון קבצים בתיקיות namespace math { doublepower(double base, doubleexp); doublesqrt(double number); doublelog(double number); } • לכל פונקציה (או טיפוס או משתנה) המוגדרת ב-namespace יש שם מלא מהצורה <namespace>::<item> • אופרטור :: (קרוי scope) משמש להפרדה בין שמות namespace כאשר מציינים שמות מלאים • כדי לגשת לפונקציה שאינה ב-namespace הנוכחי יש לרשום את שמה המלא, למשל: doubleroot = math::sqrt(10.0); מבוא לתכנות מערכות - 234122

  11. namespace • ניתן להשתמש בהוראת usingכדי לחסוך את כתיבת השם המלא בכל פעם • הוראת using "תעתיק" את הגדרת הפונקציה ל-namespace הנוכחי using math::power; • ניתן להשתמש בהוראות using namespace <name>כדי לבצע using לכל תוכןה-namespace בבת אחת usingnamespace math; • ניתן לקנן namespace אחד בתוך השני: namespacemtm { namespace ex4 { intf(int n); } } • כל ההגדרות מהספריה הסטנדרטית מופיעות תחת ה-namespace הסטנדרטי הקרוי std • מומלץ לא לבצע using namespace stdאלא להשתמש רק בחלקים מהספריה הסטנדרטית הדרושים • ה-namespace הראשי מצוין על ידי :: • מה ההבדל בין f ל-::f? מבוא לתכנות מערכות - 234122

  12. namespace • יתרונות: • ניתן לקבץ בצורה לוגית נוחה פונקציות דומות • ניתן להשתמש בשמות קצרים וברורים יותר ללא חשש להתנגשויות • מאפשר החלפה, מימוש ומיזוג של מימושים שונים בקלות typedefenum { MTM_OUT_OF_MEMORY, /*...*/ } MtmErrorCode; voidmtmPrintErrorMessage(MtmErrorCode error); C C++ namespacemtm { enumErrorCode{ OUT_OF_MEMORY, /*...*/ }; voidprintErrorMessage(ErrorCode error); } מבוא לתכנות מערכות - 234122

  13. namespace - סיכום • ניתן לקבץ קוד בצורה לוגית בעזרת חלוקתו ל-namespace שונים • ניתן להשתמש ב-using כדי להימנע מכתיבת שמות מלאים בקוד • בזכות namespace ניתן לשמור על שמות קצרים וברורים ללא צורך בתחיליות כמו ב-C • הקוד מהספריה הסטנדרטית מופיע תחת ::std מבוא לתכנות מערכות - 234122

  14. קבועים הגדרת משתנים קבועים מצביעים קבועים מבוא לתכנות מערכות - 234122

  15. קבועים - const • בהכרזה על משתנה ניתן להוסיף לשם הטיפוס את המילה השמורה const • לא ניתן לשנות את ערכו של משתנה אשר מוגדר כ-const(קבוע)לאחר אתחולו • לכן חובה לאתחל משתנים קבועים constint n = 5; n = 7; // error: assignment of read-only variable `n' constint m; // error: uninitialized const `m' • ניתן להכריז על פרמטרים וערכי חזרה של פונקציה כ-const: char* strcpy(char* destination, constchar* source); • כותב הפונקציה מתחייב לא לשנות את ערך הארגומנט constchar* studentGetName(Student s); • ניתן להחזיר משתנה פרטי ללא חשש לגרימת נזק מצד המשתמש • נכונות השימוש במשתנים קבועים נאכפת על ידי הקומפיילר מבוא לתכנות מערכות - 234122

  16. קבועים - const • כאשר מוסיפים const להגדרת מצביע ייתכנו מספר אפשרויות: • הכתובתהנשמרת במצביע קבועה • הערךהנשמר במשתנה המוצבע קבוע • ניתן למקם את המילה const במיקום שונה בהגדרת הטיפוס כדי לקבל כל אחת מהתוצאות הרצויות • אם ה-const מופיע ראשוןהוא מתייחס לשם הטיפוס הבא אחריו constint* cptr; • בכל שאר המקרים constמתייחס לשמאלו intconst* cptr2; int* constptr = NULL; // Must be initialized, why? • ניתן לרשום יותר מ-const אחד constint* constptr = NULL; מבוא לתכנות מערכות - 234122

  17. קבועים - דוגמאות • אילו מהשורות הבאות יגרמו לשגיאת קומפילציה? 1) inti = 7; 2) constint ci = 17; 3) constint* pci = &ci; 4) *pci = 7; 5) pci= &i; 6) int* pi = &ci; 7) pci= pi; 8) pi = pci; 9) int* constcpi = &i; 10) *cpi = 17; 11) cpi= &i; 12) int* const cpi2 = &ci; 13) constint* constccpi = &ci; 14) ccpi= &ci; מבוא לתכנות מערכות - 234122

  18. קבועים - הערות נוספות • משתנה אשר קבוע בהקשר אחד אינו בהכרח קבוע: • ב-C++ מגדירים קבועים בעזרת משתנים קבועים (גלובליים אם צריך) במקום בעזרת #define • מאפשר את בדיקת הטיפוס על יד הקומפיילר • מאפשר הגדרת קבועים מטיפוסים מורכבים constint MAX_SIZE = 100; constRational ZERO = rationalCreate(0,1); static constchar* const MONTHS[] = {"JAN","FEB","MAR","APR","MAY","JUN", "JUL", "AUG", "SEP", "OCT", "NOV", "DEC"}; • חשוב להקפיד על שימוש נכון בקבועים (const correctness) כאשר ניתן ב-C++ • הקפידו על const מההתחלה, הוספה מאוחרת של const יוצרת כדור שלג של שינויים voidh() { Xval; // val can be modified g(&val); } voidg(constX* p) { // can't modify *p here } מבוא לתכנות מערכות - 234122

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

  20. משתנים מיוחסים משתנים מיוחסים משתנים מיוחסים קבועים מבוא לתכנות מערכות - 234122

  21. משתנים מיוחסים - Reference • משתנה מיוחס (reference) הוא שם נוסף לעצם קיים • עבור שם טיפוס X, X& הוא רפרנס ל-X int n = 1; int& r = n; // r and n now refer to the same int r = 2; // n = 2 • העצם אליו מתייחס הרפרנס נקבע בהכרזה, לכן חובה לאתחל רפרנס int& r; // error: initializer missing • אתחול הרפרנס שונה מהשמה אליו r = n; // a normal assignment between two ints • לאחר אתחול הרפרנס לא ניתן להפעיל פעולות "על הרפרנס" אלא רק על העצם אליו הוא מתייחס intnn = 0; int& rr = nn; rr++; // nnis incremented to 1 • לא ניתן לשנות את העצם אליו מתייחסים לאחר האתחול מבוא לתכנות מערכות - 234122

  22. משתנים מיוחסים - Reference • אתחול של רפרנס יכול להתבצע רק על ידי lvalue int& x = 1; // error: invalid initialization from temporary value int& y = a+b; // same thing • עבור טיפוס X ניתן להגדיר רפרנס לקבוע - const X& • ניתן לאתחל רפרנס לקבוע גם על ידי ערכים זמניים constint& cx = 1; constint& cy = a+b; • פרמטרים(וערכי חזרה) של פונקציה יכולים להיות רפרנס • הרפרנס יאותחל כך שיתייחס לעצם המועבר לפונקציה (מוחזר מהפונקציה) voidswap(int& a, int& b) { int temp = a; a = b; b = temp; } מבוא לתכנות מערכות - 234122

  23. משתנים מיוחסים - Reference • הפונקציה הבאה מחזירה את האיבר המקסימלי במערך כרפרנס: int& getMax(int* array, int size) { int max = 0; for (int i = 0; i < size; ++i) { if (array[i] > array[max]) { max = i; } } return array[max]; } • רפרנס הוא lvalueבעצמו, לכן ניתן למשל לרשום קוד מהצורה הבאה int array[5] = { 1, 2, 3, 4, 5 }; getMax(array,5) = 0 ; // array[4] = 0 • אסור להחזיר רפרנס למשתנה מקומי • מה יקרה אם נשנה את getMax כך שתחזיר את max? אמנם הקוד הזה נראה מוזר, אך בהמשך נראה שימושים טבעיים עבור החזרת רפרנסים מבוא לתכנות מערכות - 234122

  24. משתנים מיוחסים - Reference • קיים דמיון רב בין X&ל-X* const, עם זאת קיימים גם הבדלים חשובים: • מצביע יכול להצביע ל-NULLבעוד משתנה מיוחס תמיד מתייחס לעצם חוקי • עבור מצביעים יש צורך להשתמש ב-* ו-& כדי לבצע פעולות • ניתן להשתמש בחשבון מצביעים כדי להסתכל על הזיכרון "ליד" המצביע • מומלץ לשלוח פרמטרים כ-const X& כל עוד זה מתאים • עבור משתנים פרימיטיביים (int, floatוכו'...) אין הבדל ולכן אפשר להעביר by value (יותר קצר וקריא) מבוא לתכנות מערכות - 234122

  25. משתנים מיוחסים - סיכום • עבור טיפוס X, הטיפוס X& מאפשר נתינת שם חדש לעצם • לאחר האתחול של X& לא ניתן לשנות את העצם אליו הוא מתייחס • const X& יכול להתייחס לערכים זמניים (X& לא יכול) • ניתן להעביר פרמטרים ולהחזיר ערכים מפונקציות כרפרנסים • אסור להחזיר רפרנס למשתנה מקומי • מומלץ להעביר פרמטרים שאינם פרימיטיביים לפונקציות כ-const X& מבוא לתכנות מערכות - 234122

  26. העמסת פונקציות העמסת פונקציות בחירת פונקציה מתאימה ערכי ברירת מחדל מבוא לתכנות מערכות - 234122

  27. העמסת פונקציות - Function Overloading • ב-C++ פונקציה מזוהה על ידי שמהוגם על ידי מספר וסוג הפרמטרים שלה • בניגוד ל-C בה פונקציה מזוהה על ידי שמה בלבד • מבחינת C++ הפונקציות voidprint(int)ו-voidprint(double)שונות • ניתן ב-C++ לכתוב מספר פונקציות בעלות אותו שם ו"להעמיס" על אותו שם פונקציות שונות עבור טיפוסים שונים • הקומפיילריבחר את הפונקציה המתאימה לפי הארגומנטים בקריאה לה • voidprint(int); • voidprint(double); • voidprint(constchar*); • // ... • print(5); // print(int) called • print(3.14); // print(double) called • print("Hello"); // print(const char*) C++ voidprint_int(int); voidprint_double(double); voidprint_string(constchar*); // ... print_int(5); print_double(3.14); print_string("Hello"); C מבוא לתכנות מערכות - 234122

  28. העמסת פונקציות - בחירת הפונקציה • כדי לבחור את הפונקציה המתאימה הקומפיילר מחפש פונקציה בעלת שם מתאים המקבלת את מספר הפרמטרים המתאים • מבין כל הפונקציות המתאימות הקומפיילר מחפש את הפונקציה שהפרמטרים שלה הם המתאימים ביותר לפי הדירוג הבא • התאמה מדויקת או המרות טריוויאליות (T⇐const T, מערך למצביע) • התאמה בעזרת קידום (bool⇐int, char⇐int, float⇐double וכו'...) • התאמה בעזרת המרות מובנות (int⇐double, double⇐int, T*⇐void* • התאמה בעזרת המרות שהוגדרו על ידי המשתמש (תרגול הבא) • התאמה לפונקציה עם מספר ארגומנטים משתנה (ellipsis ...) (למשל printf) • עבור יותר מפרמטר אחד הקומפיילר מחפש פונקציה שיש לה את ההתאמה הטובה ביותר עבור פרמטר אחד והתאמה שווה או טובה יותר לשאר הפרמטרים • אם קיימות שתי התאמות ברמה הגבוהה ביותר בה נמצאו התאמות אז הקריאה מכילה דו-משמעות והיא לא תתקמפל • בחירת הפונקציה אינה תלויה בערך ההחזרה, לא ניתן לכתוב שתי פונקציות השונות רק בערך ההחזרה שלהן מבוא לתכנות מערכות - 234122

  29. העמסת פונקציות - דוגמאות • אילו מהפונקציות הבאות תיקרא בכל אחת מהקריאות? voidprint(int); voidprint(double); voidprint(constchar*); voidprint(char); voidh(char c, int i, float f, double d, long l) { print(c); print(f); print(d); print(i); print(l); print('a'); print(49); print(0); print("Hello"); } במקרה של דו-משמעות יש להוסיף המרות מפורשות כדי להבהיר לקומפיילר באיזו פונקציה לבחור, למשל: print(int(l)); print(double(l)); העמסות יכולות לסבך את הקוד, השתמשו בהן רק אם קורא הקוד יוכל להבין בקלות מה קורה מהסתכלות על הקריאה לפונקציה מבוא לתכנות מערכות - 234122

  30. ערכי ברירת מחדל • קיימות פונקציות אשר אחד הארגומנטים שלהן הוא ברוב המקרים אותו ערך voidprint(int n, int base); print(6, 10); print(5, 10); print(5, 8); // Print in octal print(17,10); print(14,2); // binary • נוכל לנצל את מנגנון העמסת הפונקציות כדי לפתור בעיה זו: voidprint(int n) { print(n, 10); } • לשם הקלה על מטלה זו ניתן להגדיר ערך ברירת מחדל לפרמטרים עבור פונקציה, ולכן נוכל להגדיר רק פונקציה אחת: voidprint(int n, intbase = 10); מבוא לתכנות מערכות - 234122

  31. ערכי ברירת מחדל • ניתן לתת ערך ברירת מחדל רק לפרמטרים האחרונים של הפונקציה: intf(int n, int m = 0, char* str = 0); // ok intg(int n = 0, int m = 0, char* str); // error inth(int n = 0, int m , char* str = NULL); // error • את ערך ברירת המחדל יש לכתוב פעם אחת בלבד בהכרזת הפונקציה intf(int n = 8); //... intf(int n) { // writing n = 8 again (or any other value) is an error return n; } מבוא לתכנות מערכות - 234122

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

  33. קלט/פלט ב-C++ האופרטורים >> ו-<< הערוצים הסטנדרטיים ב-C++ מבוא לתכנות מערכות - 234122

  34. קלט/פלט ב-C++ • ערוצי הקלט ופלט הסטנדרטיים מיוצגים ב-C++ על ידי המשתנים הגלובליים הבאים (מוגדרים בקובץ iostream): • cout: ערוץ הפלט הסטנדרטי • :cinערוץ הקלט הסטנדרטי • cerr: ערוץ השגיאות הסטנדרטי • כדי להדפיס משתנה כלשהו לערוץ פלט משתמשים באופרטור >> • ניתן להדפיס ירידת שורה ולבצע flush לחוצץ על ידי הדפסת endl • כדי לקלוט ערך למשתנה מערוץ קלט משתמשים באופרטור << • ניתן לשרשרמספר הדפסות/קריאות בבת אחת intmain() { int n; std::cin>> n; // Reads an int from user std::cout<< "You entered " << n << std::endl; return 0; } מבוא לתכנות מערכות - 234122

  35. קלט/פלט ב-C++ • יתרונות: • לא צריך לזכור קודים מוזרים כדי להדפיס • לא ניתן להתבלבל בסוג הטיפוס המודפס • ניתן להרחיב את השימוש בקלט/פלט עבור טיפוסים שיצרנו (בתרגול הבא) #include<iostream> usingstd::cout; usingstd::cerr; usingstd::cin; usingstd::endl; intmain() { int n; constchar* str = "Hello"; int* ptr = &n; cin >> n; cout << str << endl; cerr << n << " at "<< ptr << endl; return 0; } C++ #include<stdio.h> intmain() { int n; constchar* str = "Hello"; int* ptr = &n; fscanf(stdin, "%d", &n); fprintf(stdout, "%s\n", str); fprintf(stderr, "%d at %x\n", n, ptr); return 0; } C מבוא לתכנות מערכות - 234122

  36. קלט/פלט ב-C++ - סיכום • הערוצים הסטנדרטיים מיוצגים ב-C++ על ידי המשתנים cout, cin ו-cerr • מדפיסים לערוצי פלט בעזרת אופרטור >> • קולטים ערכים מערוצי קלט בעזרת << • ההדפסה או הקריאה נקבעים לפי סוג הטיפוס • ניתן להרחיב את שיטה זו עבור טיפוסים שיצרנו בעצמנו (תרגול הבא) מבוא לתכנות מערכות - 234122

  37. מחלקות - Classes מתודות this public ו-private בנאים והורסים משתנים ופונקציות סטטיות מחלקות מחלקת מחסנית מבוא לתכנות מערכות - 234122

  38. טיפוסי נתונים ב-C++ structPoint { intx, y; doubledistance(constPoint& p) { int dx = this->x - p.x; intdy= this->y - p.y; returnsqrt(dx*dx+dy*dy); } }; intmain() { Point p = { 3, 4 }; Point p2 = { 2, 8 }; double d = p.distance(p2); return 0; } • יצירת טיפוסי נתונים הוטמעה בשפת C++ • ב-C++ ניתן להגדיר את הפונקציות עבור טיפוס הנתונים ישירות בתוך המבנה • פונקציות המוגדרות כחלק מהמבנה נקראות מתודות(methods) אופונקציות חברות (member functions) • כדי להפעיל מתודה יש צורך בעצם מהטיפוס המתאים להפעיל אותה עליו • לכל מתודה יש פרמטר נסתר בשם thisוהוא מצביע לעצם עליו היא הופעלה מבוא לתכנות מערכות - 234122

  39. מתודות - Methods structPoint { intx, y; doubledistance(constPoint& p); }; doublePoint::distance(constPoint& p) { int dx = this->x- p.x; intdy = this->y- p.y; returnsqrt(dx*dx+dy*dy); } • מתודות ניתן לממש ישירות בתוך המבנה (כמו בשקף הקודם) או להכריז עליהן במבנה ולממשן מחוץ לו: • הגדרות טיפוסים ב-C++ יופיעו בדרך כלל בקבצי h • אם מימוש הפונקציה נעשה בתוך המבנהאז הוא יופיע בקובץ ה-h • אם מימוש הפונקציה חיצונינשים אותו בקובץ ה-cpp/cc/C המתאים מבוא לתכנות מערכות - 234122

  40. המצביע this structPoint { intx, y; doubledistance(constPoint& p)const; voidset(int x, int y); }; voidPoint::set(int x, int y) { this->x = x; this->y = y; } doublePoint::distance(constPoint& p) const{ int dx = x - p.x; intdy = y - p.y; returnsqrt(dx*dx+dy*dy); } • לכל מתודה של עצם מטיפוס X נשלח מצביע מטיפוס X* constששמו this • ניתןלהשמיטאת ה-thisכל עוד איןדו-משמעות • ניתן להגדיר מתודה כך שתפעל על עצמים שהינם constעל ידי הוספת const בסוף חתימת הפונקציה • עבור מתודה לעצם קבוע thisיהיה מטיפוס const X* const • אם this קבוע עבור מתודה מסוימת גם כל השדות שלו קבועים מדוע לא ניתן להגדיר את set כ-const? מבוא לתכנות מערכות - 234122

  41. בקרת גישה - Access Control structPoint { private: intx, y; public: doubledistance(constPoint& p); voidset(int x, int y); }; // ... intmain() { Point p; p.x = 5; // error: 'intPoint::x' // is private p.set(3, 4); double d = p.distance(p); return 0; } • כדי לשמור על הסתרת המימוש מהמשתמש ניתן להגדיר חלקים פרטיים וחלקים פומביים • קוד אשר כתוב בתוך ה-namespace של הטיפוס רשאי לגשת לחלקים פרטיים • קוד אשר כתוב מחוץ למבנה אינו יכול לגשת לחלקים אלו • ניתן להגדיר פונקציות, שדות וטיפוסים כפרטיים או פומביים • למשל, פונקציות עזר של הטיפוס יוגדרוכ-private מבוא לתכנות מערכות - 234122

  42. מחלקות - Classes • בדרך כלל מגדירים טיפוסים ב-C++ עם המילה השמורה class • ההבדל בין class ל-struct הוא בברירת המחדל עבור בקרת הגישה - public עבור struct ו-private עבור class • נהוג להשתמש ב-struct עבור טיפוסים פשוטים שכל שדותיהם הינם public classPoint { intx, y; public: doubledistance(constPoint& p) const; voidset(int x, int y); }; structPoint{ private: intx, y; public: doubledistance(constPoint& p) const; voidset(int x, int y); }; מבוא לתכנות מערכות - 234122

  43. בנאים - Constructors classPoint { intx, y; public: Point(int x, int y); doubledistance(constPoint& p) const; }; Point::Point(int x, int y) { this->x = x; this->y = y; } intmain() { Point p1(3, 4); constPoint p2(2, 8); cout << p1.distance(p2) << endl; return 0; } • לכל מחלקה ניתן להגדיר סוג מיוחד של מתודות הנקראות בנאים(Constructorsאו C’torבקיצור) ששמן כשם המחלקה • בנאים משמשים לאתחול של עצם חדש מהמחלקה מבוא לתכנות מערכות - 234122

  44. הורסים - Destructors classArray { int* data; intsize;public: Array(int size); ~Array(); // More methods ... }; Array::Array(int size) { data = newint[size]; this->size = size; } Array::~Array() { delete[] data; }intmain() { Array array(50); // code ... return 0; } // d'tor called • לכל מחלקה ניתן להגדיר סוג נוסף של מתודה הקרויה הורס(Destructorאו D’tor) ושמה כשם המחלקה ותחילית ~ • ההורס של המחלקה נקרא אוטומטיתבזמן שחרור עצם של המחלקה • עוד על בנאים והורסים בתרגולים הבאים מבוא לתכנות מערכות - 234122

  45. פונקציות ושדות סטטיים classPoint { intx, y; staticPointorigin;public: Point(int x, int y); doubledistanceFromOrigin() const; staticvoidsetOrigin(int x, int y);};PointPoint::origin(0,0);doublePoint::distanceFromOrigin() const { int dx = x- origin.x; intdy = y- origin.y; returnsqrt(dx*dx + dy*dy);}voidPoint::setOrigin(int x, int y) { origin.x = x; origin.y = y;} • ניתן להגדיר משתנים סטטיים במחלקה, משתנים אלו אינם שייכים לעצם ספציפי • ניתן להגדיר מתודות סטטיות, מתודה סטטית אינה מקבלת thisולא דרוש עצם כדי להפעילה • מתודה סטטית רשאית לגשת לחלקים פרטיים של המחלקה • משתנים ומתודות סטטיים מצייתים לחוקי בקרת הגישה • אם למשל נגדיר משתנה סטטי כפרטי הוא יהיה נגיש רק מתוך המחלקה מבוא לתכנות מערכות - 234122

  46. מחלקת מחסנית • נמיר כעת את המחסנית שלנו מתרגול 5 למחלקה ב-C++ • ב-C++ ערכי שגיאה מטופלים על ידי חריגות(תרגול 10) ולכן לא נהוג להחזיר קודי שגיאה • כדי לכתוב קוד גנרי ב-C++ משתמשים בתבניות(תרגול 10) ולכן נסתפק במחסנית של מספריםשלמים בינתיים classStack { int* data; intsize; intnextIndex; public: Stack(int size = 100); ~Stack(); intgetSize()const; voidpush(int n); voidpop(); int& top(); constint& top() const; }; nextIndex 5 2 17 3 מבוא לתכנות מערכות - 234122

  47. מימוש המחסנית Stack::Stack(int size) { data = newint[size]; this->size = size; nextIndex = 0; } Stack::~Stack() { delete[] data; } voidStack::push(int n) { if (nextIndex >= size) { error("Stack full"); } data[nextIndex++] = n;} intStack::getSize()const{ returnnextIndex;} voidStack::pop() { if (nextIndex <= 0) { error("Stack empty"); } nextIndex--;}int& Stack::top() { if (nextIndex <= 0) { error("Stack empty"); } returndata[nextIndex - 1]; }constint& Stack::top() const { if (nextIndex <= 0) { error("Stack empty");} returndata[nextIndex - 1];} מה ההבדל? מבוא לתכנות מערכות - 234122

  48. שימוש במחסנית • #include"stack.h" • #include<iostream> • usingstd::cout; • usingstd::endl; • intmain() { • Stackstack; • Stack stack2(50); • stack.push(1); • stack.push(213); • stack.pop(); • cout << stack.top() << endl; • return0; • } • #include"stack.h" • #include<stdio.h> • intmain() { • Stackstack = stackCreate(100); • Stackstack2 = stackCreate(50); • stackPush(stack, 1); • stackPush(stack, 213); • stackPop(stack); • printf("%d\n",stackTop(stack)); stackDestroy(stack); • stackDestroy(stack2); • return 0; • } C C++ מבוא לתכנות מערכות - 234122

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

More Related