ירושה מרובה ב C++ - צורה בעייתית במיוחד. - תכנות - HWzone פורומים
עבור לתוכן
  • צור חשבון

ירושה מרובה ב C++ - צורה בעייתית במיוחד.


Kidney_stonE

Recommended Posts

שלום,

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

אני מנסה ליצור ירושה מרובה בצורה כזו:

videocastso6.th.jpg

אני מדבר על מה שסימנתי בכחול - על VideoPodcast

כמו שמתואר ב UML לעיל, הוא צריך לרשת משני מקומות-

מ- Podcast (שבעצמו יורש מ AudioMediaItem שיורש מ MediaItem)

ומ- VideoMediaItem (שיורש גם הוא, מ MediaItem)

בפועל כנראה מתרחש משהו ממש גרוע, כי אני מקבל שגיאה ב runtime שאומרת משהו לא ברור לגבי invalid null pointer

runtimebf0.th.jpg

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

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

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

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

אני יורש את המחלקות הרלוונטיות כך:

class AudioMediaItem: virtual public MediaItem {....} // (MediaItem is an Abstract Base Class)

class VideoMediaItem: virtual public MediaItem {....} // (MediaItem is an Abstract Base Class)

class Podcast: virtual public AudioMediaItem {....}

הקלאס ה"בעייתי" יורש 2 מחלקות, ניסיתי כך:

class VideoPodcast: public Podcast, public VideoMediaItem {....}

וגם כך:

class VideoPodcast: virtual public Podcast, virtual public VideoMediaItem {....}

אבל בשני המקרים שגיאת ה runtime נראית זהה לחלוטין.

מישהו יכול לכוון אותי ולומר לי איפה בדיוק אני טועה?

אני יכול להעלות את הקוד כולו אם יש צורך ב ZIP.

(קוד לא הכי גדול ומסובך בעולם למען האמת, הוא די קטן ומובן, אבל בכל זאת 19 קבצים...)

קישור לתוכן
שתף באתרים אחרים

האם אתה מצליח ליצור אובייקט מסוג Podcast?

הדבר הראשון שקפץ לי לעין הוא הירושה הוירטואלית הבאה:

class Podcast: virtual public AudioMediaItem {....}

האם היא באמת חייבת להיות וירטואלית פה? הרי AudioMediaItem נכנס רק פעם אחת ב-VideoPodCast.

קישור לתוכן
שתף באתרים אחרים

המלצות כלליות:

1) כשמשתמשים ב-MI כדאי מאוד (אפילו יותר מבד"כ) שכל המחלקות שיורשים מהם יהיו אבסטרקיטות כמה שיותר - ללא data members אם אפשר, במיוחד מעל המחלקה התחתונה שבה הירושה מתחברת.

2) http://www.parashift.com/c++-faq-lite/multiple-inheritance.html#faq-25.9

3) האם זכרת להשתמש ב-<>dynamic_cast ולא ב-(C-Style-cast)?

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

קישור לתוכן
שתף באתרים אחרים

טוב, קודם כל המון תודה על הסבלנות

התשובות:

האם אתה מצליח ליצור אובייקט מסוג Podcast? כן, אני מצליח ליצור את כל האובייקטים מלבד VideoPodCast

הדבר הראשון שקפץ לי לעין הוא הירושה הוירטואלית הבאה:

class Podcast: virtual public AudioMediaItem {....}

האם היא באמת חייבת להיות וירטואלית פה? הרי AudioMediaItem נכנס רק פעם אחת ב-VideoPodCast.

לפי מה שאני מבין מסעיף 2 של Zelig, אז כן, היא חייבת להיות וירטואלית שכן היא בבסיס ה"היהלום" הלא סימטרי שלי.

-Zelig

1. דווקא במקרה הזה, ה ABS (מדיה אייטם) מכיל את רוב המתודות (מכיוון שרובן זהות לרוב האובייקטים מהקלאסים היורשים),

AudioMediaItem ריק לחלוטין , ו VideoMediaItem מכיל רק 4-5 משתנים ומתודות נוספות.

הכל נובע מהגבלות בתיאור הפרוייקט,

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

3. כנראה שפיספסתי את ההרצאה שדיברנו על זה בה באונ'

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

אולי אני פשוט עייף כבר וזה לא קופץ לי לעין...

אם זה היה ambiguity, לא הייתה מתקבלת שגיאה בזמן הידור?

כלומר זה מה שקורה בפועל אם אני לא משתמש ב virtual בהורשה - אז יש שגיאה בזמן הידור לגבי ambiguity

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

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

mandarin, אני משתמש ב C++ כי זה מה שאני לומד, וזה תרגיל הבית האחרון שקיבלנו.

לא העליתי את הקוד קודם לכן כי בכל זאת מדובר ב 19 קבצים, וקשה לבקש ממישהו "להעיף מבט"

בדבר הזה, אבל לצורך העניין - העליתי את הקוד להודעה הנוכחית, בקובץ zip.

ה main שבתוך ה zip שהעליתי מלא ב comments מסביב לכל מה שקשור ל VideoPodcast

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

אם תורידו את ה comments שיש ב main (מספיק להוריד את ה comments משני השורות הראשונות שבונות את האובייקט m6)

ותנסו לבנות מחדש ולהריץ - תתקבל השגיאה.

אם יש צורך - אז כאן יש main זהה ללא comments:

http://cs.haifa.ac.il/courses/prog_tech/2008/homework/hw3/main.cpp

וזה הפלט המצופה:

http://cs.haifa.ac.il/courses/prog_tech/2008/homework/hw3/output.txt

את תיאור הפרוייקט אפשר לקרוא כאן:

http://cs.haifa.ac.il/courses/prog_tech/2008/homework/hw3/oop2008hw3.pdf

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

(ובכל מקרה ה-deadline להגשה הזו היה אתמול ופיספסתי אותו כי התחלתי את הפרוייקט מאוחר)

ושוב, תודה רבה לכולם.

[attachment deleted by admin]

קישור לתוכן
שתף באתרים אחרים

קימפלתי את הקוד שהבאת ב G++ והוא רץ בלי בעיה. מה שכאן הוא זרק אזהרות שיכול להיות קשורות לבעיה:


In file included from VideoPodcast.cpp:1:
VideoPodcast.h: In constructor גVideoPodcast::VideoPodcast(std::string, std::string, std::string, int, std::string, long int, int, int, int)ג:
VideoPodcast.h:16: warning: base גVideoMediaItemג will be initialized after
VideoPodcast.h:16: warning: base גPodcastג
VideoPodcast.h:16: warning: when initialized here
In file included from main.cpp:5:
VideoPodcast.h: In constructor גVideoPodcast::VideoPodcast(std::string, std::string, std::string, int, std::string, long int, int, int, int)ג:
VideoPodcast.h:16: warning: base גVideoMediaItemג will be initialized after
VideoPodcast.h:16: warning: base גPodcastג
VideoPodcast.h:16: warning: when initialized here

קישור לתוכן
שתף באתרים אחרים

קימפלת עם המיין כמו שצירפתי אותו, או שהסרת את הקומנטים?

ה main שבתוך ה zip שהעליתי מלא ב comments מסביב לכל מה שקשור ל VideoPodcast

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

אם תורידו את ה comments שיש ב main (מספיק להוריד את ה comments משני השורות הראשונות שבונות את האובייקט m6)

ותנסו לבנות מחדש ולהריץ - תתקבל השגיאה.

קישור לתוכן
שתף באתרים אחרים

אוקי, משהו מאוד מוזר מתרחש כאן

- קודם כל המון תודה! (אתה לא מבין כמה שברתי את הראש על זה, איך עלית על זה בכ"כ מעט זמן?)

זה באמת מה שפתר את הבעיה של שגיאת ה runtime ההיא.

מה שקורה עכשיו

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

(כלומר לכולם ה title הוא "" וה- duration הוא 0...

וזאת למרות שב- main אני מאתחל אותם בערכים אחרים, שאמורים לעבור דרך רשימת האתחול של מחלקת האב ולשכתב את ערכי ברירת המחדל)

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

ומבטל את היצירה של האובייקט ההוא (m6) ב main (כדי שהשגיאה לא תתרחש באמת)

עדיין מתרחש אותו דבר - ערכי ברירת מחדל של "אין כותרת" ו"אפס זמן"

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

אני מנסה לבדוק מה בדיוק גורם לזה, אשמח לרעיונות.

קישור לתוכן
שתף באתרים אחרים

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

למשל Movie שיורש מ VideoMediaItem שיורש מ MediaItem

הנה הקונסטרקטור שלו:

Movie(string title, string director, string leadActor, int release_year, long duration, 
int resX, int resY, int bright):VideoMediaItem(title,duration,resX,resY,bright),
director(director),leadActor(leadActor),release_year(release_year){}

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

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

יש לי הרגשה שאני עובד כאן לא נכון...

קישור לתוכן
שתף באתרים אחרים

פשוט מאוד, ב G++ 4 הוא זורק שגיאה נורמלית שאומרת שאתה מנסה להציב NULL בתוך אתחול של string אז חיפשתי איפה זה קורה. לגבי הבעיה השניה, זה בגלל שאתה יורש virtual ממחלקות, מה שאומר שהם יאותחלו לפני האבא שלהם ולכן ה TITLE לא עובר (כשאתה יוצר מופע של AudioMediaItem הוא יאתחל קודם את ה MediaItem כי הוא וירטואלי, ואז הוא כבר יציב את הערך הדיפולטי).

קישור לתוכן
שתף באתרים אחרים

ארכיון

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

×
  • צור חדש...