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

Post on 20-Dec-2015

233 Views

Category:

Documents

2 Downloads

Preview:

Click to see full reader

TRANSCRIPT

1

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

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או ל-???

3

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

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

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

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

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

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

להיהרס.

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

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

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

class Stack {

private:

int* array;

int size, top_index ;

public:

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

~Stack() ;~Stack() ;

4

Stack::Stack (int s) {

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

top_index = 0; size = s ;

}

Stack::~Stack() {

delete[] array;

}

Destructors ו Constructorsמימוש

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

הערה:

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

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

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

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

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

6

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

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

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

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

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

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

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

).mainסיום

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

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

.deleteמשוחרר ע”י

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

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

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

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 !

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) { …

}

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

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

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

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

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

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

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

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

רשימת אתחול.

9

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

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

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

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

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

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

10

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

המשתמש.

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

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

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

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

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

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 ;

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);

}

13

operators overloading - what can we overload?

+ - * / % ^ & | !

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

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

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

->* -> () []

what not ? . .* :: ? : sizeof

post & pre

14

Operators overloadingמגבלות

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

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

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

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

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

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

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

15

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

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

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

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

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

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

16

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

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

פנימיים.

int main

{

int x;

someclass y;

otherclass z;

cin >> x >> y >> z ;

cout << x << y << z;

}

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למה האופרטורים הוגדרו כ •

? לשנות זאת

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כפונקצית שלו הראשון שהארגומנט מכיוון

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

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

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

בתרגול הבא

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)

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לפני הקריאה ל

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)

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

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)

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)

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)

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

}

27

Class String: important points

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

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

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

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

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

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;ב-

29

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

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

top related