5.2.5.5. Inline Virtual Function

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

מתי נוכל להשתמש ב-inline בשילוב עם virtual functions?

  • במקרה הבא לא נוכל להשתמש ב-inline – הפונקציה איננה ידועה בזמן ההידור.

void SomeClass :: some_function_member(void)

{

      some_virtual_function_member();

}



  • אם אנחנו מקבלים אובייקט (ולא מצביע או משתנה התייחסות לאובייקט), אנחנו יכולים להגדיר את הפונקציה המקבלת כ-inline:

void f(SomeClass a)

{

      a.some_virtual_function_member();

}

  • אם קוראים לפונקציה וירטואלית בצורה מפורשת (כך שברור איזה פונקציה תיקרא באופן מוחלט) אזי גם ניתן להשתמש ב-inline:

void f(SomeClass& a)

{

      a.SomeClass::some_virtual_function_member();

}

  • בתוך ctor ניתן לעשות inline לפונקציה וירטואלית בשפת C++. ב-C++, כאשר ה-ctor של מחלקה נגזרת מתחיל לעבוד הוא מתחיל ב-ctor של ההורים – הבניה בעצם מתחילה מה-ctor של מחלקת הבסיס, ולאחר מכן לפי עץ ההורשה של המחלקות בדרך. הנקודה החשובה היא שגם כשבונים מחלקה C שנורשת מ-B שיורשת מ-A, בתחילת הבניה המחלקה היא A. במהלך הבניה, vptr מתעדכן כל פעם ביחס למחלקה שה-ctor שייך לה. לפיכך קריאה לפונקציה וירטואלית בתוך ה-ctor אינה ממש dynamic-binding ולכן הקומפיילר יכול לדעת לאיזה מתודה מתכוונים בכל קריאה.

בשפת Java ניסו לפשט את המנגנון. הגישה ב-Java היא שראשית יוצרים את העצם כולו עם כל השדות שבו ומאתחלים אותם להיות 0. לאחר מכן מתחילים לבנות את האובייקט מהבסיס בדומה לשפת C++ ומעדכנים את השדות לפי הבנאים שבשרשרת ההורשה. כעת ניתן לקרוא למתודות לפי

ה-dynamic binding. הרעיון מאחורי גישה זו – הטיפוס הסופי של האובייקט נקבע עם יצירתו.



מאת: ניצן

Borland style vptr

לפי מה שאני מכיר:
"חסרון בגישה זו: גם כאשר איננו משתמשים ב-dynamic binding – אנחנו משלמים במקום"
לא נכון , עבור מחלקה A שאין לה מתודות דינמיות לא יווצר כלל המצביע, ולמשל עבור מחלקה B שיורשת מA פשוט נוסיף בהתחלה את המצביע, ואחרי הבלוק של A את שאר האינפורמציה של B . וככה לא משלמים על מה שלא משתמשים ועקרונות C++ נשמרים.
מה שכן באמת הcasting קצת יותר מסובך....
שיתוף:
| עוד