Presentation is loading. Please wait.

Presentation is loading. Please wait.

תרגול 8 היכרות עם ++C. C++ מעל שפת Cשפת תכנות שנבנתה מעל שפת C CC++ –כמעט כל תכנית ב -C היא גם תכנית ב C++ עד כדי מספר הבדלים קטן C99C שאימץ כמה מהתכונות.

Similar presentations


Presentation on theme: "תרגול 8 היכרות עם ++C. C++ מעל שפת Cשפת תכנות שנבנתה מעל שפת C CC++ –כמעט כל תכנית ב -C היא גם תכנית ב C++ עד כדי מספר הבדלים קטן C99C שאימץ כמה מהתכונות."— Presentation transcript:

1 תרגול 8 היכרות עם ++C

2 C++ מעל שפת Cשפת תכנות שנבנתה מעל שפת C CC++ –כמעט כל תכנית ב -C היא גם תכנית ב C++ עד כדי מספר הבדלים קטן C99C שאימץ כמה מהתכונות C++ C99 - סטנדרט של C, שאימץ כמה מהתכונות של C++ g++הקומפיילר של C++ שאנחנו נשתמש בקורס הוא g++ לקבצי C++ נהוג לתת סיומות –.h לקובץ header, כמו ב -C –.cpp לקובץ מימוש (source file) 2

3 הערות ב C++ // ועד סוף השורה C99 –גם ב -C99 –ניתן להשתמש גם ב -C-style הערות /*... */ int foo(int n) { // this is a C++ comment int i = 7; // this is another C++ comment /* this is a C style comment */ return n+i; } 3

