السلام عليكم
كيف تستخدم وظائف من نوع CALLBACK كوظائف أعضاء في فئة CLASS ؟
هناك الكثير من التوابع التي تقوم بعملية عد وارجاع قيم مفيدة مستخدمة في نظام التشغيل للمبرمج ، مثلا:
EnumWindows //تعيد قائمة بجميع النوافذ في النظام
EnumFonts //تعيد لائحة بأنماط الخطوط المستخدمة في الجهاز
EnumObjects // تعيد لائحة بالأقلام والفراشي الخ .. المستخدمة في device context معين
الخ ...
هذه التوابع تحتاج الى بارامتر وهو عبارة عن مؤشر الى تابع آخر من النوع CALLBACK ليقوم بعملية ارجاع القيم وارسالها الى التابع Enum ، هذه التوابع استخدامها سهل في السي ولكن قد تواجهك بعض المشاكل عند استخدامها في السي ++ مع الفئات .
مشكلة هذه التوابع أن لكل منها نموذج معين prototype معروف من قبل نظام التشغيل لانستطيع تغييره ومعرفة على أساس أنها توابع C أي قبل ظهور السي ++ والفئات ، في هذه الفقرة سوف أشرح لماذا لا نستطيع استخدام التوابع الأعضاء كتوابع CALLBACK
-البارامتر الخفي ( المؤشر this )
كيف تتعرف الفئات على التوابع والمتغيرات الأعضاء ، دعونا نأخذ مثال
CExample{
int nNum;
void print(char* ch);
BOOL CALLBACK EnumWndProc(HWND hwnd,LPARAM lparam);
}
.
.
CExample example;
void CExample::print(char* ch);
فغن المترجم يضيف لها المؤشر this كبارامتر اخير لكي يحدد الى أي فئة تنتمي فتصبح
void CExample::print(char* ch,(CExample*)&example);
nNum = 0;
تصبح
this->nNum = 0;
هنا المهم ان نعرف أن المترجم يضيف هذا البارامتر للوظائف والمتغيرات الأعضاء ومن خلاله تستطيع الوصول الى بعضها .
نعود هنا الى ال CALLBACK عند استخدام هذا التابع هكذا
BOOL CALLBACK CExample::EnumWndProc(HWND hwnd,LPARAM lparam);
فإنه سيتسبب بخطأ أثناء التنفيذ run time error ، والسبب أن نظام التشغيل يقبل بارامترين فقط لهذا التابع ولكن بما أنه هنا عضو في فئة فسيُلحق به المترجم بارامتر ثالث وهو this مما يؤدي الى اضافة قيمة عشوائية للتابع مما يتسبب بتحطيم البرنامج .access violation
الخلاصة : علينا أن نخبر المترجم أن لا يلحق المؤسر this لهذا التابع ، وهناك طريقتين لعمل ذلك :
1- تعريف التابع على أساس أنه nonmember function ليس عضو بأي فئة وبمعنى آخر global function عام .
طبعا التابع العام لا ينتمي لأي فئة وبالتالي لن يضيف له المترجم المؤشر this .
2- تعريف التابع على أساس أنه static function تابع ساكن .
التابع الساكن لا يأخذ المؤشر this لأنه ينشأ أول شئ في البرنامج ويستطيع أي تابع عضو ضمن الفئة الوصول اليه بدون تعريف غرض من الفئة .
على كل أرفقت هنا مثال لعمل EnumWindows واستخدمت الطريقة الأولى global function ، المثال باستخدام MFC ويعرض لك اسم النافذه والكلاس مع قيمة مقبض النافذة داخل أداة التحكم List control .
لمزيد من المعلومات حول الموضوع
http://msdn.microsoft.com/archive/default..../msdn_callb.asp