يسمح لك برنامج التحويل البرمجي لـ Microsoft بإضافة ملحق "novtable" لسمة "__declspec" عند الإعلان عن فئة.
الهدف المعلن هو تقليل حجم الرمز الذي تم إنشاؤه بشكل ملحوظ. في تجارب مكوناتنا ، كان الانخفاض من 0.6 إلى 1.2 في المئة من حجم DLL.
قابلية التطبيق: الفصول غير المقصود منها إنشاء نسخة مباشرة منها.
على سبيل المثال: فئات واجهة بحتة.
في الكود ، يبدو كما يلي:
struct __declspec(novtable) IDrawable { virtual void Draw() const = 0; };
ملاحظة: تم استخدام الكلمة الأساسية للبنية لإعلان فئة واجهة لتخليص مثال تفاصيل المقالة غير ذات الصلة ؛ بينما في حالة استخدام الفصل ، يتعين على الفرد استخدام الجمهور للإشارة إلى "الدعاية" للطرق. للسبب نفسه ، لن أقوم بإضافة destructor الظاهري إلى فئة الواجهة في هذه المقالة.يعد اسم "novtable" بأنه لن يكون هناك جدول افتراضي ... ولكن كيف تعمل آلية استدعاء الوظائف الافتراضية في التعليمة البرمجية التالية:
تذكر ما تمت إضافته عند إعلان وظيفة افتراضية في الفصل الدراسي:
- تحديد جدول الوظائف الافتراضية. يتم استخدام مثيل واحد من هذا الجدول لجميع مثيلات الفئة.
- تتم إضافة مؤشر إلى جدول الوظائف الظاهرية إلى أعضاء بيانات الفصل الدراسي.
- رمز تهيئة هذا المؤشر في مُنشئ الفصل.
وبالتالي ، في مثالنا ، سيكون هناك إعلان لجدولين للوظائف الافتراضية: من أجل IDrawable و Rectangle. عند إنشاء كائن مستطيل ، يكون مُنشئ IDrawable هو أول من ينفذ ، حيث يقوم بتهيئة مؤشر إلى جدول وظائفه الظاهري. بشكل تخطيطي ، يبدو كما يلي:

منذ أن تم التصريح عن وظيفة السحب في IDrawable افتراضية خالصة (يشار إلى "= 0" بدلاً من نص الدالة) ، تتم كتابة عنوان دالة purecall التي تم إنشاؤها بواسطة برنامج التحويل البرمجي في جدول الوظائف الافتراضية.
بعد ذلك ، يتم تنفيذ مُنشئ Rectangle ، الذي يقوم بتهيئة نفس المؤشر ، ولكن إلى جدول الوظائف الافتراضية الخاص به:

ماذا تفعل "novtable" ، ولماذا تعد Microsoft بتقليل حجم الكود؟
إنه التعريف غير الضروري لجدول الوظائف الظاهري القابل للتحجيم وتهيئة المؤشر إليه في مُنشئ IDrawable المستثنى من التعليمة البرمجية الناتجة عند إضافة "novtable".
في هذه الحالة ، عند إنشاء IDrawable ، سيحتوي المؤشر إلى جدول الوظائف الافتراضية على قيمة غير متوقعة. لكن هذا لا ينبغي أن يزعجنا ، لأن إنشاء تطبيق مع الوصول إلى الوظائف الافتراضية قبل الإنشاء الكامل للكائن عادة ما يكون خطأ. على سبيل المثال ، إذا تم استدعاء دالة غير افتراضية من هذه الفئة في مُنشئ الفئة الأساسية ، والتي بدورها تستدعي وظيفة افتراضية ، فسيتم استدعاء وظيفة purecall بدون novtable ، وسلوك غير متوقع مع novtable ؛ قد لا يكون أي من الخيارات مقبولًا.
لاحظ أنه لا يوجد انخفاض في الحجم فحسب ، بل هناك أيضًا تسارع في البرنامج.
RTTI
كما تعلمون ، يسمح لك std :: dynamic_cast بتوجيه المؤشرات والروابط من مثيل واحد من الفصل إلى مؤشر ورابط إلى آخر ، إذا كانت هذه الفئات مرتبطة بشكل هرمي ومتعددة الأشكال (تحتوي على جدول الوظائف الافتراضية). بدوره ، يتيح لك عامل التشغيل typeid الحصول على معلومات حول كائن ما في وقت التشغيل باستخدام المؤشر (الرابط) لهذا الكائن الذي تم تمريره إليه. يتم توفير هذه القدرات بواسطة آلية RTTI ، التي تستخدم معلومات الكتابة الموجودة بالإشارة إلى vtable للفئة. تعتمد تفاصيل الهيكل والموقع على المترجم. في حالة برنامج التحويل البرمجي لـ Microsoft ، يبدو كما يلي:

لذلك ، إذا طلب المترجم أثناء التحويل البرمجي تمكين RTTI ، فإن novtable يستبعد أيضًا إنشاء تعريف type_info لـ IDrawable وبيانات الخدمة المطلوبة لذلك.
لاحظ أنك إذا قدمت بطريقة أو بأخرى المعرفة التي تشير إلى أن المؤشر المشار إليه (رابط) إلى فئة أساسية يشير إلى تطبيق مشتق ، فإن std :: static_cast أكثر فعالية ولا تتطلب RTTI.
مايكروسوفت محددة
بالإضافة إلى MSVC ، توجد هذه الميزة بنفس بناء الجملة في Clang عند التحويل البرمجي تحت Windows.
النتائج
- __declspec (novtable) - لا يؤثر على مقدار الذاكرة التي تشغلها مثيلات الفئة.
- يتم ضمان تقليل حجم البرنامج وتسريعه عن طريق حذف تعريف جداول الوظائف الظاهرية غير المستخدمة ورأسية RTTI وإزالة رمز التهيئة الخاص بالمؤشر إلى جدول الوظائف الافتراضية في مُنشئي فئة الواجهة.