ماذا تعني كلمة "ثابت" بالضبط عند الإعلان عن المتغيرات "العالمية" في لغة C++؟

StackOverflow https://stackoverflow.com/questions/3416728

  •  26-09-2019
  •  | 
  •  

سؤال

وهذا توسيع لنطاق أ سؤالي السابق.

ما هو بالضبط "ثابت"، وكيف يتم استخدامه، وما هو الغرض من استخدام "ثابت" عند التعامل مع C++؟

شكرًا.

هل كانت مفيدة؟

المحلول

الكلمة الرئيسية static له معانٍ مختلفة في لغة C++، اعتمادًا على السياق.

عند الإعلان عن دالة حرة أو متغير عام، فهذا يعني أن الوظيفة لن تكون متاحة خارج وحدة الترجمة الفردية هذه:

// test.cpp
static int a = 1;
static void foo() {}

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

// test2.cpp
namespace {
   static int a = 1;
   static void foo() {}
}

عند الإعلان عن متغير محلي داخل دالة، فهذا يعني أن عمر المتغير سيمتد من الاستدعاء الأول للدالة إلى نهاية البرنامج، وليس فقط لمدة الاستدعاء:

int foo() {
   static int counter = 0;
   return ++counter;
}
int main() {
  for ( int i = 0; i < 10; ++i ) { 
     std::cout << foo() << std::endl;
  }
}

في الكود السابق counter تتم التهيئة مرة واحدة عندما foo يتم استدعاؤه للمرة الأولى، لكن المتغير سيستمر بعد انتهاء الدالة وسيحتفظ بالقيمة عبر استدعاءات دوال مختلفة.سيتم طباعة الكود السابق "1 2 3 4...10".إذا لم يتم الإعلان عن المتغير static ثم سيكون الإخراج "1 1 1 ...1".

ضمن نطاق الطبقة، static يعني أن العضو عضو في الفصل وليس في مثيل معين.هذا الاستخدام يعادل الاستخدام في سؤالك الآخر:استخدام هذا العضو المعين غير مرتبط بأي كائن محدد.

struct test {
   int x;
   static int y;
};
int test::y;       // need to define it in one translation unit
int main() {
   // test::x = 5; // !error cannot access a non-static member variable
                   // without an instance
   test::y = 5;    // ok
   test t, other;
   t.x = 10;       // ok
   t.y = 15;       // ok, the standard allows calling a static member through
                   // an instance, but this is the same as test::y
}

وفي هذه الحالة يكون العضو x هي سمة عضو غير ثابت، وعلى هذا النحو هناك مختلفة x لكل مثيل للفئة.في برنامج العينة t.x و other.x الرجوع إلى أعداد صحيحة مختلفة.على الجانب الآخر y يكون static وبالتالي هناك مثيل واحد ل test::y في برنامج.حتى لو كان المعيار يسمح بالاتصال t.y و other.y يشير كلا الاستخدامين إلى نفس المتغير.الشيء نفسه ينطبق على أساليب الأعضاء.إذا كانت ثابتة فهي أساليب على مستوى الفصل ويمكن استدعاؤها بدون مثيل، بينما إذا كانت غير ثابتة يتم تطبيقها على مثيل ملموس و a.b أو a->b يجب استخدام بناء الجملة.

هذا الاستخدام static يشبه استخدام نفس الكلمة الأساسية في Java، بينما لا يوجد الاثنان الآخران في تلك اللغة.هناك استخدام واحد للكلمة الأساسية في Java غير موجود في C++، وهو استخدام مُهيئات الفئة الثابتة (كتلة من التعليمات البرمجية على مستوى الفئة محاطة بـ static { ... }).في Java، سيتم تنفيذ كتلة التعليمات البرمجية هذه عند تحميل الفصل ولمرة واحدة فقط.يجب أن تتم تهيئة متغيرات الأعضاء الثابتة في C++ في مُهيئ تعريف المتغير.

نصائح أخرى

وهذا يعني أن المتغير محلي إلى وحدة ترجمة (ببساطة ، على ملف مصدر واحد) ، ولا يمكن الوصول إليه من خارجه. في الواقع ، يتم إهمال استخدام ثابت في معيار C ++ الحالي - بدلاً من ذلك من المفترض أن تستخدم مساحات أسماء مجهولة:

static int x = 0;    

يجب ان يكون:

namespace {
    int x = 0;    
}

يبدو أن هذه الأشياء مغطاة بشكل جيد إلى حد ما هنا.

ولكن لإعادة الصياغة ، هناك استخدامان في ج

  1. منع استخدام متغير عالمي خارج نطاق الملف الذي يحدده.
  2. السماح للمتغيرات المحلية ضمن دالة لاستمرار دعوات الوظيفة ، كما في

    int getNextId () {static int id = 0 ؛ إرجاع معرف ++ ؛ }

يرث C ++ كلاهما ، ويضيف استخدامين خاصين به.

  1. متغيرات الأعضاء الثابتة: المتغيرات التي "مشتركة" تراكم جميع حالات الفصل ، ويمكن أيضًا الوصول إليها دون الرجوع إلى مثيل الفصل. يبدو مشترك الكلمة الخاطئة ، لكنني في جوهرها أعتقد أن النتيجة هي أن أي إشارة إلى متغير عضو ثابت يشير إلى موقع الذاكرة نفسه.
  2. الطرق الثابتة: الطرق التي يمكن استدعاؤها دون الرجوع إلى مثيل محدد للفئة التي تحدده.

الثابت يعني بشكل أساسي أن المتغير مرتبط بعمر البرنامج وليس لأي وظيفة معينة أو مثيل فئة. متى يجب استخدامه؟ لا. ما هو الغرض؟ تصحيح البيانات ، في الغالب.

بشكل عام ، في C ++ ، إذا وجدت نفسك باستخدام بيانات ثابتة ، فقد قمت بذلك خطأ. هناك أوقات يكون فيها الأمر مناسبًا ، لكنها نادرة جدًا.

عندما يتم استخدام ثابت في فئة في C ++ ، فهذا يعني أكثر أو أقل نفس الشيء الذي يفعله في Java. بالنسبة للمتغيرات ، فهذا يعني وجود مثيل واحد من المتغير لجميع الفئات والوظائف ، فهذا يعني أن الوظيفة لا تصل ضمنيًا إلى هذا المؤشر على الإطلاق.

في C و C ++ عند استخدام ثابت للمتغير أو الدالة العالمية ، فهذا يعني أنه لا يمكن الرجوع إلى المتغير إلا في ملف C أو C ++ الحالي. بمعنى آخر ، يجب ألا يقوم برنامج التحويل البرمجي بإنشاء أي رموز نقل للمتغير أو الدالة.

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

أعضاء الفئة الثابتة هي بيانات ووظائف مرتبطة بالفئة نفسها ، وليس مع كائنات الفصل.

في المثال التالي ، لدى Class Fred عضوًا ثابتًا في البيانات X_ وعضو بيانات مثيل Y_. لا يوجد سوى نسخة واحدة من Fred :: X_ بغض النظر عن عدد كائنات Fred التي يتم إنشاؤها (بما في ذلك عدم وجود كائنات Fred) ، ولكن هناك كائن Y_ لكل فريد. وهكذا يقال إن x_ يرتبط بالفئة ويقال إن y_ يرتبط بكائن فردي للفئة. وبالمثل ، فإن فئة فريد لديها وظيفة عضو ثابت F () ودالة عضو مثيل G ().

class Fred {
    public:
        static void f() throw();                           <-- 1
        void g() throw();                                  <-- 2
    protected:
        static int x_;                                     <-- 3
        int y_;                                            <-- 4
};

(1) وظيفة العضو المرتبطة بالفئة

(2) وظيفة العضو المرتبطة بكائن فردي من الفصل

(3) عضو البيانات المرتبط بالفئة

(4) عضو البيانات المرتبط بكائن فردي من الفصل

الاستخدام:

عندما تريد الاحتفاظ بمساحة عدد حالات الفصل الذي تم إنشاؤه ، فإنك تستخدم متغيرًا ثابتًا. على سبيل المثال في فئة "سيارة" ، قد يكون لكل مثيل سيارة رقم تسلسلي فريد (_y في هذه الحالة) وقد ترغب الشركة في تتبع عدد السيارات المنتجة (_x في هذه الحالة).

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top