




السمعة:
- إنضم2 سبتمبر 2023
- المشاركات 142
- مستوى التفاعل 244
- النقاط 43
بِسْمِ اللَّـهِ الرَّحْمَـٰنِ الرَّحِيمِ
في الدرس السابق تحدثنا عن مفهوم الوراثة وأنواعها , في هذا الدرس رح نحكي عن مفهوم الOverriding وهو مفهوم جدا بعتمد على مفهوم الوراثةزي ما حكينا الوراثة هي عبارة عن تضمين محتوى كلاس في كلاس آخر فيقوم بوراثة الدوال و المتغيرات الموجودة في الكلاس الاب
قبل البدء فالنعتبر أن الكلاس الابن يوجد به دالة تكون مشابهة للدالة الموروثة أي أنها تمتلك( نفس الإسم و النوع و عدد الباراميترات ) أما محتواها يختلف عن محتوى الدالة الموروثة
في هذه الحالة يمكن أن يكون في الكلاس دالتين أو أكثر تمتلك نفس الإسم و النوع و عدد الباراميترات وهذا ما يسمى بال Overriding
اذا ال Overriding هو تعريف نفس الدالة التي ورثها الكلاس الإبن من الكلاس الأب من جديد, و هذه الدالة الجديدة تكون مشابهة للدالة الموروثة من حيث الشكل فقط,
أي لها نفس الإسم و النوع و عدد الباراميترات, لكن محتواها مختلف بهدف أن يكون متناسب أكثر مع الكلاس الإبن
فالهدف الحقيقي من إعادة التعريف أو التعريف من جديد هو إتاحة الفرصة للكلاس الإبن ليعرّف الدوال حسب حاجته
ولنطبق خاصية الOverriding يجب علينا أن نطبق بعض الشروط
* يجب أن يكون الـ Modifier المستخدم للدالة الجديدة هو نفسه المستخدم للدالة القديمة, و يجب أن يكون نوعه public أو protected
* عدد و نوع باراميترات الدالة الجديدة يجب أن يطابق عدد و نوع باراميترات الدالة القديمة
* نوع الإرجاع للدالة الجديدة يجب أن يكون نفس نوع الإرجاع للدالة القديمة
إلا أنه لا يمكن أن نطبق الOverride لثلاث حالات
الحالة الأولى إذا كانت الدالة معرفة ك private فهنا لا نستطيع أن نفعل لها Override لأن كلمة private تمنع إمكانية الوصول المباشر للدالة من الكلاس الإبن
الحالة الثانية إذا كانت الدالة المعرفة كـ final لا يمكن أن نفعل لها Override, لأن كلمة final تمنع تغير محتوى الدالة بعد تعريفها
قبل أن نكمل سنتطرق هنا لمفهوم كلمة final
تستخدم كلمة finalلمنع الكلاس الإبن من إعادة تعريف الدالة التي ورثها من الكلاس فيمكنك جعل نوع الدالة virtual final
حتى أنه يمكنك جعل نوع الكلاس بأكمله final فهنا لا يمكنك إعادة تعريف أي دالة موجودة فيه بهدف أن يتم استخدام الدوال الموجودة فيه كما هي
ويجب علينا معرفة أن الدالة التي لا يمكن إعادة تعريفها يقال لها في العادة دالة ثابتة وأن الكلاس الذي لا يمكن إعادة تعريف أي شيء موجود فيه يقال له كلاس ثابت
حيث أن الكلاس الثابت لا يسمح لك بالوراثة منه لأن الوراثة بالأساس فكرتها أنك ترث الشيء بهدف تطويره أو الزيادة عليه.
بمعنى آخر يمكنك إنشاء كائنات منه فقط و استخدام ما هو موجود فيه
أمثلة بسيط عن إستخدام كلمة final
كود:
#include <iostream>
using namespace std;
// func يحتوي على دالة ثابتة إسمها Base هنا قمنا بتعريف كلاس إسمه
class Base
{
public:
virtual void func() final
{
cout << "Base class default behaviour \n";
}
};
// func و فيه قمنا بإعادة تعريف الدالة الثابتة Base يرث من الكلاس Derived هنا قمنا بتعريف محتوى الكلاس
class Derived : public Base
{
public:
void func() override // هذا السطر الذي سيسبب المشكلة عند التشغيل
{
cout << "Derived class overridden behaviour \n";
}
};
// main() هنا قمنا بتعريف الدالة
int main()
{
return 0;
}
بعدها قمنا بتعريف كلاس إسمه Derived يرث من الكلاس Base و حاولنا فيه إعادة تعريف الدالة func()
سيظهر الخطأ التالي عند التشغيل
كود:
error: virtual function 'virtual void Derived::func()' overriding final function
note: overridden function is 'virtual void Base::func()'
In member function 'virtual void Derived::func()'
اذا في هذا المثال حدث الخطأ فعلياً بسبب السطر 19 حيث أن ال compiler قال بأنه لا يمكن إعادة تعريف الدالة func()
في الكلاس Derived الذي ورثها لأنها في الكلاس الأب Base معرّفة كدالة ثابتة
المثال الثاني
كود:
#include <iostream>
using namespace std;
// func يحتوي على دالة إسمها Base هنا قمنا بتعريف كلاس ثابت إسمه
class Base final
{
public:
void func()
{
cout << "Base class default behaviour \n";
}
};
// و طبعاً هذا الأمر سيسبب مشكلة عند التشغيل Base يرث من الكلاس Derived هنا قمنا بتعريف محتوى الكلاس
class Derived : public Base
{
};
// main() هنا قمنا بتعريف الدالة
int main()
{
return 0;
}
بعدها قمنا بتعريف كلاس إسمه Derived يرث من الكلاسBase
سيظهر الخطأ التالي عند التشغيل
كود:
error: cannot derive from 'final' base 'Base' in derived type 'Derived'
المثال الثالث والأخير
كود:
#include <iostream>
using namespace std;
// func يحتوي على دالة إسمها Base هنا قمنا بتعريف كلاس ثابت إسمه
class Base final
{
public:
void func()
{
cout << "Base class default behaviour \n";
}
};
// main() هنا قمنا بتعريف الدالة
int main()
{
// b إسمه Base هنا قمنا بإنشاء كائن من الكلاس
Base b;
// b من الكائن func() هنا قمنا باستدعاء الدالة
b.func();
return 0;
}
بعدها قمنا بإنشاء كائن منه و استدعاء الدالة الموجودة فيه
سنحصل على النتيجة التالية عند التشغيل
كود:
Base class default behaviour


