عندما نلقي نظرة على الشيفرة المرفقة، نجد أنها تتعلق بلغة البرمجة C++ والتفاعل بين مُنشئات الكائنات (Constructors). في هذا السياق، يشير الكود إلى استخدام مُنشئات الكائنات لهيكل بيانات من نوع Foo
، والذي يحتوي على ثلاثة مُنشئات.
أولًا وقبل كل شيء، يتم إنشاء هيكل بيانات Foo
الذي يحتوي على مُنشئ افتراضي (default constructor
) ومُنشئ يستخدم initializer_list
ومُنشئ آخر للنسخ (copy constructor
). عند تشغيل البرنامج، يتم إنشاء كائن a
باستخدام المُنشئ الافتراضي، وهو ما يفسر ظهور “default ctor” في الإخراج.
-
تضمين رموز HTML في CSS: تحديات ونصائح05/02/2024
-
تخصيص تنسيق الشهور في d3.js12/04/2024
-
كيفية إنشاء نماذج اتصال آمنة06/04/2024
ثم يأتي التحدي الأكبر، عند إنشاء كائن b
باستخدام المُنشئ للنسخ (copy constructor
). وهنا تظهر “copy ctor” في الإخراج. وهذا يحدث لأن الكائن b
يتم إنشاؤه باستنساخ الكائن a
، وهو ما يعكس استخدام المُنشئ للنسخ.
النقطة المثيرة للاهتمام تظهر عند إنشاء كائن c
باستخدام initializer_list
، وهو الجزء الذي أثار استفسارك. على الرغم من أنك تتوقع أن يتم استدعاء المُنشئ الذي يستخدم initializer_list
، يظهر في الإخراج “copy ctor”. هذا يحدث لأن اللغة C++ تفضل استخدام المُنشئ للنسخ (copy constructor
) عند استخدام القوسين المعكوسين {}
لإعطاء قيمة ابتدائية للكائن.
في هذا السياق، تعتبر القوسين المعكوسين {}
غالبًا تعبيرًا عن استخدام المُنشئ للنسخ (copy constructor
) أو المُنشئ الذي يأخذ معاملات initializer_list
، ولكن في حالة هيكل البيانات Foo
، يتم اختيار المُنشئ للنسخ.
لتحقيق ما تريد، يمكنك إلزام استخدام المُنشئ الذي يستخدم initializer_list
عن طريق تعديل الكود كما يلي:
cppFoo c{b}; // ستستدعي المُنشئ الذي يستخدم initializer_list
في هذا التعديل، يتم توضيح الاستخدام المباشر للمُنشئ الذي يستخدم initializer_list
، وستظهر “initializer list” في الإخراج.
بهذا، نفهم أن تفضيل استخدام المُنشئ للنسخ (copy constructor
) في حالات القوسين المعكوسين {}
قد يؤدي إلى تفاجئ المبرمجين، ويجعل من الضروري توضيح النية بوضوح في الشيفرة.
المزيد من المعلومات
في سياق لغة البرمجة C++، يُشكل فهم التفاعل بين مُنشئات الكائنات وطرق استدعائها جزءًا أساسيًا من فهم كيفية عمل البرنامج. لنوسّع فهمنا، يمكننا النظر إلى النقاط التالية:
-
المُنشئ الافتراضي (Default Constructor):
في الشيفرة المقدمة، يوجد مُنشئ افتراضي لهيكل البياناتFoo
. يتم استدعاؤه عند إنشاء كائن جديد بدون تحديد للقيم. في حالتنا، يتم استخدامه عند إنشاء الكائنa
. -
مُنشئ النسخ (Copy Constructor):
عندما يتم إنشاء كائن جديد باستخدام قيمة من كائن موجود، يتم استدعاء مُنشئ النسخ. في الشيفرة، تم استخدام مُنشئ النسخ عند إنشاء الكائنb
باستخدام الكائنa
. -
مُنشئ
initializer_list
:
هذا المُنشئ يستخدم لتهيئة الكائن باستخدام قوائم المُبادلة (initializer lists). وفي الشيفرة، يتم تجاوز استخدامه عند إنشاء الكائنc
باستخدام القوسين المعكوسين{}
، حيث يتم فضل استخدام مُنشئ النسخ في هذه الحالة. -
تأثير القوسين المعكوسين
{}
:
في C++، قد تؤدي استخدام القوسين المعكوسين{}
إلى استدعاء المُنشئ الذي يفضله اللغة، سواء كان مُنشئ النسخ أو مُنشئinitializer_list
، وهذا يعتمد على سياق الاستخدام وتوافق النوع. -
توضيح النية:
حينما يواجه المبرمج تداخلًا في اختيار المُنشئ، يمكنه توضيح النية عن طريق استخدام القوسين المستديرين()
لاستدعاء المُنشئ المرغوب بشكل واضح. -
التعامل مع الهياكل المعقدة:
في بعض الحالات، عندما تكون الهياكل البيانية أكثر تعقيدًا، قد يكون من الأفضل تحديد بشكل صريح أي مُنشئ يجب استخدامه في كل حالة. -
النصائح الإضافية:
قد يكون من المفيد استخدام النمط المُبادل (= default
) لتحديد المُنشئات الافتراضية بشكل واضح، وهذا يجعل التصريحات أكثر صراحة ووضوحًا.
فهم العلاقة بين هذه المفاهيم يُسهم في كتابة كود C++ فعّال وصيانة أسهل، ويسهم في تجنب المفاجآت غير المتوقعة في سلوك البرنامج.