4 הגדרת משתנים ב C++ ב C++ ניתן להגדיר משתנים לא רק בתחילת בלוק –גם ב -C99 int foo(int size){ int i; SetResult setResult; ListResult listResult;... for(i = 0; i < size; ++i)... setResult = setCreate(...); for(i = 0; i < size; ++i)... listResult = listCreate(...);... { int foo(int size){... for(int i = 0; i < size; ++i)... SetResult setResult = setCreate(...); for(int i = 0; i < size; ++i) ListResult listResult = listCreate(...);... { עדיף להכריז על משתנים כמה שיותר קרוב לשימוש הראשון שלהם C before C99 C++/C99 4

5 זיכרון דינמי ב C++: הקצאת עצמים בודדים int *pi = new int ; *pi = 6;... delete pi; int *pi = (int*)malloc(sizeof(int)) ; if(pi == NULL){... /* out of memory */ } *pi = 6;... free(pi); C++ new type new type; delete pointer delete pointer; C malloctype malloc(sizeof(type)); freepointer free(pointer); אין צורך ב -casting אין צורך בבדיקת תוצאה של new 5

6 זיכרון דינמי ב C++: הקצאת מערכים int elements_number =...; int *pi = new int[elements_number]; pi[3] = 6;... delete[] pi; int elements_number =...; int *pi = (int*)malloc(sizeof(int) * elements_number) ; if(pi == NULL){... /* out of memory */ } pi[3] = 6;... free(pi); C++ new type[#elements] new type[#elements]; delete[] pointer delete[] pointer; C malloctype*#elements malloc(sizeof(type)*#elements); freepointer free(pointer); 6

7 זיכרון דינמי ב C++ לא נהוג free/mallocב C++ מותר אך לא נהוג להשתמש בפונקציות free/malloc new/delete –בכל מקרה, אסור לערבב בין new/delete ו - free/malloc freeאסור להפעיל free על הזיכרון שהוקצה על ידי new delete mallocאסור להפעיל delete על הזיכרון שהוקצה על ידי malloc 7

8 זיכרון דינמי ב C++ חייבים להתאים newdeleteחייבים להתאים בין סוגי new ו -delete – delete new – delete אחרי new – delete[]new[] – delete[] אחרי new[] מותר להפעיל NULLמותר להפעיל delete על NULL if(ptr != NULL) { delete ptr; } 8

9 const ב C++ לשם טיפוסקבועתוספת לשם טיפוס, מציינת טיפוס של קבוע const type const –משתנים מסוג const חייבים לאתחלחייבים לאתחל לא ניתן לבצע השמהלא ניתן לבצע השמה C99קיים גם ב -C99 #define MAX_SIZE 120 const int maxSize = 120; C before C99 C++/C99 9

10 const ב C++ i = 7; // OK. initialization to 7 const int i = 7; // OK. initialization to 7 i = 17; // error: assignment to a const variable j; // error: definition of a const variable const int j; // error: definition of a const variable // without initialization // without initialization // assignment of a const variable to a int k = i; // assignment of a const variable to a // non const variable // non const variable const int intArray[] = { 7, 17, 27, 777 } // error: assignment to a const intArray[2] = 8; // error: assignment to a const שימו לב להבדל בין אתחול להשמה 10

11 מצביעים ל -const ב C++ להגדיר מצביעיםניתן להגדיר מצביעים לטיפוסים קבועים const type* למשל, const int* pi; מצביע pi הוא משתנה מסוג מצביע ל - const int –יכול להחזיק כתובות של משתנים מסוג const int typeconst type*ניתן לבצע השמה של כתובת של משתנה מטיפוס type לתוך מצביע מטיפוס const type* ניתן להמיר –בפרט, ניתן להמיר int* ל const int*- –אך לא להפך 11

12 מצביעים ל -const ב C++ באילו ביטוים יש שגיאה ? const int i = 7; const int* cpi = &i; *cpi = 17; int j = 17; int* pi = &j; cpi = &j; cpi= pi; pi = cpi; 12

13 שימוש ב -const בפונקציות : פרמטרים פרמטרים לפונקציהניתן להגדיר כ - const פרמטרים לפונקציה –חשוב מאוד מצביעים –חשוב מאוד עבור פרמטרים שהם מצביעים /* this function changes values pointed by i,f does not change values pointed by c,d */ int foo(int* i, char* c, float*f, double* d); int foo(int* i, const char* c, float*f, const double* d); C before C99 C++/C99 חוסך תיעוד הקומפיילר מוודא שלא משנים פרמטרים שהם const 13

14 שימוש ב -const בפונקציות : ערכי חזרה ערכי חזרה של פונקציהניתן להגדיר כ - const ערכי חזרה של פונקציה –חשוב מאוד מצביעים –חשוב מאוד עבור ערכי חזרה שהם מצביעים /* please do not change the returned string !!! */ char* foo(int i); const char* foo(int i); C before C99 C++/C99 חוסך תיעוד הקומפיילר מוודא שלא משנים ערכי חזרה שהם const 14

15 Reference type& = ; שם נוסף reference הוא שם נוסף למשתנה קיים לדוגמה : &int referenceint הביטוי &int משמעותו reference לטיפוס int לא לבלבל " הכתובת של משתנה "x – לא לבלבל עם &x שמשמעותו " הכתובת של משתנה "x בפועל מתבצעתכל פעולה שמפעילים על reference, בפועל מתבצעת על המשתנה שה -reference מתייחס אליו int i = 7; int &j = i; 15

16 Reference חייב להיות מאותחל reference חייב להיות מאותחל לא ניתן לשנותלאחר האתחול לא ניתן לשנות את המשתנה שה -reference מתייחס אליו int i = 8 ; int &j = i; int x = i; i = 5 ; // i = j = 5, x = 8 j++; // i = j = 6, x = 8 j = x; // i = j = 8, x = 8 j = 7; // i = j = 7, x = 8 שימו לב : ההשמה מתבצעת ל -i j ממשיך להתייחס ל -i 16

17 השימוש העיקרי ב -Reference העברתפרמטרים החזרת ערכי חזרההעברת פרמטרים לפונקציות / החזרת ערכי חזרה ב -C העברת פרמטרים מתבצעת – by value – by pointer by referenceב C++ קיימת גם העברה by reference דוגמא : void foo(int &i) { i++; } int x = 7; foo(x); //error foo(5); //error 17

18 השימוש העיקרי ב -Reference כמו במקרה של העברה by pointer משתמשים בהעברה by reference כאשר תשנה משתנים מחוצה לה –רוצים שהפונקציה תשנה משתנים מחוצה לה –אובייקטים גדולים –אובייקטים גדולים - לא רוצים להעביר by value ולהעתיק void swap(int* p, int* q) { int t = *p ; assert(p != NULL); assert(q != NULL); *p = *q; *q = t ; } swap(&x,&y); void swap(int& p, int& q) { int t = p ; p = q; q = t ; } swap(x,y); // OK swap(x,5) ; // Error CC++ 18

19 הבדלים בין reference למצביע אתחולאתחול – reference חייב להיות מאותחל –מצביע לא חייב להיות מאותחל ערך NULLערך NULL –מצביע יכול להכיל ערך NULL –אין ל -reference ערך NULL. הוא חייב להתייחס למשתנה כלשהו שינוי הצבעה / התייחסותשינוי הצבעה / התייחסות –מצביע יכול לשנות משתנה שהוא מצביע אליו – reference יכול להתייחס למשתנה אחד בלבד 19

20 דוגמא נוספת לשימוש ב -reference int& arrayBounds (int* array, int size, int& max, int& min) { int i,sum = 0 ; max = min = array[0]; for (i=0 ; i<size; i++) { if (max < array[i]) max = array[i]; if (min > array[i]) min = array[i] ; sum += array[i] ; } return array[size/2]; } מוחזר reference לאיבר האמצעי במערך מה היה קורה אם היינו מחזירים sum ? 20

21 Function Overloading: הבעיה פונקציה מקסימום של שני שלמיםנניח, אנחנו רוצים לכתוב ב -C פונקציה שמחזירה מקסימום של שני שלמים : int max(int x, int y); פונקציה מקסימום של שלושה שלמיםנניח שבנוסף אנחנו רוצים פונקציה שמחזירה מקסימום של שלושה שלמים. – איזה שם ניתן לה ? –השם max כבר תפוס על ידי פונקציה קודמת int max3(int x, int y, int z); פונקציה מקסימום של שני floatsואם נרצה פונקציה שמחזירה מקסימום של שני floats ? float max_float(float x, float y); 21

22 Function Overloading: הפתרון ב C++ אותו שם לכל פונקציותאותו שם לכל פונקציות המקסימום ! max int max(int x, int y); max int max(int x, int y, int z); max float max(float x, float y); מאמץ מחשבתיחוסכים מאמץ מחשבתי בהמצאת שמות חדשים קצרים וטבעייםהשמות יוצאים קצרים וטבעיים יותר קריאות –משפר קריאות 22

23 Function Overloading: איך זה עובד ? השםוגם הפרמטריםהפונקציה מזוהה על ידי השם שלה וגם על ידי הפרמטרים שהיא מקבלת קריאה לפונקציהכשהקומפיילר מזהה קריאה לפונקציה כלשהיא הוא המועמדות –מחפש כל הפונקציות עם אותו שם - המועמדות להיקרא המועמדותשמתאימה ביותר לפי הפרמטרים –מבין כל המועמדות, מחפש פונקציה שמתאימה ביותר לפי הפרמטרים " מנצחת יחידה "אם יש " מנצחת יחידה " היא זאת שנקראת " מנצחת יחידה " שגיאת קומפילציהאם אין " מנצחת יחידה " יש שגיאת קומפילציה –דו - משמעות (ambiguity) 23

24 :Function Overloading כללים להתאמה 1.exact match trivial conversions 1.exact match ( + trivial conversions: int ->int&, int to const int) promotions 2.match with promotions (char,short int -> int, float->double) conversions 3.match with conversions (int->float, float -> int) user defined type conversions 4.match with user defined type conversions ellipsis 5.match with ellipsis (…) נלמד user defined type conversions בהמשך elipsis מחוץ לחומר של הקורס 24

25 :Function Overloading כללים להתאמה לא נבדלות ערך מוחזרהפונקציות לא נבדלות על ידי ערך מוחזר אסור עם אותו שם ואותם פרמטריםאסור שיהיו שתי פונקציות עם אותו שם ואותם פרמטרים –שגיאת קומפילציה foo(int i, float f) int foo(int i, float f) {... } foo(int i, float f) float foo(int i, float f) {... } שגיאת קומפילציה : foo עם הפרמטרים int ו - float כבר מוגדרת 25

26 :Function Overloading דוגמא 1.void print(int); 2.void print(const char *); 3.void print(double); 4.void print(long); char c; int i ; short s; float f; print(c); print(i); print(s) ; print(f) ; print(‘a’); print(45); print(0.0) ; print (“a”); 26

27 :Function Overloading דוגמא לדו משמעות 1.void foo(int i, float f); 2.void foo(float f, int i); int x,y; foo(x,y); // error - no best matching function foo(x,(float)y); // OK. the first foo is called foo((float)x,y); // OK.the second foo is called 27

28 Default Parameters: המוטיבציה שברוב המקריםערך קבועפרמטרקיימות פונקציות שברוב המקרים מקבלים ערך קבוע עבור פרמטר כלשהו במקרים נדירים ערך אחר –ורק במקרים נדירים ערך אחר הדפסת מספרים בבסיסים שוניםלרבלדוגמא : הדפסת מספרים בבסיסים שונים. לרב הבסיס יהיה 10 28

29 Default Parameters: המוטיבציה 29 void print_number(int n, int base ) ; void foo() {... print_number (24,8); print_number (12,10); print_number (x,10); print_number (y,10); print_number (16,2); print_number (24,10); print_number (12,10); print_number (x+2,10); print_number (y-7,10); print_number (30,16); print_number (24,10); print_number (12,10); print_number (x+2,10); print_number (y-7,10); print_number (30,10); } ברוב המקרים הפרמטר השני הוא 10. האם אפשר לחסוך את כתיבתו ?

30 Default Parameters: המוטיבציה Function Overloadingהפתרון האפשרי - שימוש ב -Function Overloading שתי פונקציותמגדירים שתי פונקציות : void print_number(int n, int base ); // print number in base 10 void print_number(int n) ; void print_number(int n) { print_number(n,10); } 30 שתי הפונקציות עושות כמעט אותו דבר. איך נמנע שיכפול קוד ?

31 Default Parameters: המוטיבציה 31 void print_number(int n, int base ) ; void foo() {... print_number (24,8); print_number (12,10); print_number (x,10); print_number (y,10); print_number (16,2); print_number (24, 10); print_number (12,10); print_number (x+2,10); print_number (y-7,10); print_number (30,16); print_number (24,10); print_number (12,10); print_number (x+2,10); print_number (y-7,10); print_number (30,10); } void print_number(int n, int base ) ; void print_number(int n) { print_number(n,10); } void foo() {... print_number (24,8); print_number (12); print_number (x); print_number (y); print_number (16,2); print_number (24); print_number (12); print_number (x+2); print_number (y-7); print_number (30,16); print_number (24); print_number (12); print_number (x+2); print_number (y-7); print_number (30); }

32 Default Parameters לחסוךכתיבת שתי הפונקציההאם אפשר לחסוך את כתיבת שתי הפונקציה print_number ? פרמטר ברירה מחדלהפתרון ב C++ - פונקציה אחת עם פרמטר ברירה מחדל (default parameter) = 10 void print_number(int n, int base = 10); שני פרמטרים כרגילכשקוראים לפונקציה עם שני פרמטרים, הקריאה מתבצעת כרגיל פרמטר אחדאוטומטית ערך ברירה מחדלכשקוראים לפונקציה עם פרמטר אחד, אוטומטית מוצב ערך ברירה מחדל במקום הפרמטר השני כרגיל –הפונקציה מתבצעת כרגיל, כאילו שקראו לה עם שני פרמטרים 32

33 Default Parameters זהותשתי הקריאות זהות מבחינת הפונקציה : 1.print_number(17,10); 2.print_number(17); אין שינוי מימושהצהרתהאין שינוי במימוש של הפונקציה - רק בהצהרתה רק פעם אחתאת ברירות מחדל של פרמטרים מציינים רק פעם אחת –בד '' כ בהצהרה על הפונקציה ב -header file void print_number(int n, int base = 10); void print_number(int n, int base) {... } 33

34 Default Parameters לפרמטרים האחרוניםניתן לתת ערכי ברירת מחדל רק לפרמטרים האחרונים : int foo(int a = 0, int b = 0, int c = 0); // OK int bar(int a, int b = 0, int c = 0); // OK int baz(int a = 0, int b = 0, int c); // Error int f(int a = 0, int b, int c = 0); // Error 34

35 Default Parameters 35 void print_number(int n, int base ) ; void print_number(int n) { print_number(n,10); } void foo() {... print_number (24,8); print_number (12); print_number (x); print_number (y); print_number (16,2); print_number (24); print_number (12); print_number (x+2); print_number (y-7); print_number (30,16); print_number (24); print_number (12); print_number (x+2); print_number (y-7); print_number (30); } void print_number(int n, int base = 10) ; void foo() {... print_number (24,8); print_number (12); print_number (x); print_number (y); print_number (16,2); print_number (24); print_number (12); print_number (x+2); print_number (y-7); print_number (30,16); print_number (24); print_number (12); print_number (x+2); print_number (y-7); print_number (30); }

36 מימוש ADTs ב ++C

37 מבנה הנתונים מחסנית תזכורת מחסנית הינה מבנה נתונים התומך בפעולות הבאות : push - הוסף איבר למחסנית. pop - הוצא את האיבר ה ” צעיר ” ביותר במחסנית. top - החזר את האיבר ה ” צעיר ” ביותר במחסנית. ובנוסף : create - צור מבנה נתונים מסוג מחסנית ( ריק ). destroy - הרוס את מבנה הנתונים מחסנית. print - הדפס את תוכן מבנה הנתונים. 128 top דוגמא למימוש אפשרי: מערך + מצביע למקום הפנוי הבא 37

38 ADTs ב ++C לעומת C ב -C מימשנו ADT בצורה הבאה : הממשק –קובץ header הכיל את הממשק הטיפוסהוגדר בו הטיפוס של ה -ADT פונקציותהוצהרו בו פונקציות המטפלות ב - ADT המימוש –בקובץ המימוש ((source הופיע המימוש של הפונקציות ב ++C הוטמעה צורת עבודה זו בשפה ניתן להגדיר טיפוסים ( מחלקות - classes) אשר כוללים בתוכם טיפוס –שדות של כל משתנה מאותו טיפוס ( אובייקט של אותה מחלקה ) –פונקציות –פונקציות ( מתודות ) המופעלות עליו 38 בשפות מונחות עצמים נהוג לקרוא לפונקציות ששייכות למחלקות - " מתודות " שמות נוספים : שיטה, method, member function

39 מימוש ב ++Header File :C enum Result {Success, Fail} ; struct Stack { int* array; int size, topIndex ; } ; שדות data members פונקציות של המחלקה method or member functions Result init (int initSize) ; void destroy() ; Result push (int element); Result pop (); Result top(int& element); Result print() ; 39

40 מימוש ב ++C:Source File Result Stack::init (int initSize) { array = new int[initSize]; size = initSize; topIndex = 0 ; return Success ; } ערך מוחזר מסמן שזוהי method של class Stack שם ה -method גישה ישירה לשדות של ה - struct כאילו הם משתנים לוקליים 40

41 מימוש ב ++C:Source File void Stack::destroy () { delete[] array; } Result Stack::push(int element) { if (topIndex == size){ return Fail ; } array[topIndex] = element; topIndex++; return Success; } 41

42 מימוש ב ++C:Source File Result Stack::pop () { if (topIndex == 0){ return Fail; } topIndex--; return Success; } Result Stack::top (int& element) { if (topIndex < 1){ return Fail; } element = array[topIndex-1]; return Success; } 42

43 שימוש ב -Stack ב ++C לעומת C 43 #include “Stack.h” int main() { Stack stack; int i; init (&stack,100) ; push (stack,1); push(stack,213); pop (stack); top(stack,&i); destroy(stack); return 0; } #include “Stack.h” int main() { Stack stack; int i; stack.init (100) ; stack.push (1); stack.push(213); stack.pop (); stack.top(i); stack.destroy(); return 0; } CC++ קריאה לפונקציה מתבצעת בדיוק כמו גישה לשדה

44 המצביע this שימו לב לאופן השונה בו נקראו הפונקציות ב - C וב ++C להעביר מצביע לאובייקט – ב -C נדרשנו להעביר מצביע לאובייקט ( מבנה ) עליו על הפונקציה לעבוד באופן שונה –ב ++C קראנו לפונקציה של המחלקה באופן שונה : stack.top(i); לאיזה אובייקטכיצד הפונקציה יודעת לאיזה אובייקט התכוונו כאשר קראו לה ? 44

45 המצביע this פרמטר סמוי thisהתשובה : כאשר נקראת מתודה כלשהי נשלח לה פרמטר סמוי בשם this מצביע למחלקה –טיפוסו הנו מצביע למחלקה בה מוגדרת המתודה מצביע לאובייקט –מכיל מצביע לאובייקט עליו נקראה המתודה בכל גישה שדהמתודה thisבכל גישה לשדה של האובייקט או למתודה שלו מתוך מתודה אחרת הקומפיילר מוסיף הצבעה דרך this void Stack::top(int& e) { e = array[topIndex-1]; } void Stack::top(int& e) { e = this->array[this->topIndex-1]; } המתודה, לאחר שהקומפיילר הוסיף את המצביע this 45

46 הביעה : הסתרת מידע struct Stack { int* array; int size, topIndex ; Result init (int size) ; void destroy() ; Result push (int e); Result pop (); Result top(int& e); Result print(); } ; 46 מה הבעיה עם המחלקה הזאת ? רמז : איזה עיקרון חשוב של ADT הופר פה ? אין הסתרת מידע ! כל השדות חשופים ! המשתמש יכול לגשת לשדות של המחלקה ישירות ולעקוף את הפונקציות

47 הפתרון : בקרת גישה לא מסתירים את מבנהב C++ להבדיל מ -ADTs ב -C לא מסתירים את מבנה המחלקה ( השדות שלה ) מגבילים גישהבמקום זה מגבילים גישה לשדות שלה –וגם לפונקציות " הפנימיות " של ADT access modifiersמשתמשים ב -access modifiers ( מאפייני גישה ) – private – private ( פרטי ) רק הפונקציות של המחלקהרק הפונקציות של המחלקה יכולות לגשת לאיברים שהם private – public – public ( ציבורי ) כל פונקציהכל פונקציה יכולה לגשת לאיברים שהם public 47

48 מחלקה Stack עם access modifiers 48 struct Stack { int* array; int size, topIndex ; Result init (int size) ; void destroy() ; Result push (int e); Result pop (); Result top(int& e); Result print(); } ; struct Stack { private: int* array; int size, topIndex ; public: Result init (int size) ; void destroy() ; Result push (int e); Result pop (); Result top(int& e); Result print(); } ;

49 הפתרון : בקרת גישה יכול לראותהמשתמש של המחלקה יכול לראות את כל השדות –וגם את כל הפונקציות הפנימיות של המחלקה לא יכול לגשתהמשתמש לא יכול לגשת לאיברים שהם private –לקרוא ערכים –לקרוא ערכים של השדות –לכתוב –לכתוב לתוך השדות –להפעיל –להפעיל פונקציות פנימיות (private) 49

50 שמוש ב -class במקום struct מחלקות class structמקובל להגדיר מחלקות על ידי המילה השמורה class ולא struct struct classההבדל בין struct ל- class: classprivate –ב-class, אם לא צוין אחרת, אופן הגישה הנו private structpublic –ב-struct, אם לא צוין אחרת, אופן הגישה הנו public struct נהוג למחלקות ללא מתודותב-struct נהוג למשתמש לייצוג מחלקות ללא מתודות 50

51 struct Stack { private: int* array; int size, topIndex ; public: Result init (int size) ; void destroy() ; Result push (int e); Result pop (); Result top(int& e); Result print(); } ; שמוש ב -class במקום struct 51 class Stack { int* array; int size, topIndex ; public: Result init (int size) ; void destroy() ; Result push (int e); Result pop(); Result top(int& e); Result print(); } ;

52 בקרת גישה : Friend functions class Stack { friend friend int second (const Stack &); int* array; int size, topIndex; public: … } int second(const Stack stack&) { assert(stack.topIndex > 1); return stack.array[stack.topIndex-2]; } בצורה סלקטיביתניתן לתת גישה לחלק הפרטי של המחלקה בצורה סלקטיבית friends –מגנון friends פונקציה friend המחלקהניתן להכריז על פונקציה כלשהיא כחברה (friend) של המחלקה לגשת לשדות הפרטיים המחלקה –אז היא יכולה לגשת לשדות הפרטיים של המחלקה 52

53 Friend classes and Methods class A { …. int foo(); … }; class B { … }; class C { friend int A::foo(); friend class B; }; מחלקה שלמהכחברהניתן להכריז על מחלקה שלמה כחברה של מחלקה כלשהיא –אז כל המתודות שלה חברות –אז כל המתודות שלה הן חברות של המחלקה 53 method foo() of class A is a friend of class C all methods of class B are friends of class C

54 Friends ב C++: נקודות נוספות שמחלקה A חברה של מחלקה B לא נגררשמחלקה B היא חברה של מחלקה Aמהעובדה שמחלקה A חברה של מחלקה B לא נגרר שמחלקה B היא חברה של מחלקה A שמחלקה A חברה של מחלקה B ומחלקה B חברה של מחלקה C לא נגרר שמחלקה A היא חברה של המחלקה Cמהעובדה שמחלקה A חברה של מחלקה B ומחלקה B חברה של מחלקה C לא נגרר שמחלקה A היא חברה של המחלקה C 54

55 מודולאריות, הסתרת מידע ו -friends להסתירמחלקה טובה צריכה להסתיר כמה שיותר " פאראנוידית " –כמה שיותר " פאראנוידית " לגבי השדות שלה לא נחוץמשתמשים חיצוניים private –כל מה שלא נחוץ לשימוש שלה על ידי משתמשים חיצוניים צריך להיות private בררנית " החברים " –כמה שיותר בררנית לגבי " החברים " שלה סוציומאטית "friends –כמה שיותר " סוציומאטית "- כמה שפחות friends friend פוגעתכל הוספה של friend פוגעת במודולאריות והסתרת מידע 55

56 const member functions: מוטיבציה פונקציה כפרמטרנניח יש לנו פונקציה שמקבלת כפרמטר const Stack& const Stack& : void foo(const Stack& stack) {... stack.top(i);... stack.push(j); stack.print(); } 56 מה הבעיה בפונקציה הזאת ? הפונקציה מקבלת פרמטר const, אך משנה אותו על ידי פונקציה push

57 const member functions אובייקט const רק למתודות constהפתרון ב C++: על אובייקט שהוא const מותר לקרוא רק למתודות שהן const המתודה const const בסוף החתימהניתן להכריז על המתודה כ -const על ידי הוספת מילה שמורה const בסוף החתימה שלה 57 class Stack { int* array; int size, topIndex ; : public: Result init (int size) ; void destroy() ; Result push (int element); Result pop(); Result top(int& element); Result print(); } ; class Stack { int* array; int size, topIndex ; : public: Result init (int size) ; void destroy() ; Result push (int element); Result pop(); const Result top(int& element) const; const Result print() const; } ;

58 const member functions void foo(const Stack& stack) {... stack.top(i); // OK, top is a const function... stack.push(j); // Error ! Calling a non-const // function on a const object stack.print(); // OK, top is a const function } 58

59 const member functions מתודה const חלק מחתימתההגדרת מתודה כ - const מהווה חלק מחתימתה שתי מתודות אותו שם ואותם פרמטרים constיתכנו שתי מתודות עם אותו שם ואותם פרמטרים, אך אחת const והשנייה לא class C { … int foo();// will be called for non const objects int foo() const; //will be called for const // objects }; 59

60 Const Correctness const בטיחותיתככל שתשתמשו ב -const יותר - התוכנה תהיה בטיחותית יותר משתנה שלא אמור להשתנות עדיף שיהיה const –כל משתנה שלא אמור להשתנות עדיף שיהיה const פרמטר לא אמורה לשנות צריך להיות const –כל פרמטר של פונקציה by pointer או by reference שהפונקציה לא אמורה לשנות - צריך להיות const פונקציהשלא משנה את האובייקט צריכה להיות const –כל פונקציה, שלא משנה את האובייקט עליו היא נקראת, צריכה להיות const יתרונות : 1. תיעוד 2. וידוא אוטומטי על ידי הקומפיילר 60

61 הבעיה : התנגשות של שמות תוכנה בנקאיתהבעיה : נניח אנחנו כותבים תוכנה בנקאית כמה חבילותהתוכנה מורכבת מכמה חבילות - packages) חלקי קוד גדולים ) 1.Clients 2.Investments 3.GUI 4.DB בכל אחת מהחבילותבכל אחת מהחבילות קיימת מחלקה Account ופונקציה reportError התנגשות של שמותאיך נמנע התנגשות של שמות ? איך נבדיל איך נבדיל בין Account של Client וה -Account של GUI ? 61

62 הפתרון של C נוסיף קידומתנוסיף קידומת לכל שם בכל חבילה : 62 class clientsAccount {... }; void clientsPrintError(char*); class investmentsAccount {... }; void investmentsPrintError(char*); class dbAccount {... }; void dbPrintError(char*); class guiAccount {... }; void guiPrintError(char*);

63 הפתרון של C: החסרונות להוסיף קידומת לכל שםצריך להוסיף קידומת לכל שם –שמות ארוכים ופחות טבעיים בקריאותפגיעה בקריאות –עבודה שחורה –קשה לשנות –קשה לשנות שם של חבילה לעבור על כל הקידומותצריך לעבור על כל הקידומות ולשנות אותן 63

64 הפתרון של C++: namespaces 64 namespace Clients { class Account {... }; void printError(char*); } namespace Investements{ class Account {... }; void printError(char*); } namespace DB { class Account {... }; void printError(char*); } namespace GUI{ class Account {... }; void printError(char*); }

65 שימוש בשמות של עם namespace void foo() { Clients::Account account;... Clients::printError(...);... GUI::printError(...); } 65

66 namespaces: הוראה using לחסוך usingניתן לחסוך ציון namespace על ידי שימוש בהוראה using : using namespace Clients; void foo() { Account account;... printError(...);... GUI::printError(...); } 66

67 namespaces: הוראה using יותר ספציפיים רק על מה שבאמת משתמשים בועדיף להיות יותר ספציפיים ולהפעיל using רק על מה שבאמת משתמשים בו –ולא להכליל כל השמות ללא צורך –ולא להכליל את כל השמות ב -namespace ללא צורך using Clients::Account; using Clients:: printError; void foo() { Account account;... printError(...);... GUI::printError(...); } 67

68 קלט / פלט ב ++C “הזרמת” נתוניםב ++ C קלט ופלט מתבצע ע”י “הזרמת” נתונים באמצעות האופרטורים >> ו-<<. משתמשים בערוצים (streams) הערוצים הסטנדרטיים הם – cin - ערוץ הקלט הסטנדרטי, כמו stdin ב -C – cout - ערוץ הפלט הסטנדרטי, כמו stdout ב -C – cerr - ערוץ השגיאות הסטנדרטי, כמו stderr ב -C iostream –מוגדרים בקובץ header סטנדרטי iostream ב -C++ קבצי ה -header הסטנדרטיים הם ללא סיומת.h std –נמצאים ב -namespace std 68

69 קלט / פלט ב ++C 69 #include int i = 17, j; double d; fprintf (stdout,“%s %d”, “A string”, i); fscanf (stdin, “%d %lf”, &j, &d); fprintf(stderr, “Error !\n”); #include using std::cin; using std::cout; using std::cerr; using std::endl; int i = 17, j; double d; cout << "A string " << i; cin >> j >> d; cerr << “Error!” << endl; C C++

70 קלט / פלט ב ++C: היתרונות הקומפיילר מזהה הטיפוסים בעצמוהקומפיילר מזהה את הטיפוסים של המשתנים בעצמו –חוסך התעסקות –חוסך התעסקות עם %d, %lf, %s וכו ' –חוסך טעיות –קוד קצר יותר וקריא יותר על משתנים ולא על הכתובותהקלט עובד על משתנים ולא על הכתובות שלהם –חוסך טעויות –חוסך טעויות ב -scanf/fscanf –קוד קצר יותר וקריא יותר 70

71 inline functions תקורה יקרהקריאה לפונקציות הינה פעולה בעלת תקורה יקרה יחסית –הכנה של מחסנית הקריאות –ביצוע קפיצה לפונקציה –ביצוע קפיצה חזרה פונקציות קטנות כדאי לחסוךעבור פונקציות קטנות יכול להיות כדאי לחסוך מחיר זה MACROב -C היינו משתמשים ב -MACRO inline functionב ++C נשתמש ב -inline function 71

72 inline functions inline function שהמתכנת ממליץ לקומפיילר inline inline function היא פונקציה שהמתכנת ממליץ לקומפיילר לבצע לה inline –לשתול קוד של פונקציה במקומות שקוראים לה בדומה ל -MACRO אך עם יתרונות של פונקציה - בדיקת פרמטרים וכו ' מופיעה בקובץ.hמופיעה בקובץ.h הקומפיילר יבחרהקומפיילר יבחר האם לבצע inline לפי השיקולים שלו –לא תמיד אפשר –לא תמיד אפשר - רקורסיה –לא תמיד כדאי –לא תמיד כדאי - tradeoff בין חיסכון בפקודות לבין שיכפול קוד מכונה ( גודל קובץ ההרצה ) 72

73 :inline functions דרך אחת כחלק מהגדרת המחלקהמימוש של inline function כחלק מהגדרת המחלקה : class Stack { public: int getSize() { return size ; }... private: int size;... } 73

74 :inline functions דרך שנייה הוספת inline לפני המימושהוספת inline לפני המימוש של הפונקציה. ממומשת ב -header file – בכל מקרה על פונקציה זו להיות ממומשת ב -header file class Stack { public: int getSize();... private: int size;... }; inline int Stack::getSize() { return size ; } 74


Download ppt "תרגול 8 היכרות עם ++C. C++ מעל שפת Cשפת תכנות שנבנתה מעל שפת C CC++ –כמעט כל תכנית ב -C היא גם תכנית ב C++ עד כדי מספר הבדלים קטן C99C שאימץ כמה מהתכונות."

Similar presentations


Ads by Google