עבור לתוכן

c#|פונקציות חופפות

Featured Replies

פורסם

אפשר בבקשה הסבר מזה פונקציה חופפת

ואיך מגדירים אותה בקוד.

תודה.

פורסם

יכול להיות שהכוונה ל"העמסת פונקציות" - Functions Overloading?

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

למה הכוונה?

למשל בתוכנה של מחשבון אתה מצפה למצוא פעולת חיבור

ובקוד אתה תצפה למצוא למשל

int Add(int n1, int n2);

שמקבלת שני מספרים שלמים ומחברת אותם ומחזירה לך מספר שלם

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

string Add(string n1, string n2)

ואולי הקלט הוא לא מספר שלם

float Add(float n1, float n2)

לרוב כל הפונקציות הללו מבצעות פעולה או הסבה וקוראות לפונקציה אחת מרכזית, במקרה שלמעלה ב-int התוכן היה משהו כזה:

int Add(int n1, int n2)

{

return (int)Add((float)n1, (float)n2));

}

ושל המחרוזות היה משהו כזה:

string Add(string n1, string n2)

{

float f1, f2;

// המרה ממחרוזת למשתנה שבר

float fres = Add(f1, f2);

string res;

// המרה ממשתנה שבר למחרוזת

return (res);

}

הבנת את הרעיון?

נערך על-ידי LiorP23

פורסם

למה הצמדת את הקוד לשמאל ולא שמת אותו בתוך טג קוד?

פורסם
  • מחבר
יכול להיות שהכוונה ל"העמסת פונקציות" - Functions Overloading?

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

למה הכוונה?

למשל בתוכנה של מחשבון אתה מצפה למצוא פעולת חיבור

ובקוד אתה תצפה למצוא למשל

int Add(int n1, int n2);

שמקבלת שני מספרים שלמים ומחברת אותם ומחזירה לך מספר שלם

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

string Add(string n1, string n2)

ואולי הקלט הוא לא מספר שלם

float Add(float n1, float n2)

לרוב כל הפונקציות הללו מבצעות פעולה או הסבה וקוראות לפונקציה אחת מרכזית, במקרה שלמעלה ב-int התוכן היה משהו כזה:

int Add(int n1, int n2)

{

return (int)Add((float)n1, (float)n2));

}

ושל המחרוזות היה משהו כזה:

string Add(string n1, string n2)

{

float f1, f2;

// המרה ממחרוזת למשתנה שבר

float fres = Add(f1, f2);

string res;

// המרה ממשתנה שבר למחרוזת

return (res);

}

הבנת את הרעיון?

התכוונתי למדריך הזה זה פונקצייה חופפת או פונקצייה הורסת?

http://www.underwar.co.il/1-Programming/d104/25/

ואפשר גם הסבר על כל הקוד בצורה של הערות.?

שפה.

http://www.underwar.co.il/1-Programming/d104/28/

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

 using System;
public class CRectangle
{
private int height, width;
public void SetHeight(int newHeight) { height = newHeight; }
public void SetWidth(int newWidth) { width = newWidth; }
public int GetHeight() { return height; }
public int GetWidth() { return width; }
}
public class CClassExample1
{
public static int Main(string[] args)
{
CRectangle rec1 = new CRectangle();
rec1.SetHeight(10);
rec1.SetWidth(20);
Console.WriteLine("Rectangle size: {0} x {1}",
rec1.GetHeight(), rec1.GetWidth());
return 0;
}
}

פורסם

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

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

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

וזה מה שנקרא דריסה (עד כמה שאני זוכר)

אבל יש דרך להעמיס שיטות (פונקציות) בלי שזה יגרום לדריסה.השיטה writeline לדוגמא היא שיטה מועמסת יש לה 19 אפשרויות שונות!

אחת מקבלת ערך מסוג int ומדפיסה אותו אחרת מקבלת ערך מסוג bool ומדפיסה אותו וכו'...

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

עכשיו איך עושים את זה?

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

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

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

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

אני מקווה שהכל מובן.

נ.ב. תקנו אותי אם טעיתי במשהו.

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

אופן הפינוי הוא בכמה שלבים שהמהדר עושה לבד, ומומלץ לא להתערב לו בזה כי זה יכול לגרום לתקלות (המשפט האחרון אמור להיות מודגש כדי להדגיש את חומרתו, אבל שוב- אין לי את הסרגל אז אני לא יכול לעשות את זה) כגון אם תפנה משתנה שעדיין פעיל במקום כלשהו- זה יצור שגיאה שתהרוס הכל, לכן ב#c המהדר עושה את זה לבד ולא מתערבים לו (שוב פעם מודגש) טכנית אפשרי לעשות את זה ידנית אבל זה מיותר ומסוכן (לתוכנה לא לך :) ) וכבר מאוחר ואין לי כוח להאריך בזה

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

נ.ב. שוב אם יש טעות תתקנו אותי.

נערך על-ידי eido300

פורסם

בלבלת פה קצת.

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

הגדרה של שיטות מועמסות לא יגרמו לאזהרה - זה מנגנון לגיטימי של שפת התכנות. הן יגרמו לאזהרה רק אם הקומפיילר לא מסוגל להחליט באיזו שיטה להשתמש (לדוגמה: נניח שכתבת למחלקה שתי שיטות עם אותו שם - אחת שמקבלת int ואחרת שמקבלת long - וניסית לקרוא לשיטה הזו עם משתנה מטיפוס double. אז הקומפיילר לא ידע לאיזה מהשיטות לקרוא, וייתן שגיאה).

בכל מקרה, eliom, אין קשר בין פונקציות חופפות ופונקציה הורסת (destructor).

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

[COLOR=#3E3E3E]CRectangle rec1 = new CRectangle();[/COLOR]

מה שקורה הוא שעכשיו יש משתנה בשם rec1 שמצביע לאובייקט מטיפוס CRectangle. במקרה של הקוד של eliom המשתנה הזה מוגדר רק בתוך הפונקציה Main (כלומר ברגע שהפונקציה Main תסתיים הוא לא יהיה קיים יותר). האובייקט, לעומת זאת, מוגדר במקום אחר בזכרון של התכנית - מקום שנקרא ה-Heap. שים לב שהמשתנה rec1 לא מכיל כלום פרט להצבעה לאובייקט. האובייקט עצמו הוא זה שמכיל את כל המידע (ה-height וה-width).

נניח עכשיו שהפעלתי את הקוד הזה:

rec1 = null;

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

יש מבין?

נערך על-ידי שניצל

פורסם

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

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

"הגדרה של שיטות מועמסות לא יגרמו לאזהרה - זה מנגנון לגיטימי של שפת התכנות. הן יגרמו לאזהרה רק אם הקומפיילר לא מסוגל להחליט באיזו שיטה להשתמש (לדוגמה: נניח שכתבת למחלקה שתי שיטות עם אותו שם - אחת שמקבלת int ואחרת שמקבלת long - וניסית לקרוא לשיטה הזו עם משתנה מטיפוס double. אז הקומפיילר לא ידע לאיזה מהשיטות לקרוא, וייתן שגיאה)."

עד כמה שאני יודע העמסה (overloaded) זה רק אם יש שני מזהים (identifiers) בעלי אותו שם באותו תחום הכרזה (scope) (וזה לא משנה אם זה שתי שיטות שני שדות).

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

אם אחרי זה אתה עדיין חושב שטעיתי אני אשמח שתכתוב לי במה טעיתי (אולי נלמד משהו חדש :) )

נערך על-ידי eido300

פורסם

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

אין כזה דבר העמסה של "מזהים", העמסה היא רק של שיטות (אין כזה דבר העמסה של שדות, לפחות לא ב-#C) בתוך אותה מחלקה.

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

CRectangle rec1 = new CRectangle();
CRectangle rec2 = rec1;

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

על מנת שהאובייקט ימחק צריך לדאוג ששני המשתנים כבר לא יצביעו אליו (כלומר לא מספיק לעשות rec1 = null, צריך לעשות גם rec2 = null).

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

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

נערך על-ידי שניצל

פורסם

פותח הת'רד לא ציין בכלל את המושג "משתנים חופפים" או "משתנים מועמסים",

נכון, אותם הכנסתי כדי להסביר.

ובכלל אין מושג כזה. אין כזה דבר העמסה של "מזהים", העמסה היא רק של שיטות (אין כזה דבר העמסה של שדות, לפחות לא ב-#C) בתוך אותה מחלקה.

על זה אני לא יכול להתווכח, זה מה שלמדתי בספר (שאגב, הוציאו microsoft) - וזה מה שאני יודע.

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

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

קוד:

CRectangle rec1 = new CRectangle();

CRectangle rec2 = rec1;

אז יש בו

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

על מנת שהאובייקט ימחק צריך לדאוג ששני המשתנים כבר לא יצביעו אליו (כלומר לא מספיק לעשות rec1 = null, צריך לעשות גם rec2 = null).

ניהול הזכרון לא מוחק משתנים, אלא אובייקטים,

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

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

לא כתבתי שהוא מפנה מתי שהזיכרון מלא, למעשה לא כתבתי בכלל מתי הוא מפנה. כתבתי שצריך לפנות כדי שהזיכרון לא יתמלא.

על איזה תקלות בניהול הזכרון אתה מדבר, אגב?

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

2. בדוק אם בין האובייקטים הבלתי נגישים יש אובייקטים עם מפרק (destructor), אם יש הוא מעביר אותם לתור מיוחד(freachable queue).

3. הקצאת זיכרון מחדש לאובייקטים שלא צריך לחסל.

4.הוא מסיים בנפרד את האובייקטים עם המפרק (destructor) ואת האובייקטים בלי המפרק.

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

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

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

אני כאן התבלבלתי בין זה לבין הנושא של ניהול משאבים ששם אפשר להשתמש בusing, או בשיטת פינוי (disposal).(שהאמת אני לא מבין מה ההבדל בין זה לבין ניהול זיכרון? אשמח שתסביר)

תודה רבה על הערות (המחכימות), ושוב תקן אותי אם טעיתי במשהו.:xyxthumbs:

פורסם

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

יש אובייקטים מסויימים שמוגדרים כ-Disposable, מה שאומר שצריך לעשות להם Dispose בסוף השימוש. הפונקציה Dispose שלהם דואגת לשחרר את כל המשאבים שהם צורכים (לדוגמה - FileStream דואג לסגור את הקובץ, DbConnection דואג לנתק את החיבור למסד הנתונים...).

using סה"כ עושה Dispose אוטומטית בסוף ה-scope שבו הוא מוגדר, וככה חוסך את הצורך ב-Dispose ידנית. בסופו של דבר הם עושים אותו דבר.

תיאורטית זה לא חובה לעשות Dispose, כי בדרך כלל לכל מחלקה שהיא Disposable מוגדר גם destructor שעושה את ה-Dispose. ה-destructor הזה כמובן נקרא אוטומטית כשהאובייקט נמחק מהזכרון. הבעיה עם זה היא שאנחנו לא יכולים להבטיח מתי בדיוק האובייקט ימחק מהזכרון, כי אין לנו שליטה על כך (גם קריאה ל-GC.Collect לא מבטיחה את זה), ולכן עדיף לבצע את זה בעצמנו.

פורסם

הבנתי, תודה

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

ארכיון

דיון זה הועבר לארכיון ולא ניתן להוסיף בו תגובות חדשות.

דיונים חדשים