תרגול מס ' 8
description
Transcript of תרגול מס ' 8
8תרגול מס' העמסת אופרטוריםבנאים הורסים והשמותהמרותfriend
2מבוא לתכנות מערכות - 234122
העמסת אופרטורים
העמסת אופרטורים חדשיםהגבלות - דוגמהComplex
3מבוא לתכנות מערכות - 234122
העמסת אופרטורים מבחינתC ++כמו אופרטורים+
הם פונקציות רגילות*או
ניתן להעמיס על אופרטוריםבדומה לפונקציות רגילות עבור
מחלקות
ניתן לקרוא לכל אופרטור מועמסבשתי דרכים
בעזרת התחביר המיוחד השמור –לו, למשל עבור אופרטור+
a+bבעזרת בעזרת תחביר של פונקציה –
, <operator<opרגילה ששמה operator+(a,b)למשל
class Complex { double re, im;
public:Complex(double r, double i);Complex operator+(const Complex& c)
const;Complex operator*(const Complex& c)
const;};
int main() {Complex a = Complex(1, 3.1);Complex b = Complex(1.2, 2);Complex c = b;a = b + c; // b.operator+(c)b = b + c * a; // b + (c * a)c = a * b + Complex(1, 2);return 0;
}
ניתן להגדיר את האופרטור במקרה זה כמתודה
הארגומנט הראשון הוא thisה-
4מבוא לתכנות מערכות - 234122
העמסת אופרטורים על האופרטורים הבאים:ניתן להעמיס
+ - * / % ^ &
| ~ ! = < > +=
-= *= /= %= ^= &= |=
<< >> >>= <<= == != <=
>= && || ++ -- ->* ,
-> [] () new new[] delete delete[]
על האופרטורים הבאים:לא ניתן להעמיס
:: . .* ? : sizeof typeid
)** לא ניתן להגדיר אופרטורים חדשים )למשלשלהם נשמריםהאסוציאטיביות וקדימותם, מספר הפרמטרים אחד הפרמטרים לאופרטור חייב להיות מטיפוס מחלקה אוenum
5מבוא לתכנות מערכות - 234122
העמסת אופרטורים כפונקציות חיצוניות או כמתודותניתן להגדיר את האופרטורים
ויש thisהפרמטר הראשון הוא ה-אם אופרטור המקבל פרמטרים מוגדר כמתודה – פרמטרים נוספיםלהכריז על
הפרמטריםאם האופרטור מוגדר כפונקציה חיצונית יש להכריז על כל –
* לחלק מהאופרטורים קיימות גרסה אונארית וגם גרסה בינארית, למשל - או
class Complex {
double re, im;
public:
Complex(double r, double i);
Complex operator+(const Complex& c) const;
Complex operator-() const; // c1 = -c2;
};
Complex operator-(const Complex& c1, const Complex& c2);
6מבוא לתכנות מערכות - 234122
העמסת אופרטורים-תאימות ל( בגלל סיבות היסטוריותC לכל מחלקה מוגדרים האופרטורים הבאים )
על ידי הקומפיילר: = )השמה(, & )כתובת של( ו-, )סדרתיות( ניתן להעמיס את האופרטורים האלה מחדש או למנוע מהמשתמש במחלקה
גישה מהם על ידי הכרזתם כפרטיים.class X {
private:
void operator=(const X&);
void operator&();
void operator,(const X&);
//...
};
בC++ 11:ניתן למנוע גישה גם ע"י
class X {
void operator=(const X&) = delete;
//...
};
7מבוא לתכנות מערכות - 234122
Complexדוגמה - מחלקת class Complex {
double re, im;
public:
Complex(double r, double i);
Complex& operator+=(const Complex& c);
Complex& operator-=(const Complex& c);
Complex operator-() const;
bool operator==(const Complex& c) const;
};
Complex operator+(const Complex& a, const Complex& b);
Complex operator-(const Complex& a, const Complex& b);
אופרטורים הכוללים השמה += מאפשרים שרשור ולכן כמו
נשמור על ההתנהגות הזו אצלנו
אופרטור - אונארי יוצר מספר מרוכב חדש, לכן התוצאה
מוחזרת כעותק חדשאופרטורים סימטריים נהוג
להכריז מחוץ למחלקה בגלל המרות )דוגמה בהמשך
התרגול(
8מבוא לתכנות מערכות - 234122
Complexדוגמה - מחלקת Complex& Complex::operator+=(const Complex& c) {
re += c.re;im += c.im;return *this;
} Complex& Complex::operator-=(const Complex& c) {
return this->operator+=(-c); // or *this += -c} Complex& Complex::operator-() const {
return *(new Complex(-re, -im));} Complex operator+(const Complex& a, const Complex& b) {
Complex c = a;return c += b;
}
9מבוא לתכנות מערכות - 234122
Complexדוגמה - מחלקת bool Complex::operator==(const Complex& c) const {
return c.re == re && c.im == im;
}
int main() {
Complex a = Complex(1, 3.5);
Complex b = Complex(1.5, 2);
Complex c = a + b; // c = 2.5 + 5.5i
c -= a;
cout << (c == b) << endl;
return 0;
}
10מבוא לתכנות מערכות - 234122
העמסת אופרטורים - הערות
][ אופרטור(subscripting יכול )לשמש להגדרת אוספים
חייב להיות מוגדר בתוך המחלקה–
(intמקבל פרמטר נוסף )לא בהכרח –
)( אופרטור(function call יכול )להיות מוגדר לכל מספר של פרמטרים
חייב להיות מוגדר בתוך המחלקה–
-דוגמאות לשימוש ב)(:החזרת איבר ממטריצה–
החזרת תת-טווח של אוסף–
עצמים המתנהגים כפונקציות –(12)דוגמאות לכך בתרגול
class Random {int seed;
public:Random(int seed);int operator()(int max);
};//...Random r(5);int random = r(100);
class Array {int* array;int size;
public://...int& operator[](int index);
};
int& Array::operator[](int index) {assert(index >= 0 && index
< size);return array[index];
}
11מבוא לתכנות מערכות - 234122
העמסת אופרטורים
יש שתי גרסאות: -- ו-++לאופרטורים pre-ו post כדי להגדיר++iמגדירים את האופרטור כרגיל כדי להגדיר אתi ++מוספים פרמטר דמה
פוגע בקריאות הקוד"להמציא שפה" שימוש בהעמסת אופרטורים כדי–list.add(item) -יותר ברור מ list += item
שפה משותפת שימוש באופרטורים מתאים רק עבור מקרים בהם קיימת)למשל אופרטור * עבור כפל מטריצות(ידועה
class X {
//...
public:
X& operator++(); // ++x
X operator++(int); // x++
};
מדוע ערך ההחזרה שונה?
12מבוא לתכנות מערכות - 234122
העמסת אופרטורים - סיכום
-ניתן להתייחס לאופרטורים כפונקציות רגילות בC++ניתן להעמיס על אופרטורים קיימים כך שישמשו עבור מחלקות את האופרטורים ניתן להגדיר כמתודות )אשר הפרמטר הראשון שלהן
( וכפונקציות מחוץ למחלקותthisהוא לחלק מהאופרטורים יש הגבלות מיוחדותמומלץ להימנע מהעמסת אופרטורים כל עוד היא לא אינטואיטיבית
13מבוא לתכנות מערכות - 234122
בנאים, הורסים והשמות
בנאיםבנאי העתקההורסיםאופרטור ההשמה
14מבוא לתכנות מערכות - 234122
C’tors & D’torsבנאים והורסים - -כמו ב( השימוש בפונקציות מפורשות לאתחול ושחרור עצמיםC חשוף )
לטעויות:את העצםלשכוח לאתחל/לשחרר המשתמש יכול –
פעמייםהמשתמש יכול לאתחל/לשחרר את העצם –
-לשם כך נוספה בC האפשרות להגדיר פונקציות ייעודיות לאתחול ++(Destructors )והורסים( Constructors )בנאיםושחרור עצמים -
-כל עצם שנוצר בC מאותחל על ידי בנאי וכל עצם שמשוחרר מטופל ++על ידי הורס
15מבוא לתכנות מערכות - 234122
Constructorsבנאים - בנאי מוגדר על ידי מתודה ששמה כשם המחלקהלבנאי אין ערך החזרה ניתן להגדיר מספר בנאים בהתאם לחוקי העמסת
פונקציות לבנאי שאינו מקבל פרמטרים קוראים גםdefault
c’tor אם לא מוגדר בנאי בצורה מפורשת למחלקה
הקומפיילר ייצור בנאי חסר פרמטרים בעצמוהבנאי הנוצר על ידי הקומפיילר קורא לבנאי חסר –
הפרמטרים של כל אחד מהשדות שלו
אם מוגדר בנאי כלשהו הקומפיילר לא ייצור בנאי–
באתחול של מערך נקרא בנאי חסר פרמטרים לכלאחד מהאיברים
לא ניתן ליצור מערך של עצמים שאין להם בנאי מתאים–
class X {public:
X();X(int n);
};
X global;
int main() {X x1;X x2(5);X* ptrx1 = new
X;X* ptrx2 = new
X();X* arrayx = new
X[10];arrayx[0] =
X();arrayx[1] =
X(5);// ...return 0;
}
איזה בנאי נקרא בכל אחת מהשורות?
16מבוא לתכנות מערכות - 234122
רשימת אתחול
-חשוב להבדיל בC:בין אתחול להשמה ++אתחול מתבצע על ידי בנאי–
השמה מתבצעת על ידי אופרטור=–
?מה הבעיה בקוד הזה
ברשימת הבנאי אחראי לאתחול השדות של המחלקה, אתחול השדות מתבצע לפני הכניסה לגוף הפונקציה על ידי קריאה לבנאיםהאתחול
אם עבור שדה מסוים לא מצוין כיצד יש לאתחל אותו הוא יאותחל על ידי בנאיחסר פרמטרים
תתקבל שגיאת קומפילציהאם אין בנאי מתאים לשדה –
Complex::Complex(double r, double i) :
re(r), im(i) {
}
Complex::Complex(double r, double i) {
re = r;im = i;
}
int n(5);
int n = 5;
n = 5;
אתחול
אתחול
השמה
re)(-ו im )(נקראים כאן
17מבוא לתכנות מערכות - 234122
Copy C’torבנאי העתקה - בנאי לבנאי המקבל פרמטר מטיפוס העצם אותו הוא מאתחל קוראים
( ויש לו מעמד מיוחדCopy C’tor)העתקה X::X(const X& x)חתימת בנאי ההעתקה היא: –
בנאי ההעתקה משמש להעברת פרמטרים והחזרת ערכיםby value:
אם לא מוגדר בנאי העתקה הקומפיילר ייצור אחד בעצמובנאי ההעתקה שנוצר על ידי הקומפיילר מעתיק את איברי המחלקה אחד אחד –
בעזרת בנאי ההעתקה המתאים של כל שדה
שימו לב: בנאי העתקה נוצר על ידי הקומפיילר גם אם הוגדרו בנאים אחרים–
Y f(X x, Y& y) { // X::X(const X&)// ...return y; // Y::Y(const Y&)
}
byלמה הפרמטר מועבר reference?
18מבוא לתכנות מערכות - 234122
Copy C’torבנאי העתקה - בנאי ההעתקה הנוצר אוטומטית עבורStack:ייראה כך ?מדוע הוא לא מתאים לנו
:בנאי העתקה מתאים ייראה כך
Stack::Stack(const Stack& s) :data(s.data),size(s.size),nextIndex(s.nextIndex) {
}
Stack::Stack(const Stack& s) :data(new int[s.size]),size(s.size),nextIndex(s.nextIndex) {for(int i = 0; i <
nextIndex; i++) {data[i] = s.data[i];
}}
19מבוא לתכנות מערכות - 234122
Destructorsהורסים - ההורס של מחלקהX מוגדר כמתודה ששמה
~X הורס אינו מקבל פרמטרים ואין לו ערך
חזרה הורס יחידניתן להגדירכאשר עצם משוחרר נקרא ההורס שלו
ההורס נקרא אוטומטית - לא כותבים קריאה –מפורשת להורס
אם לא מוגדר הורס הקומפיילר יגדיר אחדבעצמו
גוף הפונקציה של ההורס יהיה ריק–
של עצם כלשהו ייקראו לאחר סיום ההורסההורסים של כל השדות שלו
X global; int main() {
{X x1;
}X x2;X* ptrx1 = new X;X* ptrx2 = new X;delete ptrx1;
X* arrayx = new X[10];
arrayx[0] = X();delete[] arrayx;
return 0;}
מתי נקראים הורסים בקוד הזה?
20מבוא לתכנות מערכות - 234122
זמני קריאה
של בנאי רשימת האתחוללפני הכניסה לקוד מבוצעת עצמו )בתוך ה-} {(הבנאי
סדר הקריאה לאתחול השדות –הוא לפי סדר הגדרתם
במחלקה
שבתוך לאחר ביצוע הקודייקראו הורסים ה-} { בהורס של העצם הנהרס לכל שדותיו
)בסדר ההפוך מבאתחול העצם(
class X {int n;
public:X(int n) : n(n) { cout << "X::X():" << n <<
endl; }~X() { cout << "X::~X():" << n
<< endl; }};
class Y {X x1, x2;
public:Y() : x1(1), x2(2)
{ cout << "Y::Y()" << endl; }
~Y() { cout << "Y::~Y()" << endl; }};
int main() {Y y;return 0;
}
מה יודפס?
21מבוא לתכנות מערכות - 234122
אופרטור השמה
כך שיהיו זהים משתנה קיים השמה היא הפעולה של שינוי ערכיו שללשל משתנה אחר
שחתימתו היא:ניתן להעמיס על אופרטור ההשמה
X& X::operator=(const X& x)
ניתן להעמיס על אופרטור= גם עם חתימות אחרות, אך בדרך כלל איןבכך צורך
אם לא נכתב אופרטור השמה הקומפיילר ייצור אחד בעצמואופרטור ההשמה שהקומפיילר יוצר קורא לאופרטורי השמה של השדות–
22מבוא לתכנות מערכות - 234122
אופרטור השמה
אופרטור השמה למחסניתStack& Stack::operator=(const Stack& s) {
if (this == &s) {
return *this;
}
delete[] data;
data = new int[s.size];
size = s.size;
nextIndex = s.nextIndex;
for(int i=0; i < nextIndex; i++) {
data[i] = s.data[i];
}
return *this;
}
בדיקת השמה עצמיתמדוע בדיקה זו
הכרחית?מחיקת מידע ישן, בניגוד לבנאי העתקה צריך לנקות את המידע
הקודם
ביצוע הקצאות חדשות
עבור שרשורthis*החזרת
העברת המידע
מימוש זה לא מתאים עבור מקרה של חריגות )שיילמדו בהמשך(,
נראה מימוש טוב יותר לאופרטור= בעתיד
23מבוא לתכנות מערכות - 234122
פונקציות הנוצרות על ידי הקומפיילר
:הקומפיילר יוצר את הפונקציות הבאות בעצמו: מאתחל את כל השדות של העצם בעזרת בנאי חסר בנאי חסר פרמטרים–
פרמטרים
במפורש הקומפיילר לא ייצור את פונקציה זוכלשהואם נכתב בנאי •
)אחרי הגדרה default ניתן לייצר בנאי זה ע"י שימוש ב =C++ 11ב –של בנאי ללא ארגומנטים(.
: מאתחל את כל שדות העצם בעזרת בנאי ההעתקה שלהם בנאי העתקה–)והשדה המתאים בעצם אותו מעתיקים(
הקומפיילר ייצור את בנאי ההעתקה גם אם הוגדר בנאי אחר!•
: קורא לאופרטור ההשמה של כל השדות של העצםאופרטור השמה–
: קורא להורסים של כל השדות של העצםהורס–
לנוומתאימות פונקציות שהקומפיילר יוצר בעצמו אין צורך לממש
24מבוא לתכנות מערכות - 234122
Big three:בין בנאי ההעתקה, ההורס ואופרטור ההשמה קיים קשר
אם צריך אחד מהם, צריך את שלושתם
?איך יודעים מתי צריך לממש את הפונקציות האלואם מעורבים מצביעים במחלקה בדרך כלל יש צורך בפונקציות האלו–
delete ו-newאם יש שימוש ב-–אם מתבצעות הקצאות של משאבים אחרים )למשל קבצים(–
25מבוא לתכנות מערכות - 234122
בנאים, הורסים והשמות - סיכום
בנאים משמשים לאתחול עצמיםלפני הכניסה לקוד הבנאי נקראים הבנאים של כל השדות של העצםאחרי ביצוע הקוד בהורס נקראים ההורסים של כל שדות העצם בנאי ההעתקה משמש להעברת והחזרת ערכיםby valueואתחול העתקים אופרטור ההשמה )=( משמש להעתקת ערכים בין שני עצמים קיימים בכתיבת אופרטור השמה חשוב לשים לב לשחרור המידע הקיים והשמות
עצמיות הקומפיילר יכתוב בעצמו בנאי חסר פרמטרים, בנאי העתקה, אופרטור
השמה והורס. אין צורך לכתוב את הפונקציות האלו אם המימוש של הקומייפלר מתאים
אם צריך בנאי העתקה, אופרטור השמה או הורס לא טריוויאלים אז צריךאת שלושתם
26מבוא לתכנות מערכות - 234122
המרות אוטומטיות
המרות על ידי בנאיהעמסת אופרטור ההמרהבנאים מפורשים
27מבוא לתכנות מערכות - 234122
המרותלפעמים נרצה מספר פעולות בין טיפוסים שונים
למשל, פעולות חיבור מספר מרוכב עם ממשי–
Complex operator+(const Complex&, const Complex&);
Complex operator+(const double&, const Complex&);
Complex operator+(const Complex&, const double&);
לא נרצה לממש מספר פונקציות למטרה זו–
ניתן להגדיר המרות בין טיפוסים. כך למשל הקומפיילר יוכל להמירdouble-ל Complex ונצטרך רק פונקציה אחת עבור החיבור
Complex operator+(const Complex&, const Complex&);
-קיימות שתי דרכים להגדיר המרות בC:++בנאיםעל ידי –
העמסת אופרטור המרהעל ידיד –
28מבוא לתכנות מערכות - 234122
המרה על ידי בנאי המקבל פרמטר אם למחלקה יש בנאי
אז בנאי זה ישמש את הקומפיילר יחידלביצוע המרות אוטומטיות
המרות המוגדרות על ידי המשתמשלבחירה בין ישמשו את הקומפיילר
פונקציות מועמסותהמרות אלו מקבלות עדיפות נמוכה יותר –
מהמרות מובנות
בנאי עם ערכי ברירת מחדל היכול לקבלארגומנט יחיד גם יתאים להמרות,
למשל:Complex(double re = 0.0,double im = 0.0)
: re(re), im(im) {}
class Complex {double re, im;
public:Complex(double re) :
re(re), im(0.0) {}//...
}; Complex operator+(const Complex&, const Complex&);int main() {
Complex c = 3.0;Complex c2(1.0,1.0);c = 4.0;c = c2 + 2.0;return 0;
}
29מבוא לתכנות מערכות - 234122
העמסת אופרטור המרה
השימוש בבנאי עבור המרה אינוממחלקה מאפשר לנו להמיר עצם
או להמיר עצם לערך בסיסיממחלקה חדשה למחלקה ישנה
אופרטור המרה ניתן להעמיס על- שם האופרטור כשם הטיפוס אליו
נרצה להמירכמתודהאת האופרטור יש להגדיר –
, ללא ערך חזרההאופרטור מוגדר –טיפוס ערך החזרה נקבע לפי שם
האופרטור
class Rational {int num, denom;
public:Rational(int num, int
denom);// ...operator double() const;
}; Rational::operator double() const {
return double(num)/denom;} int main() {
Rational r(1,2);double d = 0.3;cout << (d+r) << endl;return 0;
}
30מבוא לתכנות מערכות - 234122
המרות אוטומטיות ולהעדיף הגדרת פונקציות להימנע מהגדרת המרות אוטומטיות מומלץ
מפורשות לביצוע המרותהמרות אוטומטיות עלולות לגרום לדו-משמעות–
המרות אוטומטיות עלולות לגרום לקוד מוזר להתקמפל–
class Rational {//...Rational(int num, int denom=1);operator double() const;
};
Rational operator+(const Rational& a, const Rational& b);
void f(const Rational& r, int n) {r + n; // error, ambiguous
}
class Array {//...
public:Array(int size);
}; void f(Array& array) {
array = 50; // Compiles}
31מבוא לתכנות מערכות - 234122
המרות אוטומטיות ניתן להוסיף את המילה השמורהexplicit בתחילת בנאי כדי לציין שבנאי
זה לא ישמש להמרה לא מפורשתארגומנטמומלץ להכריז על בנאים המקבלים –
explicit כ-יחידבמיוחד אם הארגומנט הוא מטיפוס–
(intבסיסי )למשל
שתי המרות אוטומטיות על אותו ארגומנט, הקומפיילר לא יבצעבמקרים בהם זה דרוש יש להמיר בצורה מפורשת
Complex שיומר ל-double לא יומר ל-Rationalלמשל –
class Array {//...explicit Array(int
size);};
void f(Array& array) {array = 50; //
error}
void f(const Rational& r, const Complex& c) {Complex c3 = c + r; // errorComplex c2 = c + double(r); // O.K. double -
> Complex}
32מבוא לתכנות מערכות - 234122
המרות אוטומטיות
ניתן להפעיל על עצם מהטיפוס המתאים בלבדמתודות הקומפיילר לא ימיר משתנה כדי להפעיל עליו מתודה
class Complex {
double re, im;
public:
// ...
Complex(double re);
double abs() const;
};
void f(double& d) {
d.abs(); // error
Complex(d).abs(); // o.k.
}
33מבוא לתכנות מערכות - 234122
המרות אוטומטיות - סיכום
בנאים המקבלים פרמטר אחד ישמשו את הקומפיילר לביצוע המרותאוטומטיות
ניתן להעמיס על אופרטור המרה וכך להגדיר המרה מטיפוס שיצרנולטיפוס שלא כתבנו בעצמנו
מומלץ להימנע מהגדרת המרות אוטומטיות מאחר והן יכולות לגרוםלקוד פחות קריא, בעיות דו-משמעות, וקמפול מוצלח של קוד לא הגיוני
ניתן למנוע מהקומפיילר להשתמש בבנאי עבור המרות על ידי הוספת בהכרזה עליוexplicitהמילה
הקומפיילר לא ישתמש בהמרות כדי להפעיל מתודות
34מבוא לתכנות מערכות - 234122
friendsחברים -
פונקציות חברותמחלקות חברותהעמסת אופרטורי קלט ופלט
35מבוא לתכנות מערכות - 234122
friendפונקציות חברות - לעתים נצטרך לאפשר לפונקציה חיצונית
לגשת לשדות פרטיים
כדי לאפשר לפונקציה לגשת לחלקיםפרטיים של מחלקה מסוימת נכריז עליה
friendבתוך המחלקה אחרי המילה השמורה
הקוד שמופיע בגוף הפונקציה שהוכרזהשל רשאי לגשת לחלקים פרטיים כחברה
friendהמחלקה בה הוכרז כ-
ניתן לממש את הפונקציה יחד עם ההכרזהאו בחוץ כרגיל
class A {int n;
public:A(int n) { this->n =
n; }friend int getN(const
A& a);}; int getN(const A& a) {
return a.n;} int main() {
A a(5);cout << getN(a) <<
endl;return 0;
}
36מבוא לתכנות מערכות - 234122
friendמחלקות חברות - -ניתן להכריז על מחלקה שלמה כfriend
-קוד אשר נכתב בscope של המחלקה B רשאי לגשת לחלקים Aשהוכרזה כחברה של
Aפרטיים של Aלא ניתן לבצע את ההיפך - לגשת מ-–
Bלחלקים פרטיים של
-מומלץ להימנע משימוש בfriend בדרך -של המערכת תכן רע כלל זהו תסמין של
בין החלקים השונים בקודעודף תלויותו
עם זאת קיימים מקרים בהם השימוש חשובfriendב-
class A {int n;
public:A(int n) { this->n =
n; }friend class B;
};
class B {public:
void printA(const A& a) {
cout << a.n << endl;
}};
int main() {A a(5);B b;b.printA(a);return 0;
}
37מבוא לתכנות מערכות - 234122
friendsוהעמסת אופרטורים
מה הבעיה בפונקציהfכאשר אופרטור == ממומש כמתודה?
התנהגותכדי לאפשרשל האופרטורסימטרית
עלינו להגדיר אותוכפונקציה חיצונית
עבורלאפשר גישה לשדות כדיהפונקציה החדשה נצטרך להכריז
friendעליה כ-
class Complex {//...bool operator==(const Complex&)
const;};
bool Complex::operator==(const Complex& c) const {
return c.re == re && c.im == im;}class Complex {
//...bool operator==(const
Complex&, const
Complex&);};
bool operator==(const Complex& a, const Complex& b) {
return a.re == b.re && a.im == b.im;}
void f(const double& d, const Complex& c) {
cout << (c == d) << (d == c) << endl;}
class Complex {//...friend bool operator==(const
Complex&, const
Complex&);};
bool operator==(const Complex& a, const Complex& b) {
return a.re == b.re && a.im == b.im;}
38מבוא לתכנות מערכות - 234122
העמסת אופרטור הפלט
אופרטור הפלט << מועמס כדי לאפשר הדפסה נוחה של עצמים?לא נוכל להגדיר את אופרטור << כמתודה של מחלקה שכתבנו, מדוע:נגדיר את אופרטור << כפונקציה חיצונית
במקרים רבים נצטרך גישה לשדות פרטיים - במקרים אלו נכריז עלfriendהאופרטור כ-
את אופרטור הקלט מעמיסים בצורה דומה עבור המחלקהistream
ostream& operator<<(ostream& os, const Complex& c) {
const char* sign = c.im < 0 ? "" : "+";return os << c.re << sign << c.im << "i";
}
class Complex {//...friend ostream& operator<<(ostream& os, const
Complex& c);};
39מבוא לתכנות מערכות - 234122
המעודכנתComplexמחלקת class Complex {
double re, im;
public:
Complex(double re = 0.0, double im = 0.0);
Complex& operator+=(const Complex& c);
Complex& operator-=(const Complex& c);
Complex operator-() const;
friend bool operator==(const Complex& a, const Complex& b);
friend ostream& operator<<(ostream& os, const Complex& c);
friend istream& operator>>(istream& is, Complex& c);
};
Complex operator+(const Complex& a, const Complex& b);
Complex operator-(const Complex& a, const Complex& b);
מאפשר המרות ואתחול מערכים
עבור אופרטורים אלו אין צורך friendב-
איפה בנאי ההעתקה, ההורס ואופרטור ההשמה? למה?
40מבוא לתכנות מערכות - 234122
המעודכנתComplexמחלקת Complex::Complex(double re, double im) : re(re), im(im) {}
Complex& Complex::operator+=(const Complex& c) {
re += c.re;
im += c.im;
return *this;
}
Complex& Complex::operator-=(const Complex& c) {
return *this += -c;
}
Complex Complex::operator-() const {
return Complex(-re, -im);
}
41מבוא לתכנות מערכות - 234122
המעודכנתComplexמחלקת Complex operator+(const Complex& a, const Complex& b) {
return Complex(a) += b;
}
Complex operator-(const Complex& a, const Complex& b) {
return Complex(a) -= b;
}
ostream& operator<<(ostream& os, const Complex& c) {
const char* sign = c.im < 0 ? "" : "+";
return os << c.re << sign << c.im << "i";
}
istream& operator>>(istream& is, Complex& c) {
return is >> c.re >> c.im;
}
?constלמה אין
כדי לאפשר osמחזירים את שרשור
42מבוא לתכנות מערכות - 234122
המעודכנתComplexמחלקת bool operator==(const Complex& a, const Complex& b) {
return a.re == b.re && a.im == b.im;
}
int main() {
Complex a = 1.0;
Complex b;
cin >> b;
cout << (-a+b) << endl;
return 0;
}
43מבוא לתכנות מערכות - 234122
friendסיכום -
ניתן להכריז על פונקציה שאינה שייכת למחלקה כחברה שלה ולאפשרלה גישה לשדות פרטיים
ניתן להכריז על מחלקה כחברה של מחלקה אחרת כך שכל המתודותשלה ייחשבו כחברות
-משתמשים בfriend עבור העמסת אופרטורים שצריכים להיות מוכרזים כפונקציות חיצוניות )רק אם אכן יש צורך בכך(