עבור לתוכן
View in the app

A better way to browse. Learn more.

HWzone

A full-screen app on your home screen with push notifications, badges and more.

To install this app on iOS and iPadOS
  1. Tap the Share icon in Safari
  2. Scroll the menu and tap Add to Home Screen.
  3. Tap Add in the top-right corner.
To install this app on Android
  1. Tap the 3-dot menu (⋮) in the top-right corner of the browser.
  2. Tap Add to Home screen or Install app.
  3. Confirm by tapping Install.

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

Featured Replies

פורסם

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

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

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

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

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

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

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

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

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

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

  • תגובות 45
  • צפיות 6.2k
  • נוצר
  • תגובה אחרונה
פורסם

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

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

פורסם
  • מחבר

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

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

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

פורסם

אז אין באמת דרך אחרת.

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

פורסם
  • מחבר

איך עושים את זה בשפות אחרות?

אין איזו פונקציה פשוטה שיכולה לעשות את זה? :\

פורסם
  • מחבר

אז אני יכול בעצם להשתמש ב-typeid, לא?

חוץ מזה שלא ממש הבנתי מה היא מחזירה..

פורסם

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

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

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

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

פורסם
  • מחבר

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

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

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

פורסם

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

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

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

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

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

פורסם

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

http://en.wikipedia.org/wiki/Double_dispatch

פורסם

ואם רוצים בכל זאת לעשות עם ה 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;
}

}

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

פורסם

מה הטיפוס של m_dishBoxes? אם זה וקטור של וקטורים, אז אתה לא יכול, כי לוקטור אין פונקציה בשם isSameType.

ארכיון

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

דיונים חדשים

Configure browser push notifications

Chrome (Android)
  1. Tap the lock icon next to the address bar.
  2. Tap Permissions → Notifications.
  3. Adjust your preference.
Chrome (Desktop)
  1. Click the padlock icon in the address bar.
  2. Select Site settings.
  3. Find Notifications and adjust your preference.