פונקציית התקשרות חוזרת ב- C ++

Callback Function C



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

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







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



תוכן המאמר

תכנית בסיסית לתפקוד החזרה

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



#לִכלוֹל

באמצעות מרחב שמותשעה (ות;



intmainFn(לְהַשְׁחִירצ'[],int (*ptr)(int))

{

intid1= 1;

intid2= 2;

intבְּדֶרֶך כְּלַל= (*ptr)(id2);

עֲלוּת<<'תפקיד עיקרי:'<<id1<<''<<צ'<<''<<בְּדֶרֶך כְּלַל<<' n';

לַחֲזוֹרid1;

}


intcb(intאידן)

{

עֲלוּת<<'פונקציית התקשרות חוזרת'<<' n';

לַחֲזוֹראידן;

}


intרָאשִׁי()

{

int (*ptr)(int) = &cb;

לְהַשְׁחִירלא[] = 'ו';

mainFn(אבא, cb);



לַחֲזוֹר 0;

}

הפלט הוא:





פונקציית התקשרות חוזרת

תפקיד עיקרי: 1 ו 2

הפונקציה העיקרית מזוהה על ידי principalFn (). פונקציית החזרה חוזרת מזוהה על ידי cb (). פונקציית ה- callback מוגדרת מחוץ לפונקציה הראשית אך נקראת למעשה בתוך הפונקציה העיקרית.

שים לב להצהרת פונקציית החזרה כפרמטר ברשימת הפרמטרים של הצהרת הפונקציה העיקרית. ההצהרה על פונקציית החזרה היא int (*ptr) (int). שימו לב לביטוי פונקציית החזרה, כמו קריאת פונקציה, בהגדרת הפונקציה העיקרית; כל טיעון לשיחת פונקציית החזרה מועבר לשם. המשפט עבור קריאת פונקציה זו הוא:



intבְּדֶרֶך כְּלַל= (*ptr)(id2);

כאשר id2 הוא טיעון. ptr הוא חלק מהפרמטר, מצביע, שיקושר להפניה של פונקציית החזרה בפונקציה הראשית ().

שימו לב לביטוי:

int (*ptr)(int) = &cb;

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

הפונקציה העיקרית נקראת בפונקציה הראשית () כ:

mainFn(אבא, cb);

כאשר cha הוא מחרוזת ו- cb הוא שם הפונקציה החזרה ללא כל טיעון שלה.

התנהגות סינכרונית של פונקציית החזרה

שקול את התוכנית הבאה:

#לִכלוֹל

באמצעות מרחב שמותשעה (ות;



בָּטֵלmainFn(בָּטֵל (*ptr)())

{

עֲלוּת<<'תפקיד עיקרי'<<' n';

(*ptr)();

}


בָּטֵלcb()

{

עֲלוּת<<'פונקציית התקשרות חוזרת'<<' n';

}


בָּטֵלfn()

{

עֲלוּת<<'נראה'<<' n';

}


intרָאשִׁי()

{

בָּטֵל (*ptr)() = &cb;

mainFn(cb);

fn();



לַחֲזוֹר 0;

}

הפלט הוא:

תפקיד עיקרי

פונקציית התקשרות חוזרת

נראה

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

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

ובכן, הפונקציה, fn () יכולה להיקרא מתוך ההגדרה של הפונקציה העיקרית, במקום מתוך הפונקציה הראשית (), כדלקמן:

#לִכלוֹל

באמצעות מרחב שמותשעה (ות;



בָּטֵלfn()

{

עֲלוּת<<'נראה'<<' n';

}


בָּטֵלmainFn(בָּטֵל (*ptr)())

{

עֲלוּת<<'תפקיד עיקרי'<<' n';

fn();

(*ptr)();

}


בָּטֵלcb()

{

עֲלוּת<<'פונקציית התקשרות חוזרת'<<' n';

}


intרָאשִׁי()

{

בָּטֵל (*ptr)() = &cb;

mainFn(cb);



לַחֲזוֹר 0;

}

הפלט הוא:

תפקיד עיקרי

נראה

פונקציית התקשרות חוזרת

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

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

#לִכלוֹל

באמצעות מרחב שמותשעה (ות;



בָּטֵלmainFn(בָּטֵל (*ptr)())

{

(*ptr)();

עֲלוּת<<'תפקיד עיקרי'<<' n';

}


בָּטֵלcb()

{

עֲלוּת<<'פונקציית התקשרות חוזרת'<<' n';

}


בָּטֵלfn()

{

עֲלוּת<<'נראה'<<' n';

}


intרָאשִׁי()

{

בָּטֵל (*ptr)() = &cb;

mainFn(cb);

fn();



לַחֲזוֹר 0;

}

הפלט הוא כעת,

פונקציית התקשרות חוזרת

תפקיד עיקרי

נראה

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

התנהגות אסינכרונית עם פונקציית התקשרות חזרה

קוד הפסאודו לתוכנית פונקציות החזרה האסינכרונית הבסיסית היא:

פלט סוג;

הקלד cb(פלט סוג)

{

//הצהרות

}


סוג principalFn(הקלט קלט, הקלד cb(פלט סוג))

{

//הצהרות

}

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

#לִכלוֹל

באמצעות מרחב שמותשעה (ות;

לְהַשְׁחִיר *תְפוּקָה;


בָּטֵלcb(לְהַשְׁחִירהַחוּצָה[])

{

תְפוּקָה=הַחוּצָה;

}



בָּטֵלmainFn(לְהַשְׁחִירקֶלֶט[],בָּטֵל (*ptr)(לְהַשְׁחִיר[חמישים]))

{

(*ptr)(קֶלֶט);

עֲלוּת<<'תפקיד עיקרי'<<' n';

}


בָּטֵלfn()

{

עֲלוּת<<'נראה'<<' n';

}


intרָאשִׁי()

{

לְהַשְׁחִירקֶלֶט[] = 'פונקציית התקשרות חוזרת';

בָּטֵל (*ptr)(לְהַשְׁחִיר[]) = &cb;

mainFn(קלט, cb);

fn();

עֲלוּת<<תְפוּקָה<<' n';



לַחֲזוֹר 0;

}

פלט התוכנית הוא:

תפקיד עיקרי

נראה

פונקציית התקשרות חוזרת

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

זוהי הדרך עם חוט אחד להשגת התנהגות אסינכרונית של פונקציית החזרה עם C ++ טהור.

שימוש בסיסי בספרייה העתידית

הרעיון של ערכת פונקציות החזרה אסינכרונית היא שהפונקציה העיקרית חוזרת לפני שחזרת פונקציית החזרה. הדבר נעשה בעקיפין, ביעילות, בקוד הנ'ל.

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

התוכנית לעיל נכתבה להלן, תוך התחשבות בספרייה העתידית ובפונקציית הסנכרון שלה ():

#לִכלוֹל

#לִכלוֹל

#לִכלוֹל

באמצעות מרחב שמותשעה (ות;

עתיד<חוּט>תְפוּקָה;

מחרוזת cb(מחרוזת סטרי)

{

לַחֲזוֹרstri;

}



בָּטֵלmainFn(קלט מחרוזת)

{

תְפוּקָה=אסינק(cb, קלט);

עֲלוּת<<'תפקיד עיקרי'<<' n';

}


בָּטֵלfn()

{

עֲלוּת<<'נראה'<<' n';

}


intרָאשִׁי()

{

קלט מחרוזת=חוּט('פונקציית התקשרות חוזרת');

mainFn(קֶלֶט);

fn();

ret string=תְפוּקָה.לקבל(); // ממתין להחזרה חוזרת במידת הצורך

עֲלוּת<<ימין<<' n';



לַחֲזוֹר 0;

}

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

סיכום

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

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