templates

annefan

New member
אגב, גם ג'אווה

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

annefan

New member
אני לא זוכר איך קוראים לזה

אני לא מאוד אוהב ג'אווה, קראתי את זה מתוך ההשוואה ל-++C. זה היה ב-DDJ או ב-c++ Report או משהו כזה.
 

annefan

New member
שתי דרכים

אחת זה להבין מה קורה מאחורי הקלעים, וזה שני דברים כאן: 1. שפונקציות חברות מופיעות בזכרון פעם אחת בלבד (ולא עם כל אוביקט) 2. שבכל פעם שנוצר לך אוביקט מתבנית כשהפרמטר שלו שונה, למעשה זה אוביקט מ-class חדש.
vector<int> i1; vector<int> i2; vector<double> d1;​
יש כאן שתי מחלקות שונות לחלוטין. אחת היא:
vector<int>​
והשניה:
vector<double>​
לכן, בכל המקרים של שימוש בראשונה תקרא אותה פונקציה, ובשימוש בשניה תקראה פונקציה שונה לחלוטין (לא בהכרח במובן של לוגיקה שונה, אלא מבחינת מיקום בזכרון) הדרך השניה היא להסתכל ב-VC יחד עם קוד אסמבלי, ולראות שהכתובות של הפונקציות שנקראו היא אותה כתובת: תוכנית:
vector<int> i1; vector<int> i2; vector<double> d1; i1.push_back(1); i2.push_back(2); d1.push_back(3.0);​
והאסמבלר שלה:
i1.push_back(1); 0040105A mov dword ptr [ebp-144h],1 00401064 lea eax,[ebp-144h] 0040106A push eax 0040106B lea ecx,[i1] 0040106E call std::vector<int,std::allocator<int> >::push_back (4011F0h) i2.push_back(2); 00401073 mov dword ptr [ebp-138h],2 0040107D lea eax,[ebp-138h] 00401083 push eax 00401084 lea ecx,[i2] 00401087 call std::vector<int,std::allocator<int> >::push_back (4011F0h) d1.push_back(3.0); 0040108C fld qword ptr [__real@4008000000000000 (421228h)] 00401092 fstp qword ptr [ebp-12Ch] 00401098 lea eax,[ebp-12Ch] 0040109E push eax 0040109F lea ecx,[d1] 004010A2 call std::vector<double,std::allocator<double> >::push_back (401330h)​
שים לב לכתובות של ה-call. הן זהות ב-push_back של ה-int, ושונות בשלישי (של double)
 

Scipio

New member
הוכחה לפי ה אובייקט שנוצר

אפשר להוכיח את זה על ידי בדיקה של הפונקציות שנמצאות בתוך האובייקט. בUNIX לרוב יש תוכנה שקוראים לה NM והיא מציינת מה יש בתוך האובייקט. (אני בטוח שיש גם ב VISUAL STUDIO כלי מקביל אך לא קופץ לי בראש מהו). אפשר להסתכל ב MAP אשר נוצר ב VISUAL STUDIO .
 

selalerer

New member
זה מעלה שאלה טובה:

איך אני יכול להדפיס את הכתובת של פונקציה מועמסת (overloaded)??? איך אני אומר לקומפיילר לאיזו פונקציה אני מתכוון? נסיתי לכתוב ככה:
printf("%X",v1.&push_back(int));​
אבל הוא לא קיבל את זה (parse error). איך בכל זאת אפשר לומר לו לאיזו פונקציה אני מתכוון? תודה, סלע.
 

annefan

New member
למה לא?

התשובה היא שלא, אי אפשר. אבל התשובה שם...
 

selalerer

New member
לא מצאתי את זה שם...

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

annefan

New member
אולי לא הבנתי אותך

בשאלה המקורית שלך, רצית, למעשה להתייחס למצביע לפונקציה חברה כמצביע לפונקציה רגילה או כ-* void. ראה שם שאלות 33.1 ו-33.7 למה זה לא עובד (או עלול לעבוד רק לפעמים).
vector<int> i1; vector<int> i2; vector<double> d1; i1.push_back(1); i2.push_back(2); d1.push_back(3.0); printf("addr: %X\n", &vector<int>::push_back); printf("addr: %X\n", i1.push_back); printf("addr: %X\n", i2.push_back); printf("addr: %X\n", &vector<double>::push_back); printf("addr: %X\n", d1.push_back);​
הקוד הזה עובר קומפילציה ב-VS.NET (ומוכיח את מה ששאל השואל לגבי כתובות הפונקציות). ב-++g הוא לא עובד קומפילציה בכלל.
 

selalerer

New member
אני שואל על פונקציות מועמסות....

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

annefan

New member
תגיד, סלע, רוצה מכות??

אני אומר לך שזה לא תקני. ה-FAQ אומר לך לא לעשות את זה כי זה לא תקני, וכי אין לך מושג מה יצא מהעגל הזה. השעה 23:55 ואתה שואל אותי שאלות כאלה?? מחר בבוקר אני רוצה תשובה ממך! שיהיה לך לילה טוב.
 

selalerer

New member
מה לא תקני?

יש לי שתי פונקציות:
long add1(int a,int b) { return a+b; } double add1(float a,float b) { return a+b; }​
עכשיו אני רוצה לדעת את הכתובת של השניה למשל. לכתוב ככה זה לא טוב:
printf("%X",add1);​
כי הוא לא יודע לאיזה אני מתכוון, אין דרך לדעת בכל זאת את הכתובת שלה?
 

vinney

Well-known member
נו באמת, סלע...

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

selalerer

New member
שיוסיפו! מה זה החרטה הזה?!

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

vinney

Well-known member
יש סיבה מעשית שלא

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

selalerer

New member
רוב הזמן אתה צודק, זה יותר נוח ולכן

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

annefan

New member
אני חושב שזה יותר מדי תלוי מימוש

(אגב, "רמת השליטה" זה טיעון להרבה דברים, אבל לא לכל דבר. אתה לא יכול ליצור טיפוס שהוא גם string וגם integer, נכון? לצורך העניין, אתה אפילו לא יכול ליצור וקטור של strings ו-integers, נכון? אז מה? אין לך שליטה?) לגבי מצביעים לפונקציות חברות, אני לא חושב שזה בלתי אפשרי, אלא שזה תלוי מימוש. על פונקציות כאלה אתה צריך לשמור הרבה יותר מידע מאשר מצביעים רגילים. הדרך בה אתה שומר את המידע הזה לא נקבעה בסטנדרט (אולי בגלל שזה לא מספיק חשוב. סה"כ זה לא ה-feature הכי שימושי בעולם. אולי בגלל שזה חדש יחסית ולא נסגר עד הסוף)
 
למעלה