الحالة الثالثة وهي أن نعرف الدالة كـ static فهنا لا يمكن أن نفعل لها Override و لكن يمكن تعريفها من جديد في أي مكان, لأن كلمة static تجعل الدالة مشتركة بين جميع الكلاسات
فالنأخذ الان مثال يوضح فائدة الOverride
كود:
#include <iostream>
using namespace std;
// الذي يعتبر الكلاس الأساسي لأي دولة في العالم, إذاً يجب أن يرثه كل كلاس يمثل دولة Country هنا قمنا بتعريف الكلاس
class Country {
// هنا قمنا بتعريف دالة تقوم بطباعة لغة البلد و جعلناها تطبع اللغة الإنجليزية كاللغة الإفتراضية لأي بلد
public:
void language()
{
cout << "English \n";
}
};
// Country و يرث من الكلاس Australia هنا قمنا بتعريف كلاس يمثل دولة أستراليا و إسمه
class Australia : public Country {
// من جديد لأن اللغة الإنجليزية هي لغة أستراليا أصلاً language() هنا لا داعي لتعريف الدالة
};
// Country و يرث من الكلاس Lebanon هنا قمنا بتعريف كلاس يمثل دولة لبنان و إسمه
class Lebanon : public Country {
// من جديد لأن اللغة الإنجليزية ليست لغة لبنان language() هنا يجب تعريف الدالة
public:
void language()
{
cout << "Arabic \n";
}
};
// Country و يرث من الكلاس Spain هنا قمنا بتعريف كلاس يمثل دولة إسبانيا و إسمه
class Spain : public Country {
// من جديد لأن اللغة الإنجليزية ليست لغة إسبانيا language() هنا يجب تعريف الدالة
public:
void language()
{
cout << "Spanish \n";
}
};
// main() هنا قمنا بتعريف الدالة
int main()
{
// هنا قمنا بإنشاء كائنات من البلدان الثلاثة
Australia au;
Lebanon lb;
Spain sp;
// لعرض لغة كل بلد language() هنا قمنا باستدعاء الدالة
au.language();
lb.language();
sp.language();
return 0;
}
في هذا الكلاس قمنا بتعريف دالة إسمها language() فكرتها طباعة لغة البلد و جعلناها تطبع اللغة الإنجليزية بشكل إفتراضي كلغة أي بلد
بعدها قمنا بتعريف ثلاث كلاسات تمثل ثلاث بلدان مختلفة (أستراليا, لبنان, إسبانيا) لذلك جعلناها ترث من الكلاس Country الذي يعتبر أساس أي بلد.
إذاً الكلاسات الثلاثة سترث الدالة language()
اذا فالفكرة هنا هو أن أي كلاس يرث من Country قد يضطر إلى تعريف الدالة language() من جديد حتى تناسبه
فمثلاً لبنان لغتها هي العربية, و إسبانيا لغتها هي الإسبانية.
بعد إنشاء هذه الكلاسات, قمنا بإنشاء كائنات منها و استدعاء الدالة language() من كل واحد فيهم لطباعة اللغة التي يتكلم الناس فيها
سنحصل على النتيجة التالية عند التشغيل
كود:
English Arabic Spanish


دروس البرمجة الكائنية
التعديل الأخير بواسطة المشرف: