זיהוי מחלקות.

mooznach

New member
זיהוי מחלקות.

doing this in hebrew will be too hard. say I have a template function. in that function I want to check if the type I got inherits a certain class (class Base, for example). is it possible to do at runtime? example code -
class Base { virtual void doSomething() = 0; }; class X : public Base { void doSomething() { std::cout << "Something" << std::endl; } class Y { }; template<typename T> void test(const T &t) { //if(t inherits Base) then // t.doSomething } int main() { X x; Y y; test(x); test(y); return 0; }​
 

mooznach

New member
הקוד לא אמור להתקמפל.

סתם משהו שכתבתי עכשיו בשביל להדגים.
 
יש כמה דרכים

אבל אני מניח שאתה מחפש דרך שתתבצע בזמן קומפילציה, נכון? בספר More Effective C++ יש תיאור של דרך מוצלחת לעשות זאת. באופן כללי, אתה שם "מכשול" לקומפיילר בכל צורה שבא לך. הדוגמה הכי פשוטה: הגדר ב-BASE מתודה שנקראת משהו כמו I_AM_BASE. עדיף שהיא תהיה INLINE ולא תעשה שום דבר מיוחד - אפילו כלום...מתוך ה-TEMPLATE FUNCTION, קרא למתודה הזו. מן הסתם, אם האובייקט שהעברת לא נגזר מ-BASE, הקומפיילר יזרוק הודעת שגיאה. דרך נוספת היא, בעזרת RTTI, לדאוג שהמתודה הנ"ל תחזיר את ה-TYPEID של *האב* ולא של המחלקה עצמה (שם לב: היא תחזיר את ה-TYPEID ולא את השם של המחלקה). במילים אחרות: יש ליישם מתודה ורטואלית WHO_AM_I בכל המחלקות, לפי הכלל הבא: אם המחלקה היא נגזרת, אז היא תחזיר את WHO_AMO_I של ההורה שלה (או אפילו ישירות של האב הקדמון שלה). אחרת, היא אב קדמון ולכן תחזיר את ה-TYPEID של עצמה. הפתרון השני הוא "חצי" בזמן קומפילציה, כי כל המחלקות שלא מיישמות WHO_AM_I לא יעברו קומפילציה. אבל בוודאות, גם אם מחלקה "תתחזה" ע"י יישום של מתודה כזו, היא לא יכולה להחזיר TYPEID של מחלקה הנגזרת מ-BASE.
 

mooznach

New member
תגובה

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

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

הנה פתרון בזמן ריצה, בלי RTTI: מצביע ל-BASE יכול לקבל כתובות של אובייקטים הנגזרים מ-BASE, נכון? נניח ותגדיר 2 פונקציות שנראות כך:
bool IsBase(base* b) { return true; } bool IsBase(...) { return false; }​
אז ברור לך, שאם תקרא מתוך פונקציית ה-TEMPLATE שלך ל-IsConvertable, היא תחזיר TRUE רק אם ישנה המרה מ-B ל-BASE. זה לא עמיד בפני התחזות ב-100%, כי יכול להיות שמישהו יגדיר CONVERSION ממחלקה X ל-BASE באופן מפורש. אבל זה הדבר הכי קרוב שאני מצליח לחשוב עליו כרגע. אבל אין אף שיטה שהינה ב-100% עמידה בפני התחזויות - לא בזמן ריצה ולא בזמן קומפילציה. הערה: היתה הצעה להכניס לסטנדרט של C++ את האופרטור TYPEOF אבל אין אותו כרגע....
 

mooznach

New member
תודה.

אני ניסיתי לעשות את זה עם Template Specialization. לא חשבתי על שימוש ב"...". (ellipses?).
 
ההבדל הדק...

הסטנדרט קובע ש-TEMPLATES עושים אך ורק EXACT MATCHING לארגומטים שלהם, ולכן SPECIALIZATION היה דורש ממך לעשות INSTANCE עבור כל מחלקה תחת BASE (כולל BASE). סיוט, סיוט, סיוט...
 

eyalbd

New member
אם אתה רוצה Base כפרמטר

ואתה רוצה את זה בזמן קומפילציה אז אתה לא צריך template בכלל ! פונקציה כזאת תעשה את העבודה יותר טוב מכל template עם compile-time assertion
void test(/*const*/ Base& b) { b.doSomething(); }​
שמתי את הconst בהערה משום ש doSomethig היא לא const
 

אלדד28

New member
זה תלוי מה הוא רוצה לעשות בדיוק,

ואת זה הוא לא ציין. מה אם אתה רוצה לעשות בפונקציה משהו אחד אם זה BASE ומשהו אחר אם זה BASE2?
 

eyalbd

New member
לא בשביל זה יש templates

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

הן באותה שבלונה? לא חבל לכתוב אותן פעמיים - פעם עבור BASE ופעם עבור BASE2?
 

gilad_no

New member
הגישה שלך לא נכונה

TEMPLATES זה לשימוש בזמן קומפילציה. VIRTUAL FUNCTIONS זה לשימוש בזמן ריצה. אם אתה רוצה לבדוק את זה בזמן ריצה, אין לך מה להשתמש בטמפלטים, ותצטרך לבצע RTTI או DYNAMIC_CAST. אם אתה רוצה לבדוק בזמן הידור, תשתמש בSTATIC_CAST. לא מזמן פירטתי כאן את ההבדלים השונים, תבצע חיפוש ...
 
כל השיטות כשרות

ואפשר גם ללא RTTI כמו שכבר ציינתי. בכל מקרה, אין אף שיטה שמאפשרת לך למנוע התחזויות. רק אם היה אופרטור TYPEOF, היה אפשר למנוע התחזויות בזמן קומפילציה, וגם זאת בתנאי ש-TYPEOF לא היה בודק קיום של EXPLICIT CONVERSIONS שאולי הוסיף המתכנת.
 
למעלה