דף הבית >> פונקציות וירטואליות ופולימורפיזם>>פונקציות וירטואליות

פרק 4

פונקציות וירטואליות ופולימורפיזם

פולימורפיזם נתמך ע"י ++c גם בזמן הקימפול וגם בזמן ריצה ,פולימורפיזם בזמן קימפול מושג ע"י העמסת פונקציות ואופרטורים. פולימורפיזם בזמן ריצה מושג ע"י הורשה ופונקציות וירטואליות ,אלה יהיו הנקודות בפרק זה

 

פונקציות וירטואליות

 

פונקציה וירטואלית היא פונקציה חברה אשר מוצהרת בתוך מחלקת בסיס ומוגדרת מחדש ע"י המחלקה הנגזרת. בכדי ליצור פונקציה וירטואלית , לפני הצהרת הפונקציות במחלקת הבסיס יש לרשום virtual. מתי שמחלקה מכילה פונקציה וירטואלית ,בהורשה המחלקה הנגזרת מגדירה מחדש את הפונקציה הוירטואלית ומתאימה אותה לצרכיה .בתמצית ,פונקציה וירטואלית מישמת פילוסופית "ממשק אחד ,מספר שיטות" אשר מונח ביסוד הפולימורפיזם.הפונקציה הורטואלית בתוך מחלקת הבסיס מגדירה את הצורה של המימשק לאותה פונקציה .כל הגדרה מחדש של הפונקציה הוירטואלית במחלקה הנגזרת מיישם את הפעולה אשר קרובה ספציפית למחלקה הנגזרת . זאת אומרת שההגדרה מחדש יוצרת שיטה ספציפית.הגישה היא רגילה לפונקציה וירטואלית ,היא מתנהגת כמו שאר הפונקציות במחלקה .בכל מקרה מה עושה את הפונקציה הוירטואלית לחשובה ויכולת לתמיכה בפולימורפיזם בזמן ריצה ,זה כיצד היא מתנהגת באמצעות פויינטר.כפי שאנו יודעים פויינטר של מחלקת בסיס יכול להצביע על אובייקט מכל מחלקה נגזרת ממחלקת בסיס זה.מתי שפויינטר ממחלקת בסיס מצביע לאובייקט ממחלקה נגזרת אשר מכילה פונקציה וירטואלית ,++c מחליטה איזו גירסה של פונקציה נקראת בהתבסס על סוג האובייקט המוצבע ע"י הפויינטר. והחלטה זו נעשית בזמן ריצה. לכן כאשר אובייקטים שונים מצביעים ל,גירסאות שונות של פונקציות וירטואליות יוצאות לפועל. בהתייחסות למחלקת בסיס יש את אותה ההשפעה. בכדי להתחיל נבחן את הדוגמה הקצרה:

 

#include <iostream.h>

class base {
public:
       virtual void vfunc ( ) {
           cout << "this is base's vfunc ( ) . \n " ;
       }
};

class derived1 : public base {
public:
       void vfunc ( ) {   
           cout << "this is derived1's vfunc ( ) .\n ";
       }
};

class derived2 : public base {
public :
       void vfunc ( ) {
           cout << "this derivd2's vfunc ( ) . \n";
       }
};

int main  ( ) 
{
       base *p ,b ;
       derived1 d1;
       derived2 d2;
//point to base 
       p = &b;
       p->vfunc ( ) ; //access base's vfunc ()
//point to derived1
       p = &d1; 
       p->vfunc ( ); //access derived1's vfunc ( )
//point to derived2 
       p = &d2;
       p->vfunc ( );//access derived2's vfunc ( )
       return 0 ;
}


התוכנית תציג את המשפטים הבאים :

 this is base's vfunc ( ).

 this is derived1's vfunc ( ).
 
 his is derived2's vfunc ( ).

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

בתוכנית זו, הבסיס (base) מורש לנגזרת 1 (derived1) ולנגזרת 2 (derived2) .בתוך כל אחת מהמחלקות הפונקציה ( ) vfunc מוגדרת מחדש בהתאם למחלקה .בתוך ה ( )main ,ארבעה משתנים מוצהרים.

 

שם סוג
p פויינטר מחלקת בסיס
b אובייקט של בסיס
d1 אובייקט של נגזרת 1
d2 אובייקט של נגזרת 2

 

בהמשך p מוקצה לכתובת של b,והפונקציה ( ) vfunc נקראת באמצעות p .מכווןש p מצביע על אובייקט מסוג בסיס , גירסה זו של vfunc מתבצעת. בהמשך p מכוון לכתובת אובייקט מסוג נגזרת 1 ושוב הפונקציה vfunc נקראת ע"ישימוש ב p . בפעם הזאת p מצביע לאובייקט מסוג נגזרת 1.זה גורם ל derived1:: vfunc להתבצע.לבסוף ,p מצורף לכתובת של d2 , ו ( )p-> vfunc גורם לגירסה של vfunc להיות מוגדרת מחדש בתוך נגזרת 2 ,ולהתבצע.נקודת המפתח כאן שסוג באובייקט ש p מצביע אליו קובע איזו גירסה של vfunc תתבצע.צורת תהליך זו היא הבסיס לפולימורפיזם בזמן ריצה ,למרות שאתה יכול לקרוא לפונקציה וירטואלית בצורה "הרגילה " ע"י שימוש בשם אובייקט ובאופרטור נקודה,וזה רק מתי שהגישה היא דרך פויינטר של מחלקת בסיס (או התייחסות) שפולימורפיזם בזמן ריצה מושג.לדוגמה , נניח קודם את הדוגמה שתקפה מבחינה תחבירית.

 

d2 . vfunc ( ) ; //calls derived2's vfunc ( )

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

הקודם
הבא