C++التجريد
- مفهوم التجريد
- تطبيق مبدأ التجريد
مفهوم التجريد
التجريد ( Abstraction ) هو أسلوب مهم جداً يستخدم لتسهيل كتابة الأوامر على المبرمجين, فهو يجعلك قادراً على تنفيذ ما تريد دون الحاجة إلى معرفة كافة التفاصيل التي تم فيها تنفيذ ذلك.
كمثال بسيط, إذا كنت تنوي بناء برنامج يتيح لمستخدميه إرسال إقتراحات حول التطبيق من خلال البريد الإلكتروني, في هذه الحالة لن يكون عليك القلق بتاتاً حول طريقة تعامل أوامر C++ مع البروتوكولات التي تعمل عندما يتم إرسال رسائل إلكترونية من خلال هذا التطبيق لأنك لست مسؤولاً عنها. فعلياً هذه وظيفة الشركة التي تعطيك كود جاهز يمكن استخدامه لإرسال بريد إلكتروني و سيكون عليك فقط تحديد المعلومات الأساسية مثل البريد الإلكتروني للمرسل, البريد الإلكتروني للمرسل إليه, نص الرسالة إلخ..
إذاً بشكل عام, التجريد يجعلك تتعامل مع الأشياء بسطحية بدل أن تغوص في معرفة تفاصيل الكودات المعقدة.
و هذا الأسلوب سيمر معك أيضاً في دروس لاحقة حين تتعلم مبدئ يسمى تعدد الأشكال ( Polymorphism ).
تطبيق مبدأ التجريد
إذا كنت تريد تعريف شكل الدالة ( Prototype ) فقط في الكلاس و إجبار أي كلاس يرثها على أن يقوم بتعريفها فيمكنك اتباع أسلوب التجريد لتحقيق ذلك.
كل ما عليك فعله لإعلام المترجم بأنك تريد إجبار الكلاس الإبن على تعريف الدالة التي يرثها من الكلاس الأب بنفسه هو تعريف الدالة في الكلاس الأب بالأساس كدالة مجرّدة و هنا سيكون عليك جعل نوعها virtual
و جعلها تساوي 0
فقط.
مصطلحات تقنية
- الدالة المجرّدة هي أي دالة تطبق أسلوب التجريد و يقال لها Abstract Function أو Pure Virtual Function.
- الكلاس المجرّد هو أي كلاس يحتوي على دالة مجرّدة أو أكثر و يقال له Abstract Class.
شروط التجريد
عند تطبيق أسلوب التجريد فإنه عليك الإنتباه للنقاط التالية:
- الكلاس الذي يحتوي على دوال مجردة لا يمكن إنشاء كائنات منه لأنه في حال استدعاء الدالة لم يتم تعريفها منه فإن هذا سيسبب مشكلة.
- الكلاس الذي يرث دوال مجردة و لا يقوم بإعادة كتابة محتواها أيضاً لا يمكن إنشاء كائنات منه لذات السبب.
- الدوال الثابتة التي نوعها
static
لا يمكن تعريفها كدوال مجردة لأنها أصلاً تستخدم من الكلاس الأساسي. - أسلوب التجريد يتطلب استخدام الكلمتين
virtual
وoverride
اللتين تم إضافتهما ابتداءاً من الإصدار C++ 11 لهذا تأكد أنك تستخدم هذا الإصدار أو الإصدارات الأحدث حتى تستطيع تطبيقه.
في المثال التالي قمنا بتعريف كلاس إسمه Base
يحتوي على دالة مجردة إسمها func
.
بعدها قمنا بتعريف كلاس إسمه Derived
يرث من الكلاس Base
و قمنا فيه بإعادة تعريف الدالة func
.
في الأخير قمنا بإنشاء كائن من الكلاس Derived
و من ثم استدعاء الدالة func()
الموجودة فيه.
المثال الأول
using namespace std; // func يحتوي على دالة مجردة إسمها Base هنا قمنا بتعريف كلاس إسمه class Base { public: virtual void func() = 0; }; // func و فيه قمنا بتعريف الدالة المجردة Base يرث من الكلاس Derived هنا قمنا بتعريف محتوى الكلاس class Derived : public Base { public: void func() override { cout << "Derived class overridden behaviour \n"; } }; // main() هنا قمنا بتعريف الدالة int main() { // d إسمه Derived هنا قمنا بإنشاء كائن من الكلاس Derived d; // Derived و التي تم تعريفها في الكلاس d من الكائن func() هنا قمنا باستدعاء الدالة d.func(); return 0; }
سنحصل على النتيجة التالية عند التشغيل.
Derived class overridden behaviour
سنعيد نفس المثال السابق و لكننا سنحاول إنشاء كائن من الكلاس الأب الذي يحتوي على الدالة المجردة لتنبيهك من الخطأ الذي قد يظهر لك في حال فعلت ذلك.
ملاحظة: قمنا بتعديل الأسطر التي قمنا بتغيرها باللون الأصفر.
المثال الثاني
using namespace std; // func يحتوي على دالة مجردة إسمها Base هنا قمنا بتعريف كلاس إسمه class Base { public: virtual void func() = 0; }; // func و فيه قمنا بتعريف الدالة المجردة Base يرث من الكلاس Derived هنا قمنا بتعريف محتوى الكلاس class Derived : public Base { public: void func() override { cout << "Derived class overridden behaviour \n"; } }; // main() هنا قمنا بتعريف الدالة int main() { // b إسمه Base هنا قمنا بإنشاء كائن من الكلاس Base b; // Base و التي تم تعريفها في الكلاس b من الكائن func() هنا قمنا باستدعاء الدالة b.func(); return 0; }
سنحصل على النتيجة التالية عند التشغيل.
because the following virtual functions are pure within 'Base':
'virtual void Base::func()'
لاحظ أن الخطأ فعلياً حدث بسبب السطر 26 حيث أن المترجم قال بأنه لا يمكن إنشاء كائن من الكلاس Base
لأنه يحتوي على دالة مجردة ( Pure Virtual Function ) ثم كتب لنا إسم الدالة المجردة أيضاً.