القوالب (Templates) في C++

هل فكّرت يومًا:
ليش لازم تكتب نفس الدالة مرتين، وحدة لـ int ووحدة لـ float ووحدة لـ double؟
ليش ما تكتبها مرة وحدة… وتخلي C++ “تفهم” النوع بنفسها؟

هون بيجي مفهوم Templates
اللي هو “الذكاء العام” في C++، اللي يسمح لك تكتب كود قابل لإعادة الاستخدام لأي نوع بيانات، بدون تكرار.


🧠 ما هي القوالب (Templates)؟

القوالب هي طريقة تُمكّنك من كتابة دوال (Functions) أو فئات (Classes) عامة تعمل على أنواع بيانات مختلفة.

تخيّلها كأنك تقول للمترجم:
“أنا ما بهمني نوع البيانات الآن، خلّيها رمز مؤقت (T)،
ولما أستخدم الكود، انت اختر النوع المناسب بنفسك.”


✳️ أنواع القوالب في C++

النوعالاسم الكاملالاستخدام
Function Templatesقوالب الدواللكتابة دوال تعمل على أنواع متعددة
Class Templatesقوالب الفئاتلكتابة فئات عامة لأي نوع بيانات

⚙️ أولاً: Function Templates

تُستخدم لإنشاء دالة عامة (Generic Function) تعمل مع أنواع بيانات متعددة بدون تكرار نفس الكود.


📘 الصيغة العامة:

template <typename T>
T functionName(T param1, T param2) {
    // كود الدالة باستخدام T
}
  • template → الكلمة الأساسية التي تُعرّف القالب.
  • <typename T> → “T” هو نوع عام placeholder سيتم تحديده عند الاستدعاء.
  • لاحقًا ممكن تستبدل typename بـ class — الاثنان نفس المعنى هنا.

🧩 مثال بسيط جدًا:

#include <iostream>
using namespace std;

template <typename T>
T add(T a, T b) {
    return a + b;
}

int main() {
    cout << add(2, 3) << endl;        // int
    cout << add(2.5, 3.1) << endl;    // double
    cout << add(string("كود "), string("التطور")) << endl;  // string
}

📤 النتيجة:

5
5.6
كود التطور

🔹 لاحظ إننا استخدمنا نفس الدالة add() مع أنواع مختلفة بدون إعادة تعريفها.


🧠 كيف يعمل Function Template؟

عند استدعاء الدالة، يقوم المترجم (Compiler) بإنشاء نسخة جديدة من الدالة
تناسب نوع البيانات الذي تم تمريره.

يعني فعليًا، الكود:

add(2, 3);

يخلق دالة:

int add(int, int);

بينما:

add(2.5, 3.1);

ينتج:

double add(double, double);

⚙️ قالب متعدد الأنواع (Multiple Type Parameters)

يمكنك تحديد أكثر من نوع باستخدام فاصلة.

template <typename T1, typename T2>
void display(T1 a, T2 b) {
    cout << "القيمة الأولى: " << a << ", الثانية: " << b << endl;
}

int main() {
    display(5, "محمد");
    display(3.5, 10);
}

📤 النتيجة:

القيمة الأولى: 5, الثانية: محمد
القيمة الأولى: 3.5, الثانية: 10

🧩 مثال عملي: دالة swap عامة

#include <iostream>
using namespace std;

template <typename T>
void swapValues(T &a, T &b) {
    T temp = a;
    a = b;
    b = temp;
}

int main() {
    int x = 10, y = 20;
    double a = 1.5, b = 2.5;

    swapValues(x, y);
    swapValues(a, b);

    cout << "x = " << x << ", y = " << y << endl;
    cout << "a = " << a << ", b = " << b << endl;
}

📤 النتيجة:

x = 20, y = 10
a = 2.5, b = 1.5

🔹 نفس الدالة اشتغلت مع int وdouble بدون أي تعديل.


🧱 ثانيًا: Class Templates

القوالب مش بس للدوال، بل كمان للفئات.
ممكن تكتب فئة واحدة تتعامل مع أي نوع بيانات.


📘 الصيغة العامة:

template <typename T>
class ClassName {
private:
    T data;
public:
    ClassName(T value) {
        data = value;
    }

    void show() {
        cout << "القيمة: " << data << endl;
    }
};

🧩 مثال عملي:

#include <iostream>
using namespace std;

template <typename T>
class Box {
private:
    T value;
public:
    Box(T v) : value(v) {}
    void show() {
        cout << "القيمة داخل الصندوق: " << value << endl;
    }
};

int main() {
    Box<int> box1(10);
    Box<double> box2(5.5);
    Box<string> box3("كود التطور");

    box1.show();
    box2.show();
    box3.show();
}

📤 النتيجة:

القيمة داخل الصندوق: 10
القيمة داخل الصندوق: 5.5
القيمة داخل الصندوق: كود التطور

🔹 نفس الفئة Box اشتغلت على 3 أنواع مختلفة بدون نسخ الكود.


