الواجهات في C++: كيفية التصريح بها دون تعقيد

مدرب بايثون أونلاين للمبتدئين

تعلم Python بسهولة دون إرهاق نظري. حل مهام عملية مع التحقق التلقائي واكتب الكود مباشرة في المتصفح.

ابدأ الدورة

الواجهات في C++: دليل لمن سئم من البحث

\n\n

إذا سبق لك البرمجة بلغة Java أو C# ثم انتقلت إلى C++، فبالتأكيد تساءلت: "أين الكلمة المفتاحية interface؟". المفاجأة: لا توجد. في C++، يتم تنفيذ الواجهات بطريقة مختلفة — من خلال الفئات المجردة. وهذه ليست مشكلة، بل ميزة تمنح مرونة لا تصدق.

\n\n

على موقع Stack Overflow، سؤال "How do you declare an interface in C++?" يجمع آلاف المشاهدات. هذا يعني أنه حتى المطورين ذوي الخبرة يختلط عليهم الأمر أحيانًا. اليوم سنفهم مرة واحدة وإلى الأبد كيفية التصريح عن واجهة في C++ بحيث يكون كودك نظيفًا والمترجم راضيًا.

\n\n

ما هي الواجهة في C++؟ (المفاجأة: إنها فئة مجردة)

\n\n

في البرمجة الكائنية التقليدية، الواجهة هي عقد. الفئة التي تنفذ الواجهة ملزمة بتوفير تنفيذ لجميع دوالها. في C++، يقوم بهذا الدور الفئة المجردة — وهي فئة تحتوي على دالة واحدة على الأقل افتراضية بحتة (pure virtual function).

\n\n

تذكر القاعدة الأساسية:

\n
    \n
  • الواجهة = فئة حيث جميع الدوال افتراضية بحتة.
  • \n
  • الفئة المجردة = فئة حيث دالة واحدة على الأقل افتراضية بحتة (ولكن قد تحتوي على دوال عادية مع تنفيذ).
  • \n
\n\n

بالنسبة للواجهة النقية، نستخدم الخيار الأول: لا منطق، فقط تصريحات.

\n\n

كيفية التصريح عن واجهة نقية: الصيغة الأساسية

\n\n

إليك مثال بسيط لواجهة شكل هندسي:

\n\n
class IShape {\npublic:\n    virtual double area() const = 0;      // دالة افتراضية بحتة\n    virtual double perimeter() const = 0; // دالة أخرى\n    virtual ~IShape() {}                  // مدمر افتراضي — إلزامي!\n};
\n\n

لاحظ = 0 في نهاية التصريح. هذه هي العلامة السحرية "افتراضي بحت". هذه الدالة ليس لها جسم (تنفيذ) في الفئة الأساسية.

\n\n

النقاط الرئيسية:

\n
    \n
  • البادئة I في اسم الفئة — اتفاقية غير رسمية للواجهات (I = Interface). يمكنك عدم استخدامها، لكنها تسهل قراءة الكود.
  • \n
  • المدمر الافتراضي إلزامي. إذا قمت بحذف كائن عبر مؤشر للواجهة، بدون مدمر افتراضي سيكون السلوك غير محدد (اقرأ: البرنامج سيتعطل).
  • \n
  • جميع الدوال public — يجب أن تكون الواجهة قابلة للاستدعاء من الخارج.
  • \n
\n\n

تنفيذ الواجهة: من الأقوال إلى الأفعال

\n\n

الآن لنكتب فئة تنفذ واجهتنا IShape. لتكن دائرة:

\n\n
class Circle : public IShape {\nprivate:\n    double radius;\npublic:\n    explicit Circle(double r) : radius(r) {}\n\n    double area() const override {\n        return 3.14159 * radius * radius;\n    }\n\n    double perimeter() const override {\n        return 2 * 3.14159 * radius;\n    }\n};
\n\n

الكلمة المفتاحية override (C++11 والإصدارات الأحدث) ليست إلزامية، لكنها مرغوبة بشدة. فهي تجبر المترجم على التحقق من أنك تعيد تعريف دالة افتراضية من الفئة الأساسية. أخطأت في الاسم؟ سيقول المترجم: "خطأ! لا توجد هذه الدالة في الواجهة".

\n\n

تعدد الأشكال في العمل

\n\n

الآن الجزء الممتع — يمكننا العمل مع أشكال مختلفة من خلال واجهة موحدة:

\n\n
void printShapeInfo(const IShape& shape) {\n    std::cout << "Area: " << shape.area() << "\\n";\n    std::cout << "Perimeter: " << shape.perimeter() << "\\n";\n}\n\nint main() {\n    Circle c(5.0);\n    printShapeInfo(c); // يعمل!\n    return 0;\n}
\n\n

الدالة printShapeInfo تستقبل مرجعًا إلى IShape. لا يهمها أي كائن تم تمريره — دائرة، مربع أو مثلث. طالما أنها تنفذ الواجهة، كل شيء سيعمل. هذا هو تعدد الأشكال

المدونات

توصيات الكتب