Menu
Coddy logo textTech
flag Ar iconالعربيةdown icon

أعضاء الـ Instance مقابل الـ Static

جزء من قسم Object Oriented Programming في رحلة C++ على Coddy — الدرس 27 من 104.

حتى الآن، كل متغير عضو قمت بإنشائه ينتمي إلى كائن محدد. عندما تقوم بإنشاء كائنين من نوع Player، يكون لكل منهما name و health الخاصين به. تُسمى هذه أعضاء النسخة (instance members) - وهي توجد بشكل منفصل لكل نسخة من الفئة (class).

ولكن ماذا لو كنت بحاجة إلى بيانات مشتركة عبر جميع الكائنات؟ على سبيل المثال، تتبع عدد اللاعبين الموجودين في المجمل.

هنا يأتي دور الأعضاء الساكنة (static members). فالعضو الساكن ينتمي إلى الفئة (class) نفسها، وليس إلى أي كائن (object) معين.

class Player {
    std::string name;           // عضو مثيل - كل لاعب لديه عضو خاص به
    int health;                 // عضو مثيل
    
    static int playerCount;     // عضو ثابت - مشترك بين جميع اللاعبين
    
public:
    Player(std::string n) : name(n), health(100) {
        playerCount++;          // زيادة عند إنشاء أي لاعب
    }
    
    ~Player() {
        playerCount--;          // إنقاص عند تدمير أي لاعب
    }
};

الفرق الرئيسي: يتم الوصول إلى أعضاء النسخة (instance members) من خلال كائن (object)، بينما يمكن الوصول إلى الأعضاء الساكنة (static members) من خلال اسم الفئة (class) نفسه. فكر في أعضاء النسخة على أنها "واحد لكل كائن" والأعضاء الساكنة على أنها "واحد لكل فئة".

أعضاء النسخة (Instance Members)الأعضاء الساكنة (Static Members)
فريدة لكل كائنمشتركة بين جميع الكائنات
تُنشأ عند إنشاء الكائنتوجد قبل إنشاء أي كائن
يتم الوصول إليها عبر الكائن: player.healthيتم الوصول إليها عبر الفئة: Player::playerCount

تعد الأعضاء الساكنة (Static members) مفيدة للعدادات، أو قيم الإعدادات، أو أي بيانات تنتمي منطقياً إلى الفئة بدلاً من الكائنات الفردية.

challenge icon

التحدي

سهل

لنقم ببناء نظام مخزون منتجات يتتبع تفاصيل المنتجات الفردية وإحصائيات المخزون الإجمالية باستخدام الأعضاء المثيلة (instance members) والأعضاء الساكنة (static members).

ستقوم بإنشاء ملفين لتنظيم الكود الخاص بك:

  • Product.h: قم بتعريف فئة Product التي تدير المنتجات الفردية مع تتبع البيانات على مستوى المخزون بالكامل. يجب أن تحتوي الفئة الخاصة بك على:
    • أعضاء مثيلة (Instance members): name (string) و price (double) — فريدة لكل منتج.
    • عضو ساكن (static member) باسم totalProducts يقوم بعدّ عدد المنتجات الموجودة حالياً.
    • عضو ساكن (static member) باسم totalValue يتتبع السعر الإجمالي لجميع المنتجات.
    • منشئ (constructor) يأخذ الاسم والسعر، ويقوم بتهيئة الأعضاء المثيلة، وتحديث كلا العدادين الساكنين (زيادة العدد، وإضافة السعر إلى القيمة الإجمالية).
    • مدمر (destructor) يقوم بتحديث العدادات الساكنة عند إزالة منتج (إنقاص العدد، وطرح السعر من القيمة الإجمالية).
    • دالة getInfo() تعيد سلسلة نصية بالتنسيق التالي: "<name>: "<name>: $<price>"lt;price>"
    • دالة ساكنة (static method) باسم getInventoryStats() تعيد سلسلة نصية: "Products: <count>, Total Value: "Products: <count>, Total Value: $<value>"lt;value>"
  • main.cpp: وضح كيف يتم مشاركة الأعضاء الساكنة بين جميع الكائنات بينما تظل الأعضاء المثيلة فريدة. اقرأ اسمين لمنتجين وأسعارهما من المدخلات (name1، price1، name2، price2 — كل منها في سطر منفصل)، ثم:
    • اطبع إحصائيات المخزون الأولية باستخدام اسم الفئة: Product::getInventoryStats()
    • أنشئ كتلة نطاق (scope block) باستخدام الأقواس المتعرجة وداخلها أنشئ كائن Product بالاسم والسعر الأولين. اطبع معلوماته وإحصائيات المخزون الحالية.
    • بعد انتهاء الكتلة (تدمير المنتج الأول)، اطبع "After first scope:" متبوعة بإحصائيات المخزون.
    • أنشئ كائن Product آخر بالاسم والسعر الثانيين. اطبع معلوماته وإحصائيات المخزون.
    • أنشئ كائناً ثالثاً Product بالاسم "Bonus" والسعر 5.00. اطبع إحصائيات المخزون النهائية.

تذكر تعريف أعضائك الساكنة خارج الفئة في ملف الترويسة (بعد تعريف الفئة). قم بتنسيق الأسعار بمنزلتين عشريتين باستخدام std::fixed و std::setprecision(2) من مكتبة <iomanip>.

قم بتضمين ملف الترويسة الخاص بك في main.cpp باستخدام #include "Product.h".

ورقة مرجعية

تدعم لغة C++ نوعين من أعضاء الفئة: أعضاء النسخة (instance members) و الأعضاء الساكنة (static members).

أعضاء النسخة فريدة لكل كائن - فكل نسخة تمتلك نسختها الخاصة:

class Player {
    std::string name;  // كل لاعب لديه اسمه الخاص
    int health;        // كل لاعب لديه صحته الخاصة
};

الأعضاء الساكنة مشتركة بين جميع كائنات الفئة - توجد نسخة واحدة فقط تنتمي إلى الفئة نفسها:

class Player {
    static int playerCount;  // مشترك بين جميع اللاعبين
    
public:
    Player(std::string n) : name(n), health(100) {
        playerCount++;  // زيادة العداد المشترك
    }
    
    ~Player() {
        playerCount--;  // الإنقاص عند التدمير
    }
};

الاختلافات الرئيسية:

أعضاء النسخةالأعضاء الساكنة
فريدة لكل كائنمشتركة بين جميع الكائنات
تُنشأ عند إنشاء الكائنتوجد قبل إنشاء أي كائن
يتم الوصول إليها عبر الكائن: player.healthيتم الوصول إليها عبر الفئة: Player::playerCount

يمكن استدعاء الدوال الساكنة (Static methods) باستخدام اسم الفئة، ويمكنها فقط الوصول إلى الأعضاء الساكنة:

class Player {
    static int playerCount;
    
public:
    static int getPlayerCount() {
        return playerCount;  // يمكنها فقط الوصول إلى الأعضاء الساكنة
    }
};

// الاستدعاء باستخدام اسم الفئة
int count = Player::getPlayerCount();

يجب تعريف الأعضاء الساكنة خارج الفئة (عادةً في ملف .cpp أو بعد تعريف الفئة في ملف الترويسة header):

int Player::playerCount = 0;

الأعضاء الساكنة مفيدة للعدادات، أو قيم الإعدادات المشتركة، أو أي بيانات تنتمي منطقياً إلى الفئة بدلاً من الكائنات الفردية.

جرّب بنفسك

#include <iostream>
#include <string>
#include "Product.h"

using namespace std;

int main() {
    // قراءة المدخلات
    string name1;
    double price1;
    string name2;
    double price2;
    
    getline(cin, name1);
    cin >> price1;
    cin.ignore();
    getline(cin, name2);
    cin >> price2;
    
    // TODO: اطبع إحصائيات المخزون الأولية باستخدام Product::getInventoryStats()
    
    // TODO: قم بإنشاء نطاق (scope block) باستخدام الأقواس المتعرجة
    // داخل النطاق:
    //   - قم بإنشاء Product باستخدام name1 و price1
    //   - اطبع معلوماته باستخدام getInfo()
    //   - اطبع إحصائيات المخزون الحالية
    
    // TODO: بعد انتهاء النطاق، اطبع "After first scope:"
    // ثم اطبع إحصائيات المخزون
    
    // TODO: قم بإنشاء Product آخر باستخدام name2 و price2
    // اطبع معلوماته وإحصائيات المخزون
    
    // TODO: قم بإنشاء Product ثالث باسم "Bonus" وسعر 5.00
    // اطبع إحصائيات المخزون النهائية
    
    return 0;
}
quiz iconاختبر نفسك

يتضمن هذا الدرس اختبارًا قصيرًا. ابدأ الدرس للإجابة عليه وتتبّع تقدمك.

جميع دروس Object Oriented Programming