⚙️ Class Template مع أكثر من نوع

template <typename T1, typename T2>
class Pair {
public:
    T1 first;
    T2 second;

    Pair(T1 a, T2 b) {
        first = a;
        second = b;
    }

    void show() {
        cout << "الأول: " << first << ", الثاني: " << second << endl;
    }
};

int main() {
    Pair<int, string> p1(1, "محمد");
    Pair<string, double> p2("درجة", 99.5);

    p1.show();
    p2.show();
}

📤 النتيجة:

الأول: 1, الثاني: محمد
الأول: درجة, الثاني: 99.5

🧠 كيف يعمل Class Template؟

عند كتابة:

Box<int> b1(10);
Box<double> b2(5.5);

المترجم فعليًا ينشئ نسختين من الفئة:

class Box_int { int value; ... };
class Box_double { double value; ... };

يعني القالب مش كود “يتكرر وقت التشغيل”،
بل “ينسخ نفسه” أثناء الترجمة (Compile Time).


🧩 مثال متقدم: Stack باستخدام Class Template

#include <iostream>
using namespace std;

template <typename T>
class Stack {
private:
    T arr[5];
    int top;
public:
    Stack() { top = -1; }

    void push(T val) {
        if (top == 4)
            cout << "المكدس ممتلئ!\n";
        else
            arr[++top] = val;
    }

    void pop() {
        if (top == -1)
            cout << "المكدس فارغ!\n";
        else
            top--;
    }

    void display() {
        if (top == -1)
            cout << "المكدس فارغ!\n";
        else {
            cout << "العناصر في المكدس: ";
            for (int i = 0; i <= top; i++)
                cout << arr[i] << " ";
            cout << endl;
        }
    }
};

int main() {
    Stack<int> s1;
    s1.push(10);
    s1.push(20);
    s1.push(30);
    s1.display();
    s1.pop();
    s1.display();

    Stack<string> s2;
    s2.push("كود");
    s2.push("التطور");
    s2.display();
}

📤 النتيجة:

العناصر في المكدس: 10 20 30 
العناصر في المكدس: 10 20 
العناصر في المكدس: كود التطور 

🔹 شفنا كيف نفس الفئة Stack اشتغلت لكل من int وstring بنفس الكفاءة.


⚙️ Template Specialization — التخصيص

أحيانًا بدك تكتب سلوك مخصص لنوع معين فقط.

مثلاً:
لو عندك Box<string>، بدك تطبع الجملة بطريقة مختلفة.


📘 مثال:

#include <iostream>
using namespace std;

template <typename T>
class Box {
public:
    Box(T val) { cout << "القيمة: " << val << endl; }
};

// تخصيص للفئة string
template <>
class Box<string> {
public:
    Box(string val) { cout << "النص داخل الصندوق: \"" << val << "\"" << endl; }
};

int main() {
    Box<int> b1(10);
    Box<string> b2("كود التطور");
}

📤 النتيجة:

القيمة: 10
النص داخل الصندوق: "كود التطور"

🔹 هذا بنسميه Template Specialization
ميزة عظيمة جدًا في C++ ما بتلاقيها في أغلب اللغات.


💡 فوائد استخدام القوالب

  1. إعادة استخدام الكود بدون تكرار.
  2. سرعة في الأداء لأن التخصيص يتم وقت الترجمة.
  3. كفاءة عالية في الذاكرة لأن الكود يتم إنشاؤه فقط للأنواع المستخدمة.
  4. قابلية التوسع — أي نوع جديد، نفس الكود يخدمه.
  5. نظافة الكود — تكتب مرة، وتستخدم في كل مكان.

⚠️ ملاحظات تقنية مهمة

  • لا يمكن فصل تعريف القالب في ملف CPP مستقل عن ملف الرأس بسهولة — لازم يكون التعريف في نفس الملف أو ملف .hpp مشترك.
  • القوالب تستهلك وقت ترجمة أطول (compile-time) لكن سرعة تنفيذها أعلى.
  • لا يمكن استخدام partial specialization مع function templates (فقط مع classes).

🌍 روابط خارجية موثوقة

🔗 cppreference – Templates
🔗 GeeksForGeeks – Templates in C++
🔗 Programiz – Function & Class Templates
🔗 W3Schools – C++ Templates


🧩 الخلاصة النهائية

القوالب في C++ هي أداة “المرونة القصوى”.
تكتب كود واحد… يتكيّف تلقائيًا مع كل أنواع البيانات.

  • Function Templates → دوال عامة تعمل مع أي نوع.
  • Class Templates → فئات عامة تدير أنواع مختلفة بنفس المنطق.
  • Specialization → تخصيص ذكي لسلوك معين عند الحاجة.

النتيجة؟
كود نظيف، سريع، آمن، وقابل للتوسع إلى ما لا نهاية.


اكتشاف المزيد من كود التطور

اشترك للحصول على أحدث التدوينات المرسلة إلى بريدك الإلكتروني.

اترك رد

Scroll to Top