ما الذي تخفيه معدّلات الوراثة في لغة C++؟
\n\nتخيل أنك مهندس معماري. لديك مخطط "مبنى" (الفئة الأساسية)، وتريد بناء ثلاثة "منازل" مختلفة (فئات مشتقة) بناءً عليه. منزل سيكون نسخة طبق الأصل بمدخل عام (public)، والثاني بفناء داخلي مغلق (private)، والثالث بوصول مقتصر على العائلة والأصدقاء (protected). في لغة C++، هذه هي بالضبط طريقة عمل معدّلات الوراثة. ولكن هل يؤثر هذا الاختيار على سرعة تشغيل البرنامج؟ تلميح: نعم ولا. دعنا نفهم كيف لا تطلق النار على قدمك وفي نفس الوقت تحسّن الكود.
هذا السؤال هو من أكثر الأسئلة شيوعًا على Stack Overflow (عشرات الآلاف من المشاهدات)، وليس بدون سبب. المبتدئون غالبًا ما يخلطون بين مستوى الوصول إلى أعضاء الفئة و نوع الوراثة. أما المطورون ذوو الخبرة فيعرفون: الاختيار الصحيح للوراثة يمكن أن يوفر ساعات من التصحيح بل ويسرّع البرنامج قليلاً. اليوم على pythonlib.ru سنغلق هذا الموضوع نهائيًا.
\n\nمثلث الوراثة: public, private, protected
\n\nفي البداية - الأساسيات. تخيل أن لدينا فئة أساسية Animal:
class Animal {\npublic:\n void eat() { /* ... */ }\nprotected:\n int age;\nprivate:\n std::string secretDNA;\n};\n\nالآن دعنا نرى كيف تغيّر أنواع الوراثة الثلاثة الوصول إلى هذه الأعضاء في الفئة المشتقة Dog.
1. الوراثة العامة (Public) — "كما هي"
\nالنوع الأكثر شيوعًا وبديهية. جميع مستويات الوصول تبقى دون تغيير:
\n- \n
public→public(متاح للجميع) \n protected→protected(متاح للورثة) \n private→ غير متاح (يبقى في الفئة الأساسية) \n
استخدمه عندما تريد التعبير عن علاقة "Dog IS-A Animal". هذا هو البرمجة كائنية التوجه الكلاسيكية.
\n\n2. الوراثة المحمية (Protected) — "للمقربين فقط"
\nجميع الأعضاء العامة (public) للفئة الأساسية تصبح محمية (protected) في الفئة المشتقة:
\n- \n
public→protected\n protected→protected\n private→ غير متاح \n
يُستخدم عندما تريد إخفاء تفاصيل التنفيذ عن العالم الخارجي، ولكن السماح بالوصول "للأحفاد". على سبيل المثال، مكتبة Boost تستخدم الوراثة المحمية بنشاط للآليات الداخلية.
\n\n3. الوراثة الخاصة (Private) — "لي وحدي"
\nالوضع الأكثر صرامة. جميع الأعضاء العامة والمحمية تصبح خاصة:
\n- \n
public→private\n protected→private\n private→ غير متاح \n
هذه علاقة "Dog تم تنفيذه من خلال Animal". غالبًا ما يُستخدم بدلاً من التركيب (composition) لأغراض التحسين (سيأتي ذكره أدناه).
\n\nالأداء: أين دفن السر؟
\n\nوالآن - إلى السؤال المثير للاهتمام: هل يؤثر نوع الوراثة على الأداء؟ باختصار: بشكل مباشر - لا، ولكن بشكل غير مباشر - نعم جدًا.
\n\nخرافة: الوراثة الخاصة أسرع من العامة
\nيعتقد البعض أن الوراثة الخاصة "تزيل الفحوصات الزائدة". هذا غير صحيح. معدّلات الوصول (public, protected, private) هي مفهوم وقت الترجمة (compile-time) بحت. المترجم يتحقق منها في مرحلة البناء ويولّد نفس الكود الآلي. لا فرق في وقت التشغيل (runtime).
الواقع: التحسين من خلال تحسين الفئة الفارغة الأساسية (EBO)
\nهنا حيث الوراثة الخاصة تسرّع البرنامج فعليًا! إذا كانت الفئة الأساسية لا تحتوي على بيانات (فئة فارغة)، فعند الوراثة العامة أو المحمية قد يضيف المترجم (ولكن ليس إلزاميًا) بايتًا إضافيًا للمحاذاة. أما عند الوراثة الخاصة، فيتم تفعيل تحسين الفئة الفارغة الأساسية (Empty Base Optimization).