28
1 ללללל לללללל: Copy constructor Assignment operator תתתת תתתתתתת תתתתתתתתת.- תתתתת תתתתTemplates

נושאי התרגול :

Embed Size (px)

DESCRIPTION

נושאי התרגול :. Copy constructor Assignment operator המרת טיפוסים אוטומטיות. תכנות גנרי - Templates. Copy constructor & Assignment operator. מה קורה כאשר מבצעים s1 = s2 ? מה קורה כאשר מבצעים Stack s1 = s2 ? מה ההבדל? מה הסכנה? מה קורה כאשר קוראים לפונקציה : f(Stack s) ; - PowerPoint PPT Presentation

Citation preview

1

:נושאי התרגול

•Copy constructor•Assignment operatorהמרת טיפוסים אוטומטיות.•Templatesתכנות גנרי - •

2

Copy constructor & Assignment operator

?s1 = s2מה קורה כאשר מבצעים •?Stack s1 = s2מה קורה כאשר מבצעים •

מה ההבדל? מה הסכנה?מה קורה כאשר קוראים לפונקציה:•

f(Stack s) ;f(Stack& s) ;

- להשמה.assign. Op - לאתחול, copy c’torפתרון •

3

Copy constructor & Assignment operator

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

•copy constructor זהו -c’tor המשמש לאתחול של עצם אחד של המחלקה ע"י עצם אחר של

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

, by valueמעבירים פרמטר מסוג מחלקה מסוימת ערכי השדות של הפרמטרים מאותחלים ע"י

קריאה לפונקציה זאת )כנ"ל לגבי החזרת של פונקציה זו עבור prototypeערכים(. ה-

: הואXמחלקה

X(const X&)X(const X&)

מובטח שלא נשנה את הפרמטר המועבר

copy constructorאי אפשר להגדיר copy constructorבאמצעות

4

Copy constructor & Assignment operator

- פונקציה זו משמשת אופרטור ההשמה )=(•להשמה של עצמים מהמחלקה זה לזה פרט

לאתחול של עצם אחד של המחלקה ע"י עצם אחר של אותה מחלקה )במקרה של אתחול ייקרא

, אפילו אם משתמשים בסימן = בביצוע copy c’torה-האתחול(.

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

להגדיר פונקציות אלו מחדש )דוגמא להגדרה מחדש בהמשך(Stackשל אופרטורים אלו נראה במחלקה

5

Copy constructor & Assignment operator

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

• Copy Constructor

• Assignment Operator

• Destructor

6

The Final Stack

class Stack {

int* array; int top_index, size;

public:

Stack (int s = 100) ;

Stack (const Stack&) ;

Stack& operator=(const Stack&);

~Stack() ;

Result push(int e);

Result pop() ;

Result top(int& e);

void print() ;

};

7

Copy constructor

Stack::Stack(const Stack & st) {

array = new int [st.size];

if (array == 0)

error(“out of memory”); // assumes error exits

size = st.size;

top_index = st.top_index;

for (int top = 0 ; top<st.top_index; top++)

array[top] = st.array[top];

}

8

Assignment operatorStack& Stack::operator=(const Stack& st)

{if (this == &st) return *this;

if (st.size != size) {

delete[] array;

array = new int[size = st.size];

}

for (int top = 0 ; top<st.top; top++)

array[top] = st.array[top];

top_index = top;

return *this ;

}

חמשת הצעדים:

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

שחרור משאבים

הקצאת משאבים חדשים

אתחול השדות

*thisהחזרת

9

User Defined Type Conversions

קיימים שני סוגי המרות טיפוסים Cב ++אוטומטיות :

• Conversion by constructor.

• Conversion by conversion operator.

10

Conversion by construction

אפשר להמיר כל מחלקה T של מחלקה c’torsבעזרת •אחרת או טיפוסים פנימיים של השפה כך שיהפכו

.Tלאיבר מסוג המקבל Constructorההמרה מתבצעת ע”י הגדרת •

ארגומנט יחיד, מהטיפוס הנ”ל. T(class C); //converts from class C to T

על ידי הקומפיילר.אוטומטיתההמרה תתבצע •ההמרה מאפשרת לקרוא לפונקציות המצפות לקבל •

במקום.C עם ארגומנט מטיפוס Tארגומנט מטיפוס דוגמא:

)עוד מעט(double : המרה מ-Complexבמחלקה – )תרגול קודם(String למחלקה const char המרה מ-* –

11

Complexדוגמא - המחלקה נניח כי רוצים להגדיר מחלקה של מספרים מרוכבים. היינו רוצים גם

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

כל אופרטור, בדומה לדוגמא הבאה:class complex {

double re,im;public:

complex (double r, double i) {re = r; im = i;}friend complex operator+(complex, complex);friend complex operator+(complex, double);

friend complex operator+(double, complex);

// Do the same for the rest of the operators…};

אותו את לעשות נוספת דרך מיותרות. חזרות ומלאה מייגעת זו שיטה להגדיר היא ל- constructorהדבר complex יחיד פרמטר מקבל אשר

מ doubleמטיפוס ההמרה .double ל complex אוטומטית תתבצע זה.constructorבאמצעות

12

Complexדוגמא - המחלקה class complex {

//...

complex(double r) {re = r; im = 0;}

friend complex operator+(complex,complex);

};

המהדר יבצע את ההמרה באופן אוטומטי. לדוגמא:main()

{

complex a;

complex b;

a=b+23;

}

: מה שמתבצע זה ע"י ה- complex מומר ל- 1.23

constructor..complexמתבצע חיבור בין שני .23.a מקבל את התוצאה ע"י אופרטור

ההשמה המוגדר כברירת מחדל ע"י המהדר )העתקה איבר איבר(.

13

Conversion by conversion operator אפשר להמיר את Tבעזרת אופרטורים מיוחדים שמוגדרים במחלקה •

T .לטיפוסים פנימיים של השפה או למחלקות אחרות שכבר הוגדרו הדרך היחידה להגדיר המרה לטיפוסים פנימיים של השפה )למה?(.• )מתודה של conversion operatorהמרה זו מבוצעת ע”י הגדרת •

(.Tהמחלקה

operator C() ; // converts from T to C.דוגמא: •

class Price { int Shekel, agorot ; …

public : …. operator double() { return shekel + agorot / 100.0 ;} …

};(.C )של Conversion by constructorאם ניתן רצוי להיעזר ב • בתוכו returnשימו לב שלאופרטור אין ערך החזרה אבל השתמשנו ב-•

)אז מה כן ++Cעם ערך החזרה... מנפלאות הסינטקס של מחזירים?(.

14

בעיות עם המרות אוטומטיותclass x { // ...

x(int); x(char*); … };

class y{ //...

y(int); …. };

class z {//...

z(x); …. };

x f(x);

y f(y);

z g(z);

void k1() {

f(1); // Illegal: ambiguous f(x(1)) or f(y(1))

f(x(1));

f(y(1));

g("asdf") ; // Illegal: g(z(x("asdf"))) not tried

g(z("asdf")); // O.k.: x(char*) is carried out

}

עם בעיות שתי קיימות לכך פרטהמרות:

אחת – המרה רק מתבצעתמשמעות – דו להיווצר עלולה(ambiguity)

15

המרות ואופרטורים הם בעצם פונקציות. לכן גם עבורם יכולה להתבצע operatorsכזכור •

יכול להיקרא:Complexהמרה. לדוגמה, אופרטור החיבור במחלקה c2 = c1 + 5 ;

לא תתבצע המרה על method אולם אם אופרטור מוגדר כ הארגומנט הראשון שלו. בגלל בעיה זו, עדיף בד"כ להגדיר אופרטור

ע"י פונק' חיצונית. כך, הטיפול בשני האופרנדים יהיה סימטרי.class complex { ...public: complex(double r) {re = r; im = 0;} operator+(const complex&); friend operator-(const complex&, const complex&);};main() {

complex c2,c1; c1=2.0+c2; // Error: 2.0 will not be converted

c2=2.0-c2; // O.k.: 2.0 will be converted}

16

Templatesתכנות גנרי -

- מחלקות Containersמשמש בעיקר כאשר בונים •אשר מכילות עצמים אחרים, אולם אין חשיבות

לתכונותיו הייחודיות של אותו עצם: ללא קשר Containerאותן פעולות מוגדרות על ה •

לעצם שבו. לדוגמא עבור מחסנית תמיד יוגדרו :– push– pop– top

.String או int , charללא חשיבות אם זו מחסנית של

17

דוגמת המחסניתint_stack.h:class int_stack {

int top_index,size;int* array ;

public:int_stack(int s) ; void pop() ;void push(int e);int top() ;int size();

};

char_stack.h:class char_stack {

int top_index,size;char* array ;

public:char_stack(int s) ; void pop() ;void push(char e);char top() ;int size();

};

String_stack.h:

class string_stack {

int top_index,size;

String* array ;

public:

string_stack(int s) ;

void pop() ;

void push(String e);

String top() ;

int size();

};

18

דוגמת המחסנית

int_stack.cc (חלקי):int_stack::int_stack (int s) {

top_index = 0 ; size = s ; array = new int[s];

}

int int_stack::top() {return array[top_index-1];

}

string_stack.cc (חלקי):string_stack::string_stack (int s){

top_index = 0 ; size = s ; array = new String[s];

}

String string_stack::top() {return array[top_index-1];

}

19

מחלקות גנריותבכדי להימנע משכפול הקוד (ליתר דיוק: כדי לבצע •

.Templateשכפול קוד מבוקר) נעזר ב מקבל טיפוס(ים) כפרמטר, ויכול Templateה-•

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

את Template“מקרו” מתוחכם). לאחר שהעברנו ל-הטיפוס עמו הוא עובד (ע”י הוספת > טיפוס > לשם

מחלקה רגילה לכל דבר. נקבלTemplateה-

20

מה קורה בפועל? כמו שאנחנו כותבים Templateאנחנו כותבים מחלקה שהיא •

>template <class Tמחלקה רגילה, פרט לתוספת השורה לפני הגדרת המחלקה.

Tכעת נוכל לכתוב את קוד המחלקה תוך שאנחנו מתייחסים ל-•כאל טיפוס כלשהו, שיועבר כפרמטר רק מאוחר יותר.

Templateבתוך התוכנית, כאשר אנחנו רוצים להשתמש ב-•, מעבירים את הערך הזה גם כן Tעבור ערך מסוים של

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

ייכתב T ובכל מקום שבו מופיע Templateשכתבנו עבור ה- במקומו.Templateהערך שהועבר ל-

21

מחסנית גנריתstack.h:template <class T>class stack {

int top_index,size;T* array ;

public:stack(int s=100) ; void pop() ;void push(T e);T top() ;int size();

};

int_stack.h:

class int_stack {

int top_index,size;

int* array ;

public:

int_stack(int s) ;

void pop() ;

void push(int e);

int top() ;

int size();

};

22

מחסנית גנריתstack.h (חלקי):

template <class T<

stack<T<::stack (int s) {

top_index = 0 ; size = s ;

array = new T[s];

}

template <class T<

T

stack<T<:: top() {

return array[top_index-1];

}

int_stack.cc (חלקי):

int_stack::int_stack (int s) {

top_index = 0 ; size = s ;

array = new int[s];

}

int

int_stack::top() {

return array[top_index-1];

}

23

שמוש במחסנית הגנריתint main() {

stack<int< si(100);stack<char*< sc(3);

si.push(5);sc.push(“xxx”);sc.push(6); // error !si.size();sc.size();

}

int main() {int_stack si(100);

si.push(5);

si.push(“xxx”); // error !si.size();

}

24

Templates

•Templates הינם כלי מאוד שמושי לצורך .Containersהגדרת

ב +Templatesלמרבה הצער המימוש של •+C מזכיר macro חכם ולכן כל הקוד של ה

Template נמצא ב header file כפי שהוצג או ..inline functionכ

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

25

פונקציות גנריות

int major (int a , int b , int c ) {

if (a == b || a == c) return a ;if (b == c) return b ;exit(1);

}: שימוש

int j = major (1,3,3); // ok?char c = major (‘w’,’w’,’w’);//ok?String s1 = major(s1,s2,s3); //ok ?int j = major (1,’a’,’a’); //ok ?

template <class T<

T

major (T a ,T b , T c ) {

if (a == b || a == c) return a ;

if (b == c) return b ;

exit(1);

}

שימוש :

int j = major (1,3,3); // ok ?

char c= major (‘w’,’w’,’w’); //ok

String s1 = major(s1,s2,s3); // ok?

int j = major (1,’a’,’a’); //ok ?

26

Templates - advanced issues

לא “מתעניין” בתכונותיו Templateלמרות ש ה •ניח יכול לההמיוחדות של הטיפוס המועבר כפרמטר הוא

הנחות לגבי קיומם של פונקציות או מתודות מסוימות בו. ? stack ? אילו T על majorאילו הנחות הניח –

ניתן להעביר כמה טיפוסים שונים בפרמטר:•template <class K, class D< class hashtable {

bool find (const K &k, D &d) ;…

};

27

Templateפרמטרים ל ל להעביר . Templateניתן פרמטר טיפוס שאינו פרמטר

, קבוע או פונקציה שם מחרוזת להיות :יכולtemplate <class T, int Dim< class Vector {

T vec[Dim] ;…

};

Vector<int, 5< v ; Vector < double, 12 < v1; Vector <Complex, 3< v2; Vector <int , 6< v3 ;

ה שגודל בכך היתרון מהטיפוס ? bufferמה חלק הנוב) יקרה מה ? (v=v3רמז

28

Templates - advanced issues הינו טיפוס לכל דבר. אולם templateטיפוס שנוצר ע”י

בדרך כלל כתיבת שמו המלא מסובכת לכן נעזרים בקיצור הבא:

typedef stack<int< stack_int ;

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

typedef stack<stack_int< stack_stack_int;

ונעזר בו:stack_int s1(100);

stack_stack_int s2(5);

s2.push(s1); // in this case push should have better // accepted const T& instead of T ...