קטע של קוד לא ברור לי

קטע של קוד לא ברור לי

אני תוהה אם בקטע הקוד הנ"ל יש משפט תנאי בתוך פקודת cout.
קוד:
void Clock::show()
{
cout << (hours < 10 ? "0" : "") 
	<< hours << ":" 
	<< (minutes < 10 ? "0" : "") 
	<< minutes;
}
 
ויש לי גם שאלה על private

מצד אחד , אני מבין שב-private אנו שמים תכונות שהערך שלהן לא משתנה.
מצד שני, אנימבין שב-public ניתן להגדיר פונקציות שמשנות את אותם ערכים.

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

BravoMan

Active member
אין שום סטירה: לא הבנת נכון את תפקיד ה-private.

הערכים ב-private יכולים להשתנות כמה שתרצה.
רק ערכים const אינם משתנים.
&nbsp
גם פונקציות (מתודות) יכולות להיות private.
&nbsp
ההבדל בין שדה (משתנה) private ל-public הוא מי יכול לשנות אותו.
שדה שמוגדר private יכול לשנות רק קוד בתוך המחלקה.
שדה שמוגדר public אפשר לשנות ישירות מכל מקום בקוד.
&nbsp
אז למה עושים שדות private ואז כותבים פונקציה public כדי לשנות אותם?
כדי לשמור על עקרון ההכלה ולשלוט בקלות על השינויים.
&nbsp
נניח שיש לך מחלקה שמייצגת בן אדם.
במחלקה יש שדה age ששומר את הגיל של האדם.
&nbsp
מן הסתם, שדה כזה לא יכול לקבל ערך שלילי, כי אין דבר כזה "בן 10-".
&nbsp
אם היית עושה את השדה הזה public, היית צריך לבדוק מה מכניסים אליו בכל מקום בקוד שניגש אליו.
ואם אתה בכלל לא שולט בקוד שמשתמש במחלקה שלך, אלא רק במחלקה עצמה?
איך תוודא שלא ייווצרו בני אדם בגיל שלילי?
&nbsp
אם תקבע את השדה private, כל קוד מחוץ למחלקה יצטרך לעבור בפונקציה שלך שתיצור, כדי לשנות אותו. בפונקציה הזו תוכל לבדוק שהערך שמבקשים לשים בשדה חוקי, לפני שאתה מסכים לשנות את השדה.
&nbsp
עוד דוגמה:
נניח שאתה כותב מחלקה שמייצגת זווית.
אתה בוחר לייצוג הפנימי לשמור את הזוויות בתור מעלות במשתנה מסוג float.
&nbsp
אבל אחרי זמן מה גילית שנוח לך יותר לעשות חישובים עם רדיאנים, ובשביל דיוק גבוהה יותר להחזיק את הערך במשתנה מסוג double.
&nbsp
מה עכשיו?
אם האיבר ששומר את המעלות היה public, היה צריך לרוץ בכל מקום בקוד ולשנות את כל הטיפול בו.
אבל אם הוא private, יש רק מקום אחד בקוד בו תצטרך לעשות המרה ולשנות טיפול - פונקציות get ו-set במחלקה שלך.
שאר הקוד בתוכנה יכול להמשיך להשתמש במעלות.
&nbsp
 
עכשיו מובן. יש לי עוד שאלות בבקשה...

1) האם למעשה הבנאי נועד בהגדרת מחלקה לתת ברירת מחדל לפרמטרים המוגדרים תחת private? מתי ניתן לוותר על הבנאי או שמא תמיד יש להגדירו?
מדוע לא ניתן לוותר על הבנאי ולהשתמש במקום זאת בפונקציות get ו-set (אני מניח שתדעו למה כוונתי...) ?
2) מתי יש להשתמש ב-const במחלקה? האם רק בפונקציות שבהכרח לא מבצעות שינוי של הפרמטרים המוגדרים תחת private?
 
ואם כבר הזכרתי בנאים- לגבי קטע הקוד הבא:

קוד:
class Stam
{
int num;
public:
Stam(int n)
{
num = n;
cout << "In c'tor -> num=" << num << endl;
}

~Stam() 
{
	cout << "In d'tor -> num=" << num << endl;
}
};

void foo(Stam s)
{
	cout << "In foo\n";
}

void goo(Stam& s)
{
	cout << "In goo\n";
}
מדוע בפונקציה goo יש & אחרי Stam?
 

אוסנתס

New member
כי הוא מקבל בפרמטר

את הכתובת של המשתנה s ולא את הערך של המשתנה. זו לא נראית מחלקה בעלת משמעות.
 

BravoMan

Active member
את טועה!

הוא לא מקבל כתובת, הוא מקבל reference.
&nbsp
אלה דברים קרובים, אבל לא זהים!
&nbsp
ב-++C (בניגוד ל-C) יש דבר כזה reference - התייחסות למשתנה - כאילו קיצור דרך אליו.
כשאר מעבירים פרמטר לפי reference כפי שעשו בדוגמת הקוד, זה נותן לפונקציה גישה ישירה לאותו משתנה.
&nbsp
בניגוד להעברת כתובת (מצביע, תוך שימוש ב-*), אין צורך לבצע dereference כשרוצים לקבל את הערך.
ניתן לקרוא ולהציב ערכים בפרמטר בצורה רגילה כאילו היה משתנה מקומי של פונקציה, אבל ההצבה תישמר גם מחוץ לפונקציה.
&nbsp
לפרטים נוספים קראו כאן:
http://www.learncpp.com/cpp-tutorial/73-passing-arguments-by-reference/
 

אוסנתס

New member
כל אחד יכול להבין מהתגובה

למה הכוונה לא צריך להכנס לכזה פירוט בהודעה.
 

BravoMan

Active member
סליחה???!

את רוצה שאני לא אעזור למישהו כדי שלך יהיה הכבוד לא להודות שנתת תשובה שגויה?
איזו מין התנהלות זו?
&nbsp
השואל שאל מה משמעות האופרטור & לפני פרמטר.
התשובה הנכונה היא שהאופרטור מציין reference שכלל אינו כתובת!
אם הפרמטר היה כתובת, האופרטור לפניו היה * והשימוש בפרמטר בתוך ומחוץ לפונקציה היה עובד שונה.
&nbsp
לפי השאלות של פותח השרשור רואים בבירור שהוא רק לומד, ולכן אין לו דרך לדעת שכשכתבת לו "כתובת" התכוונת בעצם למשהו שבכלל אינו כתובת!
 

BravoMan

Active member
כתובת באנגלית זה address

reference בעברית זה ייחוס.
&nbsp
זה לא עניין של תרגום, זה עניין של מינוח נכון ומשמעות המונח.
בתור מתכנתת את וודאי יודעת שחשוב לדייק במינוח כשמתקשרים בעניינים טכניים, אחרת הדבר יוביל לבעיות.
 

אוסנתס

New member
זה כבר לפורום אנגלית

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

BravoMan

Active member
ממש לא לפורום אנגלית:

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

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

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

address ו-reference (לא משנה איך תבחרי לקרוא להן בעברית) בשפת ++C הם מונחים שונים, עם סינטקס שונה וצורת עבודה שונה.

ואם כבר: לפי מה בדיוק את קובעת איזה מונח מצריך איזה פירוש?
לצורך העניין, אם ניקח את הקוד הבא, מה יודפס:
קוד:
int a = 42;

void what(int &num) {
    cout << num;
}
 

אוסנתס

New member
אם יש לי עניין אני אתקין אריץ ואבדוק.

האמת, אין לי עניין להבין את בעל השפה אלא להשתמש בשפה. הוא ידפיס את הערך של num, בלי להריץ נראה לי שאם תקרא עם a ידפיס 42. אני לא עם סביבת פיתוח של C, C++.
 

BravoMan

Active member
למה את צריכה להתקין משהו או להריץ משהו?

ולמה נראה לך?
&nbsp
מקודם, ענית בביטחון מלא: "כי הוא מקבל בפרמטר את הכתובת של המשתנה s ולא את הערך של המשתנה"
&nbsp
אם הוא מקבל את הכתובת, למה שידפיס ערך ולא את הכתובת שהוא מקבל?
הרי המשפט אומר לו להדפיס את הערך של s?
 

אוסנתס

New member
השיחה הזו מיותרת

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

BravoMan

Active member
זו לא היית חקירה, זה היה ניסיון להבהיר לך את הבעיה...

אני מסכים איתך שהענף הזה בשרשור מיותר, אבל את זו שהחלטת שנכון לענות לאנשים בפורום עם מידע שגוי ומבלבל, ובחרת לקבוע מה אנשים שאינך מכירה כלל יודעים ולא יודעים, ובאיזה מונחים אפשר להשתמש.
&nbsp
אני בסה"כ מנסה להעביר הבדל טכני חשוב בין ייחוס לכתובת בשפת ++C.
&nbsp
מה שכתבת נכון - יודפס 42.
הסיבה היא, שייחוס אינו כתובת, ואינו מכיל כתובת, אלא משמש בדיוק באותה צורה כמו שם המשתנה המקורי.
&nbsp
אם הפרמטר בדוגמה שלי היה מכיל כתובת, היית מודפסת כתובת, ושימוש באופרטור = היה דורס את הכתובת הזו, ולא משנה בכלל את תוכן המשתנה המקורי (זה שהכתובת שלו נשלחה לפונקציה).
&nbsp
ומה לעשות שבגלל שמדובר בפורום פומבי ופתוח, את אני והשואל לא היחידים כאן.
יהיו עוד אנשים עם שאלות דומות שיקראו את השרשור הזה, וחשוב לי שהם יקבלו מידע נכון ומדויק עד כמה שאפשר.
 

אוסנתס

New member
המידע לא שגוי ולא מבלבל

אתה זה אתה כתבת מאחורי שם בדוי, מה שבא לך.
 

BravoMan

Active member
תפקידו של בנאי הוא...

"לבנות אובייקט מטיפוס מסוים".
בנאי הוא פונקציה שיכולה לבצע כל מיני דברים.
בניהם, לאתחל את האיברים של המחלקה.
בנאי יכול גם לקבל פרמטרים ולאתחל לפי הם, במקום סתם לתת ערכי ברירת מחדל.
&nbsp
אם אין פעולה מיוחדת חוץ מהקצאת זיכרון שצריך לבצע כשבונים אובייקט ממחלקה מסוימת, אפשר לוותר על כתיבה מפורשת של בנאי, והקומפיילר יוסיף בנאי ריק ברירת מחדל.
&nbsp
לחלופין, ניתן לתת ערכים ברירת מחדל לאיברי מחלקה ישירות כשמגדירים את האיברים (כמו שמאתחלים כל משתנה), ואז בנאי ברירת מחדל שהקומפיילר בונה ישים את הערכים האלה פנימה.
&nbsp
2) מהילה const ב-++C מציינת "לא ניתן לשינוי \ אין שינוי".
משתמשים בה בכל מקום בו צריך להבהיר שערך מסוים הוא קבוע ולא בר שינוי, או שמתודה (לא משנה אם היא private או public) לא משנה את מצב האובייקט.
 

BravoMan

Active member
קרוב:

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