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

בדיקת טיפוסים בזמן ריצה ב-C++


MiniMizer

Recommended Posts

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

בקצרה, הסיפור הוא כזה:

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

יצויין גם כי כל הכלים במפעל יורשים מאובייקט משותף בשם Dish.

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

עכשיו, אני מכיר שתי דרכים לעשות את זה:

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

ב) לממש אופרטור השוואה בכל אחד מהבנים על ידי שימוש ב-dynamic_cast מתאים.

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

יש דרכים נוספות בהן אפשר להשוות בין טיפוסים בזמן ריצה? :-\

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

  • תגובות 45
  • נוצר
  • תגובה אחרונה

שתי הדרכים קצת הורסות את כל הקטע של פולימורפיזם. זו שאלה די טיפשית.

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

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

אתה כזה חמוד כשאתה נאיבי ;D לצערי יש כל מני מגבלות על התרגיל :-\

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

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

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

אובייקט מטיפוס type_info.

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

אגב, יש דרך קצת יותר יפה לעשות את פתרון א':

להגדיר ל-Dish פונקציה וירטואלית טהורה בשם getType שמחזירה String. כל אחד מסוגי המוצרים השונים יממש את getType בהתאם.

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

אגב, יש דרך קצת יותר יפה לעשות את פתרון א':

להגדיר ל-Dish פונקציה וירטואלית טהורה בשם getType שמחזירה String. כל אחד מסוגי המוצרים השונים יממש את getType בהתאם.

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

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

אובייקט מטיפוס type_info.

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

אגב, יש דרך קצת יותר יפה לעשות את פתרון א':

להגדיר ל-Dish פונקציה וירטואלית טהורה בשם getType שמחזירה String. כל אחד מסוגי המוצרים השונים יממש את getType בהתאם.

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

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

ואם רוצים בכל זאת לעשות עם ה DYNAMIC CAST איך אני יכול לבדוק איבר בוקטור אם הוא מאותו טיפוס של האיבר שאותו אני רוצה לבדוק?

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

TYPE* dynamic_cast<TYPE*> (object);

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

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

כמו שאמרנו כאן, יש לך שתי אפשרויות:

הראשונה היא להוסיף פריט מזהה לקלאס שלך (כמו פונקציית getType).

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

את הדרך השנייה אפשר לממש באמצעות dynamic_cast או באמצעות typeid.

אגב, אם אתה לא רוצה להשתמש ב-typeid אתה יכול לעשות משהו כזה:

class Dish {
virtual bool isSameType(Dish*) = 0;

}

ואז בכל קלאס שמממש את Dish לעשות משהו כזה:

class Plate : public Dish {
virtual bool isSameType(Dish* d) {
Plate* p = dynamic_cast<Plate*>(d);
return (p != null);
}
}

כמובן שאת המימוש הזה תצטרך לעשות לכל טיפוס שיורש מ-Dish. אופציה קצת יותר חסכונית היא לשלב ירושה ו-Templates.

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

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

ואז אני יכול למעשה לעשות לולאה כזאת?

for ( BoxIterator iterator = m_dishBoxes.begin(); iterator != m_dishBoxes.end(); iterator++ )
{

if ( iterator->isSameType( dish ) )
{
iterator->pushback(dish);
break;
}

}

תודה על ההסבר.

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

ארכיון

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


×
  • צור חדש...