Programming Basics SQL HTML CSS JavaScript Python C++ Java JavaFX Swing Problem Solving English English Conversations Computer Fundamentals Learn Typing

C++التعميم

  • مفهوم التعميم
  • الأحرف المستخدمة في التعميم
  • كيفية تعريف نوع غير محدد
  • أمثلة شاملة حول التعامل مع الـ Generics

مفهوم التعميم

التعميم ( Generics ) هو أسلوب في كتابة الكود يجعلك قادراً على بناء كود واحد يلائم أكثر من نوع بيانات، و عند الحاجة إلى استخدام هذا الكود يمكنك إستخدامه كما هو أو تحديد نوع البيانات التي تريده أن يعمل معها حسب حاجتك.

كل كلاس، إنترفيس أو دالة تجد الرمز < > موجود ضمن تعريفه، إعرف مباشرةً أنه مصمم للتعامل مع أكثر من نوع بيانات.


فائدة التعميم

أنت لست مجبر على استخدام أسلوب التعميم و لكن تعلمه سيفيدك كثيراً في تطوير الكود الخاص بك، و جعل حجمه أصغر و أسهل في حالة التعديل.
فمثلاً، يمكنك بناء دالة يمكنك أن تمرر لها مصفوفة من أي نوع كان فتقوم بطباعة قيم العناصر الموجودة فيها.


مصطلحات تقينة

  • Generic Function: تعني تعريف دالة تتعامل مع أكثر من نوع بيانات.
  • Generic Class: تعني تعريف كلاس يتعامل مع أكثر من نوع بيانات.
  • Bounded Type Parameters: تعني تعريف كلاس أو دالة يتعاملان مع نوع محدد بالإضافة إلى جميع الأنواع المشتقة منه, أي التي ترث منه.

الأحرف المستخدمة في التعميم

ذكرنا في الجدول التالي الأحرف المتعارف عليها بين المبرمجين عند التعامل مع الـ Generics.

الأحرف المتعارف عليها في الـ Generics
T إختصار للكلمة Type, يقصد منه أي نوع كان.
نستخدمه في العادة عند بناء كود يتعامل مع أي نوع بيانات.
N إختصار للكلمة Number, يقصد منه أي نوع من الأنواع التي تستخدم لتخزين الأرقام.
نستخدمه في العادة عند بناء كود يتعامل مع الأرقام من أي نوع كانت مثل ( int - float - double إلخ.. ).
E إختصار للكلمة Element, يقصد منه عنصر ليس له نوع محدد.
نستخدمه في العادة عند بناء كود يتعامل مع عناصر المصفوفة من أي نوع كانت.
K إختصار للكلمة Key, يقصد منه مفتاح ليس له نوع محدد.
نستخدمه في العادة عند بناء كود يتعامل مع مفاتيح كائن يخزن البيانات بشكل key / value.
V إختصار للكلمة Value, يقصد منه قيمة ليس لها نوع محدد.
نستخدمه في العادة عند بناء كود يتعامل مع قيم كائن يخزن البيانات بشكل key / value.

ملاحظة: جميع الأحرف المذكورة في الجدول ليس لها أي تأثير على الكود و يمكنك وضع أي حرف أو كلمة مكانهم, لكننا ننصحك باعتمادهم.

كيفية تعريف نوع غير محدد

أي حرف ستستخدمه في دالة أو كلاس للإشارة إلى أن نوعه غير محدد, يجب تعريفه قبل تعريف الدالة أو الكلاس مباشرةً لأنه يعتبر خاص بما تعرّفه بعده فقط.


الشكل العام لتعريف نوع غير محدد هو كالتالي مع الإشارة إلى أنك تستطيع وضع أي حرف أو إسم تريد بدل الحرف T.

template <typename T>
template <typename T>

في حال كنت تريد تعريف أكثر من نوع غير محدد, يجب أن تضع فاصلة بينهما كالتالي.

template <typename T1, typename T2>
template <typename T1, typename T2>


في المثال التالي قمنا بتعريف دالة تقوم بطباعة قيمة أي متغير نمرره لها مهما كان نوعه.
بعدها قمنا باستدعائها ثلاث مرات مع تمرير قيمة مختلفة لها في كل مرة.

مثال

main.cpp
#include <iostream>
using namespace std;
// و هو خاص بالدالة التي سنقوم بتعريفها بعده E هنا قمنا بتعريف نوع بيانات غير محدد قمنا بتسميته
template <typename E>
// فتقوم بطباعتها x عند استدعائها نمرر لها قيمة من أي نوع كانت مكان الباراميتر printVar هنا قمنا بتعريف دالة إسمها
void printVar(E x)
{
cout << x << endl;
}
// main() هنا قمنا بتعريف الدالة
int main()
{
// string و متغير نوعه float متغير نوعه ,int هنا قمنا بتعريف متغير نوعه
int x = 10;
float y = 7.5;
string name = "Mhamad";
// ثلاث مرات مع تمرير قيمة لها نوع مختلف في كل مرة printVar() هنا قمنا باستدعاء الدالة
printVar(x);
printVar(y);
printVar(name);
return 0;
}
#include <iostream> using namespace std; // و هو خاص بالدالة التي سنقوم بتعريفها بعده E هنا قمنا بتعريف نوع بيانات غير محدد قمنا بتسميته template <typename E> // فتقوم بطباعتها x عند استدعائها نمرر لها قيمة من أي نوع كانت مكان الباراميتر printVar هنا قمنا بتعريف دالة إسمها void printVar(E x) { cout << x << endl; } // main() هنا قمنا بتعريف الدالة int main() { // string و متغير نوعه float متغير نوعه ,int هنا قمنا بتعريف متغير نوعه int x = 10; float y = 7.5; string name = "Mhamad"; // ثلاث مرات مع تمرير قيمة لها نوع مختلف في كل مرة printVar() هنا قمنا باستدعاء الدالة printVar(x); printVar(y); printVar(name); return 0; }

سنحصل على النتيجة التالية عند التشغيل.

10
75
Mhamad
		

النوع الذي تقوم بتعريفه قبل أي شيء يمكنك جعله ملاصق لها عند تعريفه و لكننا لم نفعل ذلك حتى نستطيع كتابة شرح واضح لك.

إذاً الدالة printVar() كان بإمكاننا تعريفها كالتالي و الأفضل أن نعرّفها كالتالي أيضاً.

template <typename E>
void printVar(E x)
{
cout << x << endl;
}
template <typename E> void printVar(E x) { cout << x << endl; }


عند استدعاء الدالة printVar() يمكنك تحديد نوع البيانات - التي تريد وضعها بنفسك مكان أي نوع غير محدد فيها - بدل جعل المترجم يفعل ذلك و هذا الأمر من شأنه جعل برنامجك أسرع في التنفيذ.

إذاً كان من المستحسن تحديد نوع القيمة التي سنمررلها للدالة printVar() عند استدعائها كالتالي.

printVar<int>(x); // int بشكل مباشر بالنوع printVar() في الدالة E هنا سيقوم المترجم بتديل الحرف
printVar<float>(y); // float بشكل مباشر بالنوع printVar() في الدالة E هنا سيقوم المترجم بتديل الحرف
printVar<string>(name); // string بشكل مباشر بالنوع printVar() في الدالة E هنا سيقوم المترجم بتديل الحرف
printVar<int>(x); // int بشكل مباشر بالنوع printVar() في الدالة E هنا سيقوم المترجم بتديل الحرف printVar<float>(y); // float بشكل مباشر بالنوع printVar() في الدالة E هنا سيقوم المترجم بتديل الحرف printVar<string>(name); // string بشكل مباشر بالنوع printVar() في الدالة E هنا سيقوم المترجم بتديل الحرف

أمثلة شاملة حول التعامل مع الـ Generics


المثال الأول

المثال التالي هو تطبيق لفكرة Generic Function حيث ستتعلم منه كيف تبني دالة يمكنك أن تمرر لها باراميتر ليس له نوع محدد.

شاهد المثال



المثال الثاني

المثال التالي هو تطبيق لفكرة Generic Function أيضاً و لكنك ستتعلم منه كيف تبني دالة ترجع قيمة ليس لها نوع محدد.

شاهد المثال



المثال الثالث

المثال التالي هو تطبيق لفكرة Generic Class حيث ستتعلم منه كيفية بناء كلاس يتعامل مع مختلف الأنواع.

شاهد المثال