תכנות מכוון עצמים ו‪++C -‬‬ ‫יחידה ‪01‬‬ ‫מ‪ C -‬ל‪++C -‬‬ ‫קרן כליף‬

Содержание

Слайд 2

ביחידה זו נלמד: הגדרת תכנות מכוון עצמים השוני הסינטקטי בין C

ביחידה זו נלמד:

הגדרת תכנות מכוון עצמים
השוני הסינטקטי בין C ל- C++:
printf

? cout
scanf ? cin
gets ? cin.getline
malloc ? new
free ? delete
טיפוס התייחסות
מרחבי שמות (namespace)

© Keren Kalif

Слайд 3

מה אנחנו יודעים? תכנות פרוצדורלי בקורס C למדנו לתכנת במתודלוגיה הנקראת

מה אנחנו יודעים? תכנות פרוצדורלי

בקורס C למדנו לתכנת במתודלוגיה הנקראת תכנות

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

© Keren Kalif

Слайд 4

מה נלמד? תכנות מכוון עצמים בקורס זה נלמד מתודולוגית תכנות הנקרא

מה נלמד? תכנות מכוון עצמים

בקורס זה נלמד מתודולוגית תכנות הנקרא "תכנות

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

© Keren Kalif

Слайд 5

לתכנות מכוון עצמים 3 עקרונות מרכזיים הסתרה (encapsulation): כל הנתונים והפעולות

לתכנות מכוון עצמים 3 עקרונות מרכזיים

הסתרה (encapsulation): כל הנתונים והפעולות הקשורות

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

© Keren Kalif

Слайд 6

תכנות מכוון עצמים ו- C++ בנוסף ל- 3 העקרונות שראינו קודם,

תכנות מכוון עצמים ו- C++

בנוסף ל- 3 העקרונות שראינו קודם, בשפת

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

© Keren Kalif

Слайд 7

מ- C ל- C++ שפת C++ מאוד דומה סינטקטית לשפת C,

מ- C ל- C++

שפת C++ מאוד דומה סינטקטית לשפת C, אך

יחד עם זאת יש כמה שינויים:
נפתח פרויקט באותו אופן כמו בקורס C, אבל נייצר קובץ עם סיומת cpp (ברירת המחדל), ולא עם סיומת c
הקומפיילר שונה, ולכן יתכנו שגיאות קומפילציה טיפה שונות
ניתן להגדיר משתנים בכל חלק בתוכנית, ולא רק בתחילת בלוק
במקום הכללת הספריה stdio.h שהכילה פקודות קלט-פלט, נכליל את הספריה iostream ונוסיף using namespace std; (הסבר בהמשך)
קיים הטיפוס bool שמחזיק את הערכים true או false

© Keren Kalif

Слайд 8

מ- C ל- C++ (2) פקודות שונות לטיפול בקלט ופלט: במקום

מ- C ל- C++ (2)
פקודות שונות לטיפול בקלט ופלט:
במקום הפקודה printf

נשתמש בפקודה cout
במקום הפקודה scanf נשתמש בפקודה cin
פקודות שונות לטיפול בהקצאות ושחרור זכרון:
במקום הפקודות malloc/calloc נשתמש בפקודה new
במקום הפקודה free נשתמש בפקודה delete

© Keren Kalif

Слайд 9

אבל ראשית, שאני לא אתעצבן.. © Keren Kalif http://qph.is.quoracdn.net/main-qimg-e0c9dafb319150b6c6d9816047ed9eae?convert_to_webp=true

אבל ראשית, שאני לא אתעצבן..

© Keren Kalif

http://qph.is.quoracdn.net/main-qimg-e0c9dafb319150b6c6d9816047ed9eae?convert_to_webp=true

Слайд 10

הפקודה cout יודעת להדפיס נתונים למסך (Console OUT) הסינטקס הרבה יותר

הפקודה cout

יודעת להדפיס נתונים למסך (Console OUT)
הסינטקס הרבה יותר פשוט מ-

printf: אין צורך להבדיל בהדפסה בין הטיפוסים השונים, משרשרים את חלקי המחרוזת להדפסה באמצעות >>

© Keren Kalif

#include
void main()
{
char str[] = "hi";
int num = 5;
printf("string: %s number: %d\n",
str, num);
{

#include
using namespace std;
void main()
{
char str[] = "hi";
int num = 5;
cout << "string: " << str << " number: " << num << "\n";
}

Слайд 11

הפקודה cin יודעת לקרוא נתונים מהמקלדת (Console IN) הסינטקס הרבה יותר

הפקודה cin

יודעת לקרוא נתונים מהמקלדת (Console IN)
הסינטקס הרבה יותר פשוט מ-

scanf: אין צורך להבדיל בקליטה בין הטיפוסים השונים, משרשרים את הנתונים השונים שרוצים לקרוא באמצעות <<

© Keren Kalif

#include
void main()
{
char str[10]
int num;
printf("Enter string and number: ");
scanf("%s%d", str, &num);
{

#include
using namespace std;
void main()
{
char str[10];
int num;
cout << "Enter string and number: ";
cin >> str >> num;
}

Слайд 12

הפקודה cin.getline cin יודעת לקרוא מחרוזת עד רווח ע"י שימוש ב-

הפקודה cin.getline

cin יודעת לקרוא מחרוזת עד רווח
ע"י שימוש ב- cin.getline ניתן

לקלוט תווים עד ENTER או עד למקסימום תווים

© Keren Kalif

#include
void main()
{
char str[10];
printf("Enter string: ");
gets(str);
{

#include
using namespace std;
void main()
{
char str[10];
cout << "Enter string: ";
cin.getline(str, 5);
}

הפונקיה תקרא עד 4 תווים (אחד עבור ה- '0\')
או עד ENTER

Слайд 13

הפקודות new ו- delete הפקודה new להקצאה דינאמית, מקצה מערך עם

הפקודות new ו- delete

הפקודה new להקצאה דינאמית, מקצה מערך עם ערכי

זבל (מקבילה ל- malloc)
אין מקבילה ל- calloc
אין מקבילה ל- realloc
הפקודה delete לשחרור זכרון. אם משחררים מערך יש לשחרר עם []

© Keren Kalif

#include
#include
void main()
{
int *arr, numOfElements;
printf("How many elements? ");
scanf("%d", &numOfElements);
arr = (int*)malloc(numOfElements*sizeof(int));
free(arr);
}

#include
using namespace std;
void main()
{
int *arr, numOfElements;
cout << "How many elements? ";
cin >> numOfElements;
arr = new int[numOfElements];
delete []arr;
}

Слайд 14

דוגמא © Keren Kalif #include #include void main() { int i,

דוגמא

© Keren Kalif

#include
#include
void main()
{
int i, numOfNumbers;
int* arr;

printf("How many numbers? ");
scanf("%d", &numOfNumbers);
arr = (int*)calloc(numOfNumbers, sizeof(int));
for (i=0 ; i < numOfNumbers ; i++)
printf("Value #%d: %d\n", i+1, arr[i]);
free(arr);
{

#include
using namespace std;
void main()
{
int numOfNumbers;
cout << "How many numbers? ";
cin >> numOfNumbers;
int* arr = new int[numOfNumbers];
for (int i=0 ; i < numOfNumbers ; i++)
cout << "Value #" << i+1 << ": " << arr[i] << "\n";
delete []arr;
}

נשים לב להגדרת המשתנים באמצע התוכנית

Слайд 15

דוגמא: תוכנית המטפלת במטריצה #include using namespace std; const int N

דוגמא: תוכנית המטפלת במטריצה

#include
using namespace std;
const int N = 3;
const

int M = 4;
// prototypes
int** allocateMatrix (int rows, int cols);
void enterInput (int** mat, int rows, int cols);
void printMatrix (int** mat, int rows, int cols);
void freeMatrix (int** mat, int rows);
void main()
{
int** mat = NULL;
mat = allocateMatrix(N, M);
enterInput(mat, N, M);
printMatrix(mat, N, M);
freeMatrix(mat, N);
{

© Keren Kalif

ה- main כתוב בראשי פרקים וניתן להבין בקלות מה קורה בתוכנית

Слайд 16

דוגמא: תוכנית המטפלת במטריצה (2) int** allocateMatrix(int rows, int cols) }

דוגמא: תוכנית המטפלת במטריצה (2)

int** allocateMatrix(int rows, int cols)
}
int** mat =

new int*[rows]; // allocating the rows
for (int i=0 ; i < rows ; i++)
mat[i] = new int[cols]; // allocating the columns
return mat;
{
void enterInput(int** mat, int rows, int cols)
}
for (int i=0 ; i < rows ; i++)
for (int j=0 ; j < cols ; j++)
mat[i][j] = i*cols + j;
{

© Keren Kalif

בתחילה מקצים מערך של int*, עבור השורות

נשים לב לאפשרות הגדרת המשתנים בכל חלק בקוד

Слайд 17

דוגמא: תוכנית המטפלת במטריצה (3) void printMatrix(int** mat, int rows, int

דוגמא: תוכנית המטפלת במטריצה (3)

void printMatrix(int** mat, int rows, int cols)
{
for

(int i=0 ; i < rows ; i++)
}
for (int j=0 ; j < cols ; j++)
cout << mat[i][j] << ", ";
cout << "\b\b \n";
{
{
void freeMatrix(int** mat, int rows)
}
for (int i=0 ; i < rows ; i++)
delete []mat[i];
delete []mat;
{

© Keren Kalif

נשים לב: שחרור מערך עם ציון [ ]

Слайд 18

טיפוס התייחסות בשפת C כאשר רצינו שפונקציה תשנה את ערכו של

טיפוס התייחסות

בשפת C כאשר רצינו שפונקציה תשנה את ערכו של ארגומנט

מסוים, העברנו את הכתובת שלו (העברה by pointer, לעומת העברת העתק, by value)
בשפת C++ עדיין ניתן להעביר מצביעים כדי לשנות ארוגמנטים בפונקציות, אך יש דרך חדשה הנקראית העברת פרמטרים by reference
בהגדרת הפרמטרים שהשיטה מקבלת מציינים ליד הפרמטר &
זהו למעשה מתן שם נוסף לארגומנט המקורי שנשלח הנגיש מתוך הפונקציה
אין הבדל סינטקטי בשליחת המשתנה בעבור משתנה שעובר by value או by reference

© Keren Kalif

Слайд 19

שליחת פרמטר by ref לעומת by val © Keren Kalif הזכרון

שליחת פרמטר by ref לעומת by val

© Keren Kalif

הזכרון של

ה- main

הזכרון של ה- chagneTo4ByRef

הזכרון של ה- chagneTo4ByVal
void changeTo4byVal(int x)
{
x = 4;
{
void changeTo4byRef(int& x)
}
x = 4;
}
void main()
}
int num = 10;
cout << "orig num = " << num << endl;
changeTo4byVal(num);
cout << "after changeTo4byVal: num = " << num << endl;
changeTo4byRef(num);
cout << "after changeTo4byRef: num = " << num << endl;
{

Слайд 20

הדוגמא swap #include using namespace std; void swap(int& a, int& b)

הדוגמא swap

#include
using namespace std;
void swap(int& a, int& b)
{
int temp =

a;
a = b;
b = temp;
{
void main()
}
int x=3, y=5;
cout << "Before swap: x = " << x << ", y = " << y << "\n";
swap(x, y);
cout << "After swap: x = " << x << ", y = " << y << "\n";
{

© Keren Kalif

הזכרון של ה- main

הזכרון של ה- swap

Слайд 21

משתנה מטיפוס reference מתן שם נוסף למשתנה כלשהו חייב להיות מאותחל

משתנה מטיפוס reference

מתן שם נוסף למשתנה כלשהו
חייב להיות מאותחל
לא ניתן לייצר

מערך של הפניות
אינו תופס מקום נוסף, ולכן כתובתו כמו כתובת המשתנה אליו הוא מפנה

© Keren Kalif

הזכרון של ה- main

void main()
{
int x = 5, y = 3;
int& ref = x;
cout << &ref << " " << &x << endl;
cout << "x=" << x << ", y=" << y << ", ref=" << ref << endl;
x++;
cout << "x=" << x << ", y=" << y << ", ref=" << ref << endl;
ref = y;
cout << "x=" << x << ", y=" << y << ", ref=" << ref << endl;
ref++;
cout << "x=" << x << ", y=" << y << ", ref=" << ref << endl;
}

Слайд 22

החזרת טיפוס התייחסות מפונקציה בשפת C יכולנו להחזיר כתובת של משתנה

החזרת טיפוס התייחסות מפונקציה

בשפת C יכולנו להחזיר כתובת של משתנה מתוך

פונקציה, וכך למעשה החזרנו את המשתנה המקורי, ולא העתק שלו
בשפת C++ עדיין ניתן להחזיר משתנה by pointer, אך ניתן גם להחזיר משתנה by reference
יש לשים לב שכשמחזירים משתנה by reference שהוא עדיין יהיה קיים ביציאה מהפונקציה (בדיוק כמו בשפת C)

© Keren Kalif

Слайд 23

דוגמא להחזרת משתנה by ref מפונקציה #include using namespace std; void

דוגמא להחזרת משתנה by ref מפונקציה

#include
using namespace std;
void printArr(int arr[],

int size)
{
for (int i=0 ; i < size ; i++)
cout << arr[i] << " ";
cout << endl;
{
int& getMax(int arr[], int size)
}
int maxIndex = 0;
for (int i=1 ; i < size ; i++)
if (arr[i] > arr[maxIndex])
maxIndex = i;
return arr[maxIndex];
{

© Keren Kalif

void main()
}
int arr[] = {6,8,2};
int size = sizeof(arr)/sizeof(arr[0]);
getMax(arr, size)
cout << "arr after changing max:\n ";
printArr(arr, size);
{

הפונקציה מחזירה הפניה לאיבר המקסימלי

הזכרון של ה- main

הזכרון של ה- getMax

*= 10;

Слайд 24

מרחבי שמות (namespace) כאשר עובדים על פרויקט גדול, לרוב משתמשים בקוד

מרחבי שמות (namespace)

כאשר עובדים על פרויקט גדול, לרוב משתמשים בקוד מוכן,

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

© Keren Kalif

Слайд 25

#include using namespace std; namespace first { void foo() }cout {

#include
using namespace std;
namespace first
{
void foo() }cout << "This is

the first foo\n“; {
{
namespace second
}
void foo() }cout << "This is the second foo\n“; {
{
void foo() }cout << "This is just foo\n“; {
void main()
{
first::foo();
second::foo();
foo();
{

להלן קטע קוד עם 3 פונקציות זהות
2 מימושים נמצאים בתוך namespace שונה
פניה לפונקציה הנמצאת בתוך namespace מחייבת ציון שם ה- namespace שבתוכו היא נמצאת
פונקציה שלא בתוך napespace נמצאת במרחב השמות הגלובלי

דוגמא: שימוש ב- namespace

© Keren Kalif

Слайд 26

קיצור אופן השימוש ב- namespace #include using namespace std; namespace first

קיצור אופן השימוש ב- namespace

#include
using namespace std;
namespace first
{
void foo() {cout

<< "This is the first foo\n";}
}
namespace second
}
void foo() {cout << "This is the second foo\n";}
{
using namespace second;
void main()
}
first::foo();
second::foo();
foo();
{

© Keren Kalif

פקודה זו מאפשרת לנו לפנות לפונקציות שתחת namespace זה בלי הקידומת

פקודה זו מאפשרת לנו לפנות לפונקציות שתחת namespace זה בלי הקידומת

Слайд 27

#include using namespace std; namespace first { void foo() {cout }

#include
using namespace std;
namespace first
{
void foo() {cout << "This is the

first foo\n";}
}
namespace second
}
void foo() {cout << "This is the second foo\n";}
{
void foo() }cout << "This is just foo\n“; {
using namespace first;
using namespace second;
void main()
}
first::foo();
second::foo();
foo(); // ERROR!
::foo();
{

קיצור אופן השימוש ב- namespace

© Keren Kalif

במקרה זה נהייה חייבים תמיד לפנות בשם המלא של הפונקציה, אחרת נקבל את השגיאה: ambiguous call to overloaded function מאחר והקומפיילר אינו יודע איזו פונקציה לפנות

במקרה זה נהייה חייבים תמיד לפנות בשם המלא של הפונקציה, אחרת נקבל את השגיאה: ambiguous call to overloaded function מאחר והקומפיילר אינו יודע לאיזו פונקציה לפנות

פניה בשם המלא לפונקציה הנמצאת במרחב השמות הגלובלי

Слайд 28

מדוע שמים את using namespace std? בתוך namespace זה יש את

מדוע שמים את using namespace std?

בתוך namespace זה יש את כל

הפקודות הבסיסיות
בלעדיו נצטרך להוסיף את הקידומת ::std לכל הפונקציות הבסיסיות שבהן נשתמש, אחרת נקבל למשל את השגיאה:
error C2065: 'cout' : undeclared identifier

© Keren Kalif

#include
using namespace std;
void main()
{
int x;
cout << "Enter a number: ";
cin >> x;
{

#include
void main()
{
int x;
std::cout << "Enter a number: ";
std::cin >> x;
{

Слайд 29

ביחידה זו למדנו: הגדרת תכנות מכוון עצמים השוני הסינטקטי בין C

ביחידה זו למדנו:

הגדרת תכנות מכוון עצמים
השוני הסינטקטי בין C ל- C++:
printf

? cout
scanf ? cin
gets ? cin.getline
malloc ? new
free ? delete
טיפוס התייחסות
מרחבי שמות (namespace)

© Keren Kalif