העמסת פונקציות באופרטור, ושיטה המוגדרת בתור const

העמסת פונקציות באופרטור, ושיטה המוגדרת בתור const

1) בקוד הבא יש שני מימושים של אופרטור + : אחד בצורה "רגילה", ואחד בצורה של העמסת פונקציה.
קוד:
void main()
{
Point p1(5, 6);
Point p2 = p1 + 3;

p2.show();
}


class Point
{
int x, y;

public:
Point(int x = 0, int y = 0) : x(x), y(y) {}

Point add(const Point& other) const
{
	return Point(x + other.x, y + other.y);
}

Point operator+(const Point& other) const
{
	return Point(x + other.x, y + other.y);
}

Point operator+(int add) const
{
	return Point(x + add, y + add);
}

void show() const 
{ 
	cout << "(" << x << ", " << y << ")\n"; 
}
};

כיצד יודע הקומפיילר במקרה הזה לזהות לאיזו שיטה לפנות בפועל מבלי שתהיה שגיאת ambiguity ?
כיצד בפועל מתאפשרת העמסת פונקציה לאופרטור ?


2) נתון הקוד הבא:

קוד:
1.class X {
2.public:
3.int x;
4.int *p;
5.X() : x(1), p(&x) {}
6.void g() const {
7.p = &x;
8.*p = 1;
9.}
10.};
לגבי הפונקציה המוגדרת כ-const : למה שורה 7 גורמת לשגיאת קומפילציה ואילו שורה 8 לא גורמת לשגיאת קומפילציה?
 

BravoMan

Active member
זה פשוט מאוד:

1. בדוגמה הראשונה, יש שתי העמסות אופרטור באותה שיטה בדיוק, והקומפיילר יודע להבדיל בניהן בדיוק כמו שהוא מבדיל בין כל העמסת פונקציות:
לפי הפרמטרים שהפונקציה מקבלת.
&nbsp
שים לב שהשוני בין 2 המימושים הוא בסוג הפרמטר שהאופרטור מקבל - במקרה הראשון, שאתה קורא לו "רגיל" למרות שהוא אינו שונה מהמקרה השני, מבצעים חיבור בין 2 אובייקטים של Point.
&nbsp
במקרה השני, מבצעים חיבור בין Point ל-int.
&nbsp
כשאתה קורא לפונקציה, הקומפיילר מסתכל מה אתה מחבר למה, ולפי זה בוחר בפונקציה המתאימה.
&nbsp
2. בשורה 7 אתה מנסה לשנות ערך של p.
p הוא איבר במחלקה X. והפונקציה g מוגדרת כ-const, כלומר היא לא אמורה לשנות שום דבר במחלקה g.
&nbsp
בשורה 8 אתה מנסה לשנות ערך בכתובת כלשהי בזיכרון.
הכתובת הזו יכולה להיות שייכת לאובייקט של מחלקה X ויכולה להיות שייכת למשהו אחר לגמרי. לקומפיילר אין דרך לדעת בזמן קומפילציה איזה ערך יהיה ב-p.
&nbsp
למרות שהבנאי מאתחל את p לכתובת של x, האיבר p הוא public כך שייתכן שבהמשך התוכנית תשנה אותו למשהו אחר מחוץ למחלקה.
 
תודה, אבל בשאלה הראשונה עדיין לא הבנתי

את צורת ההעמסה הזאת:
קוד:
Point operator+(const Point& other) const
{
	return Point(x + other.x, y + other.y);
}

Point operator+(int add) const
{
	return Point(x + add, y + add);
}
 

BravoMan

Active member
אתה מבין העמסה רגילה?

ב-++C אופרטור הוא כמו כל פונקציה אחרת.
אתה יכול להעמיס כמה עותקים של פונקציה שאתה רוצה, כל עוד הפרמטרים של כל עותק שונים בטיפוס ו\או בכמות שלהם.
&nbsp
תסתכל על הפונקציות בדוגמה שלך: אחת מקבלת Point ואחרת מקבלת int.
ככה הקומפיילר יודע להבדיל בניהן.
&nbsp
אם תקרא לפונקציה עם פרמטר מסוג int, או כזה שניתן להמיר ל-int, הקומפיילר יבחר גרסה של פונקציה שמצפה ל-int.
אם תקרא לפונקציה עם פרמטר מסוג Point, הקומפיילר יבחר בגרסה שמצפה ל-Point.
 
שאלה נוספת לגבי קוד אחר:

לגבי הקוד הבא:
קוד:
1.class X {};
2.void main() {
3.X a;
4.X b();
5.X c = X;
6.X d = X();
7.}
מדוע שורות 4 ו-5 לא יוצרות אובייקט מסוג X ?
 

BravoMan

Active member
למה שיצרו?

אני משאיר לקומפיילר להסביר לך מה עשית לא בסדר בשורה 5.
זה סינטקס לא חוקי, והוא יישמח להראות לך אפה טעית.

שורה 4 מעניינת יותר:
היא תתקמפל, אבל באמת לא תיצור אבייקט של X.

והסיבה מדוע זה קורה אינה מובנת מאליה, והיא אחת הקונצים המעצבנים של ++C.

אם הייתי נותן לך שורה כזו:
X func();
מה היית חושב עליה?
ללא קוד מסביב, בטח היית חושב שמדובר בהכרזה על פונקציה בשם func שמחזירה אובייקט מסוג X.

אובכן, זה בדיוק מה שהקומפיילר חושב שאתה עושה בשורה 4!
מבחינתו, לא משנה שאתה כבר בתוך פונקציה (main). מותר ב++C להכריז על פונקציות בתוך פונקציות.

והוא יודע שליצירת אובייקט לא צריך סוגריים.

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

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

וזה ההסבר: במקום הכרזה על משתנה, קיבלת הכרזה על פונקציה. אז לא נוצר כלום.
 
שאלה לגבי template

מדוע הקוד הנ"ל לא מתקפל?

קוד:
template<class T>
class Tem
{
	T t;
public:
	Tem(const T& t1) { cout << "t=t1\n"; }
	~Tem()           { cout << "In Tem::d'tor\n"; }
};

void main()
{
Tem<Tem<A> > t1;
cout << "------------\n";
Tem<Tem<A>> t2(t1);
cout << "------------\n";
}
 

BravoMan

Active member
אני אזרוק ניחוש:

כי לא הגדרת A בשום מקום.
&nbsp
אחרת, היה עוזר אם היית מצרף את שגיאת הקומפילציה שנתקלת בה...
 
למעלה