תעזרו לי עם זה בבקשה....

vbgames

New member
תעזרו לי עם זה בבקשה....

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

odstudio

New member
נו טופ...

מה שאתה רוצה לעשות נקרא Down-Cast, כלומר לבצע Casting מאב לבן. דבר זה, כמו שנראה לי שכבר גילית, נחשב לפעולה "מסוכנת". אך יש פתרון: דרך אחת היא, לנצל את תכונת RTTI של הקומפיילר (בהנחה שאתה משתמש ב- ++Visual C ושהקוד שלך לא אמור להיות "Cross-Platform". (קרא ב- MSDN על נושא RTTI - Run-Time-Type-Information). או-אז, בעזרת dynamic_cast תוכל לבצע בדיקת instance מסויים בכדי לדעת מאיזה סוג הוא. הדרך השנייה, היא לאתחל משתנה (המוגדר ב- block) בהתאם ל- class. תוכל לאתחל אותו ב- constructor של כל מחלקה היורשת מ- block, ובעת הצורך, תוכל לבדוק ערך משתנה זה דרך הפוינטר של block, ולדעת איזו מחלקה יורשת זו באמת. קצת מסורבל, אבל אין לך דרך אחרת לבצע Down-Cast בצורה בטוחה. דרך-אגב, אם אתה עובד עם MFC, אז כל אובייקט היורש מ- CObject כולל מידע על מקומו בהיררכיה ואפשר לבצע בדיקות ב- Run-Time לגבי instance של class מסויים בעזרת הפונקציונליות ש- CObject כולל. במקרה שאתה עובד עם MFC הייתי ממליץ על ירושת block מ- CObject. אם לא, תוכל לממש בעצמך מין "CObject" שכזה. בהצלחה!
 

vbgames

New member
תודה!! ../images/Emo13.gif

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

חובבן

New member
RTTI בדרך כלל סימן לטעות בתכנון

למה שלא תיצור מחלקת אב אבסטרקטית חדשה C, שכוללת את מה שמשותף ל A,B? כלל אצבע בתכנון ירושה: מחלקה שיורשים ממנה, היא אבסטרקטית - אסור שיהיו לה אוביקטים.
 

vbgames

New member
למעשה

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

חובבן

New member
הרשימה תהיה של מצביעים ל C

כמו שכבר ציון פה, זה מזכיר את בעית הריבוע והמלבן. מה יקרה שתרצה להוסיף ל A פונקצונליות שלא שייכת ל B? איך תעשה זאת?
 

vbgames

New member
אוקיי..נניח שהרשימה

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

חובבן

New member
אני מתנצל, לא הבנתי עד הסוף

בדרך כלל לכל העצמים ברשימה יש קבוצה של פונקציות שמופעלות על כל האיברים ברשימה. אחרת אולי כדאי להחזיק שתי רשימות נפרדות? אם אין ברירה ניתן להפעיל RTTI בצורה דומה לזאת:
Derived derived; Base* pBase = &derived; // the base pointer points to a derived // object. Legal, but confusing. Derived* pDerived = dynamic_cast<Derived*>(pBase); // because pBase is actually a pointer t // o a Derived at runtime, the // cast succeeds and pDerived is assigne // d the value of pBase if (pDerived) pDerived->DoSomething();​
בהצלחה
 

odstudio

New member
מאיפה הבאת את זה?

באמת אשמח לשמוע מאיפה הבאת את כל ה´כללים´ ו´חוקי האצבע´ האלה...
 

חובבן

New member
מהקורסים ומהחיים:

בעיקר קורס OOP וקורס Design. אני מודה שעברו מספר שנים מאז סיימתי את לימודי, אבל העקרונות נשארים...
 

odstudio

New member
מי זה חיים?

אותי הנסיון לימד, שבתכנות דווקא אין ´כללי אצבע´... בכל מקרה, העובדות מדברות עצמן - אין לאף אחד פתרון טוב יותר מזה שהצעתי. האם ביצוע Down-Cast מעיד על Design לקוי? האם מחלקות שיורשים מהן ´חייבות´ להיות אבסטרקטיות? ובכן, אם בחרת להשתמש ב- OOP על כל תכונותיו, התשובות לשתי השאלות הללו היא - לא!
 
../images/Emo13.gif

"אין לאף אחד פתרון טוב יותר מזה שהצעתי" קצת יומרני לא? סה"כ הצעת פיתרון, שבתמונה הכוללת יצור הרבה מקומות בקוד, שבהם יהיו SWITCH CASES אדירים, שבודקים את סוג האובייקט. וזה *כן* מעיד על DESIGN לקוי. מה יקרה אם מחר יהיה אובייקט חדש, או פעולה חדשה שהאובייקטים יודעים לבצע? לפעמים כן שווה לאמץ כמה עקרונות מקורסים (לאו דווקא זה שהוזכר כאן), לדוגמא עקרון ה-OCP - open/closed principle הותיק והטוב. ולכן, לדעתי, יש אלטרנטיבה הרבה יותר בריאה ממה שהצעת, הדואגת שהקוד יהיה גמיש באותה מידה שהוא מהיר. ואת זה כבר פירטתי בהודעה אחרת בשרשור הזה.
 

חובבן

New member
יש הרבה יותר מ 10 אצבעות ...

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

odstudio

New member
כללים לכלים...

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

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

vbgames

New member
אוקיי אני ינסה להסביר ותן את עצתך

קודם כל את הרשימה אני בטוח שאני צריך, אני מתכנן להוסיף ולהסיר אובייקטים בזמן ריצה. יש לי שתי סוגים של אובייקטים שאת כולם אני צריך לצייר על המסך, עבור כולם אני צריך לשמור את המיקום, ויש עוד איזה 2-3 פונקציות משותפות... חלק מהאובייקטים יותר מתקדמים הם מסוגלים גם לזוז על גבי המסך, לבדוק התנגשות עם אובייקטים אחרים, לתקוף, ועוד. אז בעקרון מה שעשיתי הוא לאפשר לרשימה להכיל אובייקטים משני הסוגים המתקדם פחות והמתקדם יותר, אבל בשביל שאני אוכל לרוץ על הרשימה ולהפעיל את הפונקציות הייתי צריך להכיל בפולימורפיזם את כל הפונקציות, גם את התזוזה התקיפה וכו´ למרות שחלק מהאובייקטים לא מסוגלים לעשות את זה. לפי קריאה מרופרפת על הRTTI אני מבין שאוכל להמיר את הפוינטר לאובייקט הבסיס לפוינטר לאובייקט האמיתי שהוא מצביע עליו וכך לא יהיה צריך בכלל להשתמש בפולימורפיזם. האם הבנתי נכון? בכל מקרה אני יודע שאני יכול להגדיר שתי אובייקטים של רשימות מקושרות שכל אחת מהם תוכל להכיל רק אובייקט מסוג אחד, ואז שוב לא יהיה צורך בפולימורפיזם. אבל זה נראה לי הרבה פחות הגיוני לעשות. אם יש לך הצעות אחרות למימוש אשמח לשמוע
 
הממממ...

מכיר STATE PATTERN? יש לי רעיון מסויים. מכיוון שאני לא מבין לגמרי את הצרכים שלך מכל אובייקט, קח את מה שאני אומר בחשבון אבל בע"מ
בגדול הבנתי שמדובר במשחק מרובה "משתתפים", עם אופי פיסיקלי, סטייל סימולציה או משהו כזה. יש לי קצת נסיון בכיוון הזה... הבה נפריד את הפעולות הפיסיות מהפעולות הלוגיות. לדוגמה: התקפה היא פעולה לוגית. מעין STATE OF MIND. אך תזוזה היא פעולה פיסית. פעולת התקפה אולי יכולה לגרום לתזוזה מסויימת ואולי לא. לכן אני עושה את ההפרדה הזו. אופציה אחת שחשבתי עליה: א. צור יישות אבסטרקטית STATE, ומתחתיה צור יישויות עבור תקיפה, תזוזה וכו´. מתחת להן יהיו CLASSES עבור כל יישום של פעולה שקיים. לדוגמה: MONSTERATTACK או HUMANMOVE או LONGRANGEATTACK או כל חלוקה שתחליט. כל STATE כזה מחזיק את המאפיינים שלו ואת האובייקט שאליו הוא משוייך. כל STATE יכול לעדכן את עצמו ע"י מתודת UPDATE. לדוגמה, HUMANMOVE->Update ישנה את מיקום האובייקט, יקדם את מספר ה-FRAME באנימציה של ההליכה, וכו´. ב. צור יישות אבסטרקטית OBJECT ומתחתיה עצמים שונים. כאשר כל עצם מכיר STATES מסויימים ומסוגל לעבור ביניהם עם המתודה:
SETSTATE(state)​
כמו כן, כל עצם יוכל לעדכן את המצבים של עצמו ע"י המתודה UPDATE. לכל עצם ב-CTOR יהיה אתחול רשימה פרטית של STATE ID´S, המיישמים את כל הפעולות שהוא אמור לדעת לעשות. אפשר לעשות שהרשימה תהיה משותפת לכל העצמים מסוג מסויים אם עושים אותה STATIC. יש לזה חסרונות, אבל צריך לבדוק מה מתאים לאפליקציה שלך. בנוסף, תהיה רשימה של STATE OBJECTS פרטית לכל אובייקט (לא סטאטית, כי אם אובייקט א´ תוקף *כרגע*, זה לא אומר שכולם תוקפים כרגע). השימוש: ========= כאשר במהלך הסימולציה, ישנה התנגשות או תזוזה או החלטה לבצע התקפה, פשוט גש למיקומים הרלוונטים ברשימה וקרא לפונקציה SETSTATE עם הפרמטר המתאים. בלי שום קשר, באופן קבוע, כל FRAME, עליך לקרוא לפונקציה UPDATE של כל אובייקט, כדי שכולם יעדכנו את עצמם בהתאם למצב/ים שבו/בהם הם נמצאים. ה-UPDATE הזה למעשה יקרא ל-UPDATE של כל STATE OBJECT שהעצם הזה מחזיק. דוגמה: ========= אדם נמצא ב-2 STATES: הולך וממצמץ. שאר המצבים שלו לא פעילים כרגע. מכיוון שיש יישום ספציפי של מצמוץ ושל הליכה לבני אדם, הרי שבכל קריאה של UPDATE, יתבצע עדכון של המצבים של ההליכה והמצמוץ לאותו אדם. אם אתה מחליט להעביר את האדם למצב של JUMP, הפעל את SetState עם פרמטר jump, ואם צריך, אז ביישום של SetState עבור האובייקט מסוג Human, וודא ש-jump יכבה אוטומאטית את המצב walk. וזאת, כי לפעמים יש מצבים שלא הולכים ביחד. סביר להניח שפעולות לוגיות ופיסיות הולכות ביחד, אבל לוגיות-עם-לוגיות או פיסיות-עם-פיסיות מכילות כל מיני מגבלות. בהצלחה!
 

vbgames

New member
אוקיי

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

קודם כל, יש לך הרבה עבודה לפניך. אני לא אסבן אותך
אבל זו ההזדמנות שלך לשמוע כמה מילים שיובילו אותך בכיוון הנכון: בכל דרך שלא תבחר, אל תשכח שאתה עלול יום אחד להתבאס מלכתוב הכל "מחדש" רק כי יש דרך שנראית לך יותר טובה. רוב הסיכויים הם, שאם יצא מזה משהו, אתה תמשיך עם הקוד שקיים, ולא תכתוב מחדש. במילים אחרות, במציאות, לא משתלם לעשות עיצוב מחדש של תוכנה על כל חלקיה (רק לתתי חלקים - מה שנקרא פיתוח איטראטיבי/מחזורי). כאשר אתה מעצב תוכנה, אתה חייב להסתכל קדימה ולשאול את עצמך שאלה פשוטה: מכל החלקים של התוכנה שלי, מה סביר להניח שיורחב בצורה הכי משמעותית? לדוגמה, במקרה שלך: אולי יתווספו/יוסרו עוד סוגי עצמים, או עוד סוגי פעולות שעצמים יודעים לבצע, וכו´. את העיצוב שלך אתה תדאג "להגמיש" במקומות האלה, כדי שיותר מאוחר לא תיאלץ לעשות שינויים נרחבים בקוד. זה הגיון פשוט, אבל לפעמים קשה ליישום.... אל תדאג, ההחלטה הזו תבוא לך באופן טבעי עם הזמן. אני לדוגמה, ישר מתאר לעצמי שתרצה מאוחר יותר להוסיף את הדברים הבאים, בסדר סבירות יורד: 1. עוד עצמים 2. עוד STATES ועוד יחסים בין ה-STATES השונים 3. להחליף משמעות של STATE למשהו אחר. בקיצור, זו הסיבה שאני לא תומך בשימוש ב-RTTI או בכל דבר שיגרום לך לשאול בקוד "אם זה עצם מסוג א´ אז.... אם זה עצם מסוג ב´ אז....", כי זה יסרבל את הקוד כאשר תוסיף עוד סוגי עצמים ופעולות. ומכיוון שאני די בטוח בתחזית שלי, אז הצעתי לך שיטה, שדואגת, שכל אובייקט חדש שתוסיף, לא יצריך שינויים בקוד הקיים. וזהו עיקרון ה-OCP המפורסם שהזכרתי כבר... אז שוב בהצלחה! אז שוב בהצלחה, ואני מאוד ממליץ על הספר:
Design Patterns Elements of Reusable Object-Oriented Software by Erich Gamma, Richard Helm, Ralph Johnson, John Vlisiddes ISBN 0-201-63361-2 Adison Wesley Pub.​
שמו בקיצור: GOF - Gang of Four ע"ש 4 סופריו.... דוגמה מצויינת לשיתוף פעולה בינלאומי (הכותבים הם משוייץ, אוסטרליה, ניו יורק ואילינוי) שבסופו יוצא ספר מאוד פרקטי. הדבר הכי חשוב אולי שתלמד בספר, הוא להיות יצירתי. בהצלחה!
 
למעלה