1 ++c: יוצרים, הורסים ואופרטורים. 2 המחלקה stack תזכורת class...

29
1 ++ C : םםםםםם, םםםםםם םםםםםםםםםם

Post on 20-Dec-2015

233 views

Category:

Documents


2 download

TRANSCRIPT

Page 1: 1 ++C: יוצרים, הורסים ואופרטורים. 2 המחלקה Stack תזכורת class Stack { private: int* array; int size, top_index; public: Result init (int size) ; void

1

++C יוצרים, הורסים :ואופרטורים

Page 2: 1 ++C: יוצרים, הורסים ואופרטורים. 2 המחלקה Stack תזכורת class Stack { private: int* array; int size, top_index; public: Result init (int size) ; void

2

Stackחלקה המ זכורתת

class Stack {

private:

int* array;

int size, top_index;

public:

Result init (int size) ;

void destroy() ;

Result push (int e);

Result pop ();

Result top(int& e);

Result print() ;

} ;

class Stack {

private:

int* array;

int size, top_index;

public:

Result init (int size) ;

void destroy() ;

Result push (int e);

Result pop ();

Result top(int& e);

Result print() ;

} ;

init ומה יקרה אם המשתמש ישכח לקרוא ל-destroyאו ל-???

Page 3: 1 ++C: יוצרים, הורסים ואופרטורים. 2 המחלקה Stack תזכורת class Stack { private: int* array; int size, top_index; public: Result init (int size) ; void

3

יוצרים והורסים פתח לטעויות- בהגדרת הטיפוס אנו משאירים הבעיה

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

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

אובייקטים זמניםיתר על כן, פעמים רבות נוצרים (למשל, בהעברת והחזרת פרמטרים מפונקציות) שאין

למשתמש יכולות לאתחלם בצורה מפורשת.

פונקציות אתחול והריסה שנקראות – הפתרוןאוטומטית כאשר האובייקט נוצר וכאשר הוא אמור

להיהרס.

נדרש Stackבכל פעם שנגדיר משתנה מטיפוס מעתה,להעביר ליוצר את הפרמטרים הדרושים לצורך אתחול

האובייקט, ובכל פעם שהאובייקט לא יהיה נגיש יותר הקומפיילר יקרא להורס אשר ישחרר את האובייקט.

) כשם המחלקה. שם constructorsשמות היוצרים () כשם המחלקה שלפניה ~.destructorההורס (

class Stack {

private:

int* array;

int size, top_index ;

public:

Stack (int size) ; Stack (int size) ;

~Stack() ;~Stack() ;

Page 4: 1 ++C: יוצרים, הורסים ואופרטורים. 2 המחלקה Stack תזכורת class Stack { private: int* array; int size, top_index; public: Result init (int size) ; void

4

Stack::Stack (int s) {

array = new int[s] ; // חסרה בדיקה

top_index = 0; size = s ;

}

Stack::~Stack() {

delete[] array;

}

Destructors ו Constructorsמימוש

לא מחזירים ערכים !D’tor ו C’torשימו לב

הערה:

כמעט לכל מחלקה נדרש להגדיר יוצרים לאתחול שדותיה.

הגדרת הורסים תתבצע בד”כ עבור מחלקות המקצות זיכרון דינמי בעצמן. במקרה זה על

ההורס לשחררו.

אם איננו מגדירים יוצרים והורסים, מוגדרים אוטומטית יוצרים והורסים דיפולטיים.

Page 5: 1 ++C: יוצרים, הורסים ואופרטורים. 2 המחלקה Stack תזכורת class Stack { private: int* array; int size, top_index; public: Result init (int size) ; void

5

שימוש במחסנית שיש לה יוצרים והורסים#include “Stack.h”

int main() {

int i;

Stack s(100) ; // the c’tor is called with size 100

Stack* ps = new Stack(100); // same here

if (ps == NULL) exit(1);

s.push (1); s.push(213); s.pop (); s.top(i);

ps->push(1); ps->push(2); ps->pop() ;

delete ps ; // the d’tor is called for ps

}

// the d’tor is called for s

Page 6: 1 ++C: יוצרים, הורסים ואופרטורים. 2 המחלקה Stack תזכורת class Stack { private: int* array; int size, top_index; public: Result init (int size) ; void

6

זמני קריאה של יוצרים והורסים דרכים להקצאת משתנים. זמני הקריאה של 4קיימות •

היוצרים וההורסים תלויים באופן שבו הוקצה האובייקט.

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

מגיעה להכרזת המשתנה. בכל פעם שהתוכנית ההורס

יוצאת מהתחום בו הוגדר המשתנה

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

).main(לפני ה- עם סיום התוכנית (לאחר ההורס

).mainסיום

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

. newאובייקט ע”י בכל פעם שאובייקט ההורס

.deleteמשוחרר ע”י

משתנים סטאטייםבפעם הראשונה נקראהיוצר

שהתוכנית מגיע לתחום בו מוגדר המשתנה.

עם סיום התוכנית.ההורס

Page 7: 1 ++C: יוצרים, הורסים ואופרטורים. 2 המחלקה Stack תזכורת class Stack { private: int* array; int size, top_index; public: Result init (int size) ; void

7

דוגמא לזמני קריאה#include “Stack.h”

Stack glbals(100); // globals c’tor is called

int main() {

Stack locals(50) ; // locals c’tor is called

Stack* ps = new Stack(600); // ps c’tor is called

Stack* ps2 = new Stack(600); // ps2 c’tor is called

delete ps ; // ps destructor is called

return 0; // locals destructor is called

}

// globals destructor is called

// ps2 destructor is never called !

Page 8: 1 ++C: יוצרים, הורסים ואופרטורים. 2 המחלקה Stack תזכורת class Stack { private: int* array; int size, top_index; public: Result init (int size) ; void

8

Advanced C’tors and D’tors

class TwoStack .. {Stack s1, s2 ;

public :TwoStack(int s) ;

..};

TwoStack::TwoStack (int size) :s1(100), s2(size * 5) { …

}

של מערכיםבכדי להקצות •אובייקטים ממחלקה כלשהי, לאותה

מחלקה נדרש שיהיה יוצר שלא מקבל פרמטרים (או שיש לו ערכים דיפולטיים לכל הפרמטרים שלו כך

שאין צורך לציין פרמטרים במפורש).

ניתן להגדיר מחלקות אשר יש בהן •שדות שהם עצמם עצמים של

מחלקות אחרות. במקרה זה:כאשר נוצר אובייקט של –

המחלקה, ראשית מאותחלים כל שדותיו. כאשר נהרס אובייקט

כזה, ראשית נקרא ההורס שלו ורק אח”כ של שדותיו.

אם יוצרי השדות זקוקים –לפרמטרים ניתן לבצע זאת ע”י

רשימת אתחול.

Page 9: 1 ++C: יוצרים, הורסים ואופרטורים. 2 המחלקה Stack תזכורת class Stack { private: int* array; int size, top_index; public: Result init (int size) ; void

9

רשימות אתחולהדרך המקובלת לאתחול שדות פנימיים של מחלקה. •מייד אחרי הצהרת היוצר ולפני גוף היוצר (החלק שבתוך ה-{}) •

מופיעות נקודותיים ואז רשימה של השדות הפנימיים, כשהם מופרדים על ידי פסיקים.

כל מופע של שדה ברשימת האתחול הוא למעשה קריאה לאחד •מהיוצרים של השדה.

לכל שדה כותבים בסוגריים את הערכים שמעבירים ליוצר שלו •(ויכולים להיות תלויים בפרמטרים שהועברו ליוצר הראשי).

הסדר בו הם מופיעים ברשימת האתחול אינוסדר הפעלת היוצרים •אלא בו השדות מופיעים בהגדרת המחלקה.

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

Page 10: 1 ++C: יוצרים, הורסים ואופרטורים. 2 המחלקה Stack תזכורת class Stack { private: int* array; int size, top_index; public: Result init (int size) ; void

10

operators overloading לאפשר עבודה טבעית ככל האפשר עם מחלקות שהגדיר מטרה:•

המשתמש.

ע”י שימוש באופרטורים, המחלקות שהמשתמש מגדיר יוכלו לעבוד עם אופרטורים כמו טיפוסים פנימיים. אם האופרטורים מממשים פעולה

טבעית של המחלקה, הדבר יכול לשפר את הקריאות של הקוד. הגדרת אופרטורים מתבצעת באופן הבא:•

<return type> operator<operator name> (<arguments>);

של המחלקה או פונקציות methodsאופרטורים יכולים להיות •חיצוניות.

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

Page 11: 1 ++C: יוצרים, הורסים ואופרטורים. 2 המחלקה Stack תזכורת class Stack { private: int* array; int size, top_index; public: Result init (int size) ; void

11

operators overloading

operatorפונקציות עם שם מיוחד: + •Stack& operator+=(int e) { // bad : no error checking !

array[top_index] = e; top_index++;

return *this

}

צורת קריאה לפונקציה: • s.operator+=(5) ; s += 5 ;

Page 12: 1 ++C: יוצרים, הורסים ואופרטורים. 2 המחלקה Stack תזכורת class Stack { private: int* array; int size, top_index; public: Result init (int size) ; void

12

The matrix exampleclass M {

double mat[5][5];public:

...M& operator+=(const M&);friend M operator+( const M&,

const M&);M operator*(const M &) ;

…}; M operator+(const M&,const M&){

int main() {

M m1 , m2, m3 ;

….

m1+= m2 ;

// calls m1.operator+=(m2);

m2 = m1 + m3 ;

// calls operator+(m1,m3);

m3 = m2 * m2;

// calls m2.operator*(m2);

}

Page 13: 1 ++C: יוצרים, הורסים ואופרטורים. 2 המחלקה Stack תזכורת class Stack { private: int* array; int size, top_index; public: Result init (int size) ; void

13

operators overloading - what can we overload?

+ - * / % ^ & | !

= < > += -= *= /= %=

^= &= |= << >> <<= >>= ==

!= <= >= && || ++ -- ,

->* -> () []

what not ? . .* :: ? : sizeof

post & pre

Page 14: 1 ++C: יוצרים, הורסים ואופרטורים. 2 המחלקה Stack תזכורת class Stack { private: int* array; int size, top_index; public: Result init (int size) ; void

14

Operators overloadingמגבלות

רק אופרטורים שכבר קיימים (ולא למשל אופרטור $%$).•

האופרטורים מקבלים את אותו מספר משתנים•

אותו סדר עדיפות ואותה אסוציאטיביות.•

הערות בנוגע להגדרת אופרטורים:

ניתן להגדיר את שני סוגי הגדלה / הקטנה עצמית ע”י .בפרמטר דמישמוש

• x.operator++() (pre) (++num)

• x.operator++(int) (post) (num++)

Page 15: 1 ++C: יוצרים, הורסים ואופרטורים. 2 המחלקה Stack תזכורת class Stack { private: int* array; int size, top_index; public: Result init (int size) ; void

15

ערכי החזרה של אופרטורים יחזיר בדרך כלל איבר זמני classאופרטור עבור המחלקה

.&class או רפרנס לאובייקט שעליו נקרא: classמסוג

יוצרת איבר חדש כאשר הפעולה איבר זמניהאופרטור יחזיר .a+bשאותו אנו רוצים לקבל, למשל

רוצים לקבל את כאשר אנו רפרנסהאופרטור יחזיר דורש שהפעולה a+=2=+(3(. למשל, האובייקט לאחר השינוי

תחזיר רפרנס (ואז ניתן יהיה להפעיל אותה מספר פעמים +=ברצף על אותו אובייקט).

אמורה a++ אמורה להחזיר איבר זמני, ואילו ++aהפעולה להחזיר רפרנס (מדוע?)

Page 16: 1 ++C: יוצרים, הורסים ואופרטורים. 2 המחלקה Stack תזכורת class Stack { private: int* array; int size, top_index; public: Result init (int size) ; void

16

Overloading של אופרטורי I/Oהקלט והפלט בכדי לאפשר של אופרטוריoverloadניתן לבצע

יקטים מטיפוסים שהוגדרו ע"י י מאובטלבצע קלט אל ופלהמשתמש בדומה לצורה שבה הדבר אפשרי עבור טיפוסים

פנימיים.

int main

{

int x;

someclass y;

otherclass z;

cin >> x >> y >> z ;

cout << x << y << z;

}

Page 17: 1 ++C: יוצרים, הורסים ואופרטורים. 2 המחלקה Stack תזכורת class Stack { private: int* array; int size, top_index; public: Result init (int size) ; void

17

Overloading של אופרטורי I/Oclass someclass { int k , j ; ….

friend ostream& operator<< (ostream& os, const someclass& s1);friend istream& operator>> (istream& is, someclass& s1);

};ostream& operator<< (ostream& os,const someclass& s1) {

os << “(“ << s1.k << “,” << s1.j <<“)” ;return os ;

}istream& operator>> (istream& is, someclass& s1) {

is >> s1.k >> s1.j ;return is ;

}כיצד ניתן האם זה מתחייב? (רמז: לא). ?friendלמה האופרטורים הוגדרו כ •

? לשנות זאת

Page 18: 1 ++C: יוצרים, הורסים ואופרטורים. 2 המחלקה Stack תזכורת class Stack { private: int* array; int size, top_index; public: Result init (int size) ; void

18

overloading של אופורטורי I/Oint main()

{

someclass s;

int i; ….

cin >> i >> s ; // assume the user typed 1, 2 and 3

cout << s << i; // What does the program print?

}

להגדיר • ניתן לא האלה האופרטורים את כי לב שימו צריך memberכפונקצית שלו הראשון שהארגומנט מכיוון

עצם השייך למחלקה אחרת )ערוץ(.על הפונקציה המחזירה את האופרטור להחזיר כפלט את •

הערוץ כדי שיהיה אפשר להמשיך ולהזרים לו נתונים.

Page 19: 1 ++C: יוצרים, הורסים ואופרטורים. 2 המחלקה Stack תזכורת class Stack { private: int* array; int size, top_index; public: Result init (int size) ; void

19

class String {int len; // length of stringchar* val; // value of stringvoid enter(const char*);

public:String(); // String x;String(const char*); // String x = "abc”String(const String&); // String x = y;String& operator=(const String&); // x = y;String& operator=(const char*); // x = “abc”;~String();

int len() const { return len; } // x.len()char operator[](int i) const ; // c = x[1]char& operator[](int i); // x[1] = ‘d’ String& operator+=(const String&); // x+=y

friend bool operator==(const String&, const String&); // if (x == y)friend bool operator!=(const String&, const String&); // if (x != y)friend ostream& operator<<(ostream&, const String&); // cout << x;

};

String.h

בתרגול הבא

Page 20: 1 ++C: יוצרים, הורסים ואופרטורים. 2 המחלקה Stack תזכורת class Stack { private: int* array; int size, top_index; public: Result init (int size) ; void

20

#include <cstdlib.h>error(const char* st) {

cerr << st << '\n';exit (1);

}void String::enter(const char* st) {

if (val) delete[] val; // if string existsif (st == 0) // Null pointer

val = 0 ;else

if (val = new char[strlen(st)+1]) {strcpy(val, st);len = strlen(st);

}else error("String: out of memory");

}

String.cc (1)

Page 21: 1 ++C: יוצרים, הורסים ואופרטורים. 2 המחלקה Stack תזכורת class Stack { private: int* array; int size, top_index; public: Result init (int size) ; void

21

String::String() {

len = 0; val = 0; // Null pointer

}

String::String(const char* st) {

len = 0; val = 0;

enter(st);

}

String::String(const String& st) {

len = 0; val = 0;

enter(st.val);

}

String::~String() {

if (val) delete[] val;

}

String.cc (2)

0 ל valלמה קובעים את ?enterלפני הקריאה ל

Page 22: 1 ++C: יוצרים, הורסים ואופרטורים. 2 המחלקה Stack תזכורת class Stack { private: int* array; int size, top_index; public: Result init (int size) ; void

22

String& String::operator=(const char* st) {enter(st);return *this;

}

String& String::operator=(const String& st){if (this!= &st)

enter(st.val);return *this;

}

String.cc (3)

בדיקת הצבה עצמית

Page 23: 1 ++C: יוצרים, הורסים ואופרטורים. 2 המחלקה Stack תזכורת class Stack { private: int* array; int size, top_index; public: Result init (int size) ; void

23

char& String::operator[](int i) {if ((i < 0) || (i > len))

error("String: index out of range");return val[i];

}

char String::operator[](int i) const {if ((i < 0) || (i > len))

error("String: index out of range");return val[i];

}

String.cc (4)

Page 24: 1 ++C: יוצרים, הורסים ואופרטורים. 2 המחלקה Stack תזכורת class Stack { private: int* array; int size, top_index; public: Result init (int size) ; void

24

String& String::operator+=(const String& st) {

char* p;

if (st.len == 0)

return *this ;

if ( (p = new char[len+st.len+1]) == 0)

error (“String: out of memory”);

strcpy(p,val);

strcat(p,st.val);

enter(p);

delete[] p;

return *this ;

}

String.cc (5)

Page 25: 1 ++C: יוצרים, הורסים ואופרטורים. 2 המחלקה Stack תזכורת class Stack { private: int* array; int size, top_index; public: Result init (int size) ; void

25

bool operator==(const String& x, const String& y){

return !strcmp(x.val, y.val) ;

}

bool operator!=(const String& x, const String& y) {

return !(x == y);

}

ostream& operator<<(ostream& os,const String& st) {

if(st.val)

os << st.val;

return os;

}

String.cc (6)

Page 26: 1 ++C: יוצרים, הורסים ואופרטורים. 2 המחלקה Stack תזכורת class Stack { private: int* array; int size, top_index; public: Result init (int size) ; void

26

String תוכנית הנעזרת ב int main() {

String a;String b(“1234");String c = b; // Copy constructor

a = "kookoo"; // operator=(const char*) is calledcout << a << "\n"; // kookoo is printeda = c; // operator=(const String&) is calledcout << a << "\n"; // 1234 is printeda+=b;cout << a << "\n"; // 12341234 is printedc="oooo"; // If the copy constructor or assignment

// were not redefined, b or a would be// changed as well

}

Page 27: 1 ++C: יוצרים, הורסים ואופרטורים. 2 המחלקה Stack תזכורת class Stack { private: int* array; int size, top_index; public: Result init (int size) ; void

27

Class String: important points

שימוש בפונקציה אחת שעושה את כל העבודה •) וכל השאר רק קוראות לה. enterהאמיתית בבניה (

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

.method הינו חלק מחתימת ה constהעובדה כי •

מדוע האופרטורים == ו =! הינם פונקציות גלובליות • .methodsבעוד =+ ו [] הינם

אופרטור הפלט. •

Page 28: 1 ++C: יוצרים, הורסים ואופרטורים. 2 המחלקה Stack תזכורת class Stack { private: int* array; int size, top_index; public: Result init (int size) ; void

28

Class String: points to improve

c’torsלא השתמשנו ברשימת אתחול ב-•

String::string(): val(0), len(0){}יותר מדיי פונקציות חברות, מחלקה צריכה להיות •

כמה שיותר סוציומטית. אפשר להוסיף פונקציות פנימיות נוספות על מנת שפונקציות ההשוואה לא

יצטרכו לגשת לשדות.;char operator[] (int i) const :נחליף את•

const char& operator[](int i) const;ב-

Page 29: 1 ++C: יוצרים, הורסים ואופרטורים. 2 המחלקה Stack תזכורת class Stack { private: int* array; int size, top_index; public: Result init (int size) ; void

29

מומלץ מאוד!!!

http://www.yanivhamo.com/material/yanivs_string.pdf