كيف تجتاز مقابلة C++: تحليل أهم الأسئلة مع أمثلة
مقابلة مطور C++ هي اختبار ليس فقط للقواعد النحوية، بل وأيضاً للفهم العميق لكيفية عمل الذاكرة والمُجمّع والمكتبة القياسية. في هذه المقالة، سنقوم بتحليل الأسئلة الأكثر شيوعاً التي تُطرح في المقابلات في الأعوام 2024-2025. ستتعلم ليس فقط الإجابات الصحيحة، بل وسترى أمثلة على الأكواد التي ستساعدك على اجتياز المقابلة التقنية بثقة.
1. الدوال الافتراضية وتعدد الأشكال (Polymorphism)
هذا كلاسيكي. يريد القائمون على المقابلة التأكد من أنك تفهم الفرق بين الربط الثابت (Static Binding) والربط الديناميكي (Dynamic Binding)، بالإضافة إلى آلية عمل جدول الدوال الافتراضية (vtable).
السؤال: ماذا يحدث إذا تم استدعاء دالة افتراضية (Virtual Function) من المُنشئ (Constructor) أو المُدمّر (Destructor)؟
الإجابة: استدعاء دالة افتراضية من مُنشئ الفئة الأساسية (Base Class) لن يكون متعدد الأشكال (Polymorphic). في لحظة استدعاء مُنشئ الفئة الأساسية، لم يتم إنشاء كائن الفئة المشتقة (Derived Class) بعد، لذلك سيتم استدعاء نسخة الدالة الخاصة بالفئة الأساسية. وبالمثل بالنسبة للمُدمّر — بعد استدعاء مُدمّر الفئة المشتقة، يتم "خفض" الكائن إلى الفئة الأساسية.
#include <iostream>
class Base {public: Base() { print(); } // استدعاء دالة افتراضية في المُنشئ virtual void print() { std::cout << "Base"; } virtual ~Base() = default;};
class Derived : public Base {public: Derived() { print(); } void print() override { std::cout << "Derived"; }};
int main() { Derived d; // الإخراج: Base (من مُنشئ Base) // Derived (من مُنشئ Derived) return 0;}2. المؤشرات الذكية (Smart Pointers)
لا تخلو أي مقابلة حديثة من هذا الموضوع. المؤشرات الذكية هي أساس RAII وإدارة الموارد في C++.
السؤال: ما الفرق بين std::unique_ptr و std::shared_ptr و std::weak_ptr؟ ومتى يتم استخدام كل منها؟
الإجابة:
- unique_ptr — ملكية فردية. لا يُنسخ، بل يُنقل فقط. مثالي للموارد التي يجب تحريرها عند الخروج من نطاق الرؤية (Scope).
- shared_ptr — ملكية مشتركة. يستخدم عداد المراجع (Reference Count). يحذف الكائن عندما يصبح العداد صفراً.
- weak_ptr — "مراقب" لـ shared_ptr. لا يزيد عداد المراجع. يُستخدم لمنع التبعيات الدائرية (Cyclic Dependencies).
#include <memory>#include <iostream>
class Resource {public: Resource() { std::cout << "Resource acquired"; } ~Resource() { std::cout << "Resource released"; }};
int main() { // unique_ptr std::unique_ptr<Resource> uptr = std::make_unique<Resource>(); // shared_ptr std::shared_ptr<Resource> sptr1 = std::make_shared<Resource>(); std::shared_ptr<Resource> sptr2 = sptr1; // عداد المراجع = 2 // weak_ptr std::weak_ptr<Resource> wptr = sptr1; // لا يزيد العداد if (auto locked = wptr.lock()) { std::cout << "Resource is still alive"; } return 0;}3. دلالات النقل (Move Semantics) والمراجع من النوع rvalue (rvalue References)
دلالات النقل هي إحدى الميزات الرئيسية في C++11. في المقابلة، قد يُطلب منك كتابة مُنشئ نقل (Move Constructor) أو شرح ما هو مرجع التوجيه (Forwarding Reference).
السؤال: ما هي دلالات النقل (Move Semantics) ولماذا هي مطلوبة؟ أعط مثالاً عندما تعمل على تسريع الكود.
الإجابة: تسمح دلالات النقل بنقل ملكية الموارد (مثل الذاكرة الديناميكية) دون نسخها. بدلاً من النسخ العميق (Deep Copy)، نقوم "بنقل" المؤشرات، مع إعادة تعيين الكائن الأصلي إلى الصفر. هذا أمر بالغ الأهمية للأداء عند العمل مع الحاويات الكبيرة.
```