למה זה לא עובד?

eyal the one

New member
למה זה לא עובד?

void CAsdDlg::OnOK() { // TODO: Add extra validation here CWnd* p = GetDlgItem(IDCANCEL); CButton* h = dynamic_cast<CButton*>(p); h->SetWindowText(_T("eyal")); CDialog::OnOK(); }​
מדובר ב דיאלוג רגיל OK ו CANCEL בלבד
 

cganir

New member
מה לא עובד ? לא מתקמפל ?

לא רואה שינוי ? מה אתה מנסה לעשות, איזו תוצאה אתה מצפה לראות, ומה בסופו של דבר אתה רואה ?
 

gmorphus

New member
מצטרף לשאלה שמעליי ומוסיף

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

eyal the one

New member
כן מתקמפל

אבל בזמן ריצה התוכנית עפה. אם הייתי עושה casting רגיל זה היה עובר בשלום , אבל משום מה dynamic_cast לא עובד פה. אגב במקרה הזה ה dynamic_cast הוא חוקי ואמור להחזיר פוינטר ל CButton יש פה downcast לכל דבר (לפני שהערך הוחזר כ CWnd* מ GetDlgItem) הוא עבר המרה upcast מ CButton ל CWnd. ובגלל שבעבר הפוינטר התחיל מ CButton ה downcast אמור לעבור בשלום. אז מי שאמר קודם שב VC6 יש RTTI (נדמה לי שזה היה אלדד), אולי יוכל לעזור בנושא.
 

gmorphus

New member
למה?

למה לך להשתמש ב dynamic_cast כשאתה יכול לעשות casting רגיל? אני אשאל שאלה יותר מהותית, למה לך בכלל לעשות casting כלשהו כשהפונקציה SetWindowText שייכת ל CWnd ולא ספציפית ל CButton. בכל מקרה, כשאני מנסה לקמפל את הקוד שהראית אני מקבל את האזהרה הבאה מהקומפיילר:
D:\Projects\MFC Tests\Test1\Test1Dlg.cpp(176) : warning C4541: 'dynamic_cast' used on polymorphic type 'class CWnd' with /GR-; unpredictable behavior may result​
שזה בעצם השאלה שבה פתחתי את ההודעה...
 

gmorphus

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

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

gilad_no

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

אם חלון היה מחזיק באמת את רשימת המצביעים האמיתיים, אז DYNAMICCAST היה עובד לך. אבל מה שקורה בפועל זה שנוצר אובייקט זמני של CWND שעוטף את HWND שמוחזר ע"י GETDLGITEM. מכיוון שאתה יודע שזהו כפתור (כי אתה יצרת אותו), תוכל לקרוא לפונקציות שלו שבסה"כ עוטפות API רגיל שעובד על כל HWND. אין כאן שום פולימורפיזם במנגנון הנ"ל. הדרך היחידה שלך לוודא טיפוס של חלון שמוחזר ע"י GETDLGITEM הינה לבדוק את טיפוס המחלקה שלו עם טיפוסים קבועים (BUTTON וכו'). DYNAMICCAST לא יעבוד במקרה הנ"ל מכיוון שMFC מרמה (בגלל זה היא כ"כ גרועה לפי טעמי).
 

eyal the one

New member
לא נכון

עובדה שה casting הרגיל כן עובד. וכן מדובר בפולימרפיזם , הפונקציה SetWindowText היא וירטואלית, תנסה להריץ את הקוד הבא:
void CAassDlg::OnOK() { // TODO: Add extra validation here (GetDlgItem(IDCANCEL))->SetWindowText("eyal"); }​
הפוינטר המוחזר בהחלט מצביע על אוביקט יורש של CButton, אחרת הוא לא היה יודע שהמימוש של הפונקציה שונה (הצגת הטקסט בלב הכפתור) אל תשכח שבברירת המחדל הצגת הטקסט היא ב caption.
 

gilad_no

New member
טעות לחלוטין

תנסה לקרוא לSETWINDOWSTEXT של הAPI הרגיל רק עם HWND של כפתור ותגיד לי מה קורה.
 

ברנדל

New member
בדיוק כך ../images/Emo45.gif

איל, גם אני בעבר התחבטתי בשאלה הזו, טוב שאתה מתעניין בדברים שמאחורי הקלעים ולא מקבל אותם as is קבל קישור
 

gmorphus

New member
מגניייב! עכשיו אני מבין למה

אף פונקציה לא וירטואלית גם בCWnd וגם CButton. כי אם זה היה ככה ומה שאתה אומר הוא נכון אז הcasting לא היה עוזר והיינו מגיעים לפונקציות של CWnd במקום לאלה של CButton. אני לא חושב שזה נורא לעשות את זה ולרמות ככה. אחרי הכל זה עובד... ויותר מזה, אתה יכול לרשת מ CButton בעצמך (לדאוג לא לשים פונקציות וירטואליות) ולהשתמש רק בפונקציות של הAPI וזה עדיין יעבוד. אסור לך גם להוסיף משתנים אם אתה רוצה להשתמש בזה דרך GetDlgItem. עוד משהו, אם למשל תירש מהפונקציות הוירטואליות ב CWnd (למשל OnCommand) ותשתמש בGetDlgItem כדי לקרוא להן זה לא יעבוד (אם יהיה לך מצביע "אמיתי" לאובייקבט שלך לא תהיה שום בעיה). הממ.. טוב זה די מגעיל.
 

voguemaster

New member
הייתי מוסיף

ASSERT(h != NULL);​
וכנראה שהיית מגלה שהפוינטר שאתה מקבל מה-cast הוא NULL, כלומר, ה-cast נכשל. עכשיו לך תגלה למה
 

eyal the one

New member
למה ה cast נכשל??

זה בדיוק מה שאני לא מבין, יש כאן downcast תקין לחלוטין
 
למעלה