المنشئ الافتراضي
جزء من قسم Object Oriented Programming في رحلة C++ على Coddy — الدرس 18 من 104.
إنّ المُنشئ الافتراضي (default constructor) هو مُنشئ يمكن استدعاؤه بدون أي وسائط. يقوم بتهيئة كائن عندما لا يتم توفير قيم أولية. تحتاج كل فئة (class) إلى طريقة لإنشاء كائنات في حالة افتراضية صالحة.
إذا لم تقم بتعريف أي منشئ (constructor)، فإن المترجم (compiler) ينشئ منشئاً افتراضياً ضمنياً لا يفعل شيئاً للأنواع الأولية (primitive types) ويستدعي المنشئات الافتراضية للكائنات الأعضاء (member objects).
class Player {
int health;
int score;
public:
Player() { // المنشئ الافتراضي
health = 100;
score = 0;
}
};
Player p1; // يستدعي المنشئ الافتراضي
Player p2{}; // يستدعي أيضاً المنشئ الافتراضيبمجرد قيامك بتعريف أي منشئ (مثل المنشئ ذو المعاملات - parameterized)، لن يقوم المترجم (compiler) بإنشاء منشئ افتراضي (default constructor) بعد الآن. يجب عليك تعريف واحد صراحةً إذا كنت لا تزال بحاجة إليه.
class Enemy {
int damage;
public:
Enemy(int d) : damage(d) {} // منشئ بمعاملات فقط
};
Enemy e1(10); // يعمل
Enemy e2; // خطأ! لا يوجد منشئ افتراضيفي لغة ++C الحديثة، يمكنك طلب المنشئ الافتراضي الذي يولده المترجم بشكل صريح باستخدام = default:
class Item {
int id;
public:
Item() = default; // المترجم ينشئ المنشئ الافتراضي
Item(int i) : id(i) {}
};تعد المشيدات الافتراضية (Default constructors) ضرورية لإنشاء مصفوفات من الكائنات وللأصناف المستخدمة في الحاويات مثل std::vector، والتي قد تحتاج إلى إنشاء عناصر بدون وسائط.
التحدي
سهللنقم ببناء نظام عداد بسيط يوضح كيف تقوم المُنشئات الافتراضية (default constructors) بتهيئة الكائنات إلى حالة بداية صالحة.
ستقوم بإنشاء ملفين لتنظيم الكود الخاص بك:
Counter.h: قم بتعريف فئةCounterالتي تتبع قيمة العداد. يجب أن تحتوي الفئة الخاصة بك على:- سمة
countخاصة (عدد صحيح) - سمة
nameخاصة (سلسلة نصية) لتحديد العداد - مُنشئ افتراضي يقوم بتهيئة
countإلى0وnameإلى"Unnamed"، ثم يطبع"Counter created: <name>" - طريقة
increment()تزيد العداد بمقدار 1 - طريقة
getCount()ترجع قيمة العداد الحالية - طريقة
getName()ترجع اسم العداد
- سمة
main.cpp: وضح أن المُنشئات الافتراضية تعمل عند إنشاء الكائنات بطرق مختلفة. اقرأ رقماً من المدخلات يشير إلى عدد مرات زيادة العداد، ثم:- قم بإنشاء Counter باستخدام التهيئة المباشرة:
Counter c1; - قم بإنشاء Counter آخر باستخدام تهيئة الأقواس (brace initialization):
Counter c2{}; - قم بزيادة
c1بعدد المرات المحددة في المدخلات - اطبع
"<name>: <count>"لـ c1 - اطبع
"<name>: <count>"لـ c2
- قم بإنشاء Counter باستخدام التهيئة المباشرة:
يجب أن يبدأ كلا العدادين من 0 بفضل المُنشئ الافتراضي الخاص بك، ولكن سيتم زيادة c1 فقط. يوضح هذا كيف تضمن المُنشئات الافتراضية أن يبدأ كل كائن في حالة صالحة ويمكن التنبؤ بها بغض النظر عن كيفية إنشائه.
قم بتضمين ملف الرأس الخاص بك في main.cpp باستخدام #include "Counter.h".
ورقة مرجعية
الـ default constructor (المُنشئ الافتراضي) هو مُنشئ يمكن استدعاؤه بدون أي وسائط (arguments). يقوم بتهيئة الكائن عندما لا يتم توفير قيم أولية.
class Player {
int health;
int score;
public:
Player() { // Default constructor
health = 100;
score = 0;
}
};
Player p1; // Calls default constructor
Player p2{}; // Also calls default constructorإذا لم تقم بتعريف أي مُنشئ، يقوم المترجم (compiler) بإنشاء مُنشئ افتراضي ضمني. ومع ذلك، بمجرد تعريف أي مُنشئ (مثل المُنشئ ذو المعاملات - parameterized constructor)، لن يقوم المترجم بإنشاء مُنشئ افتراضي تلقائياً.
class Enemy {
int damage;
public:
Enemy(int d) : damage(d) {} // Parameterized constructor only
};
Enemy e1(10); // Works
Enemy e2; // Error! No default constructorيمكنك طلب المُنشئ الافتراضي الذي يولده المترجم صراحةً باستخدام = default:
class Item {
int id;
public:
Item() = default; // Compiler generates default constructor
Item(int i) : id(i) {}
};تعد المُنشئات الافتراضية ضرورية لإنشاء مصفوفات من الكائنات وللأصناف (classes) المستخدمة في الحاويات مثل std::vector.
جرّب بنفسك
#include <iostream>
#include "Counter.h"
using namespace std;
int main() {
// اقرأ عدد مرات الزيادة
int n;
cin >> n;
// TODO: أنشئ Counter باستخدام التهيئة المباشرة: Counter c1;
// TODO: أنشئ Counter آخر باستخدام تهيئة الأقواس: Counter c2{};
// TODO: قم بزيادة c1 بعدد المرات المحدد بواسطة n
// TODO: اطبع "<name>: <count>" لـ c1
// TODO: اطبع "<name>: <count>" لـ c2
return 0;
}
يتضمن هذا الدرس اختبارًا قصيرًا. ابدأ الدرس للإجابة عليه وتتبّع تقدمك.
جميع دروس Object Oriented Programming
1أساسيات الـ OOP
الملفات الخارجيةبناء وتجميع (Compilation) لغة C++ملفات الـ Header وملفات الـ Sourceالـ Namespaces والـ Scopeمقدمة في الـ OOP في C++الـ Classes مقابل الـ Objectsالمؤشر 'this'الـ Methods (الدوال الأعضاء)الـ Attributes (بيانات الأعضاء)أساسيات الـ Ctors والـ Dtorsمراجعة - آلة حاسبة بسيطة4خصائص الـ Class
أعضاء الـ Instance مقابل الـ Staticدوال الـ Getters والـ Settersدوال الأعضاء الثابتة (Const)الكلمة المفتاحية Mutableالدوال والمتغيرات الساكنة (Static)الدوال والفئات الصديقة (Friend)مراجعة - مدير الحساب البنكي7الوراثة
الوراثة الأساسيةمستويات الوصول في الوراثةترتيب استدعاء الـ Ctor والـ Dtorإعادة تعريف الدوال (Method Overriding)الدوال الافتراضية والـ VTableالوراثة المتعددةالوراثة الافتراضيةمراجعة - هيكلية الموظفين10نظرة عامة على STL
نظرة عامة وفلسفة STLحاويات STLالـ Iteratorsخوارزميات STLالـ Functors وتعبيرات Lambdaمراجعة - تكرار الكلمات13أنماط التصميم - الجزء الأول
مقدمة في أنماط التصميمنمط Singletonنمط Factory و Abstract Factoryنمط Builderنمط Observerنمط Strategy2إدارة الذاكرة
ذاكرة Stack مقابل Heapالمؤشرات والمراجعالذاكرة الديناميكية (new/delete)المؤشرات الذكية في C++RAII في C++مراجعة - مدير المصفوفات الديناميكية5التغليف (Encapsulation)
محددات الوصول في C++محددات الوصول بشكل متعمقإخفاء المعلوماتStruct مقابل Classالأصناف المتداخلة والداخليةمراجعة - نظام سجلات الطلاب8تعدد الأشكال (Polymorphism)
تعدد الأشكال: وقت التجميع مقابل وقت التشغيلالتحميل الزائد للدوال (Function Overloading)مراجعة الدوال الافتراضية (Virtual Functions)الدوال الافتراضية البحتة (Pure Virtual Functions)الأصناف المجردة (Abstract Classes)تصميم الواجهات (Interface) في C++التحويل الديناميكي (Dynamic Casting) و RTTIملخص - حاسبة الأشكال11مفاهيم OOP المتقدمة
التركيب مقابل الوراثةالـ Mixins عبر CRTPنمط Pimplمحو النوع (Type Erasure)أصناف Enum والأنواع القويةمعالجة الاستثناءات في OOPتسلسلات الاستثناءات المخصصة14أنماط التصميم - الجزء الثاني
نمط الأمرنمط المحولنمط المزيننمط قالب الطريقةنمط الحالةنمط التركيبRAII كنمط3المنشئات والموادم
المنشئ الافتراضيالمنشئ ذو المعاملاتمنشئ النسخمنشئ النقلقوائم تهيئة المنشئالمنشئات المفوضةتعمق في الموادمقاعدة الثلاثة / الخمسة / الصفرمراجعة - فئة String6تحميل العوامل (Operator Overloading)
مقدمة في تحميل العواملتحميل العوامل الحسابيةتحميل عوامل المقارنةعوامل Streamتحميل عامل التعيينتحميل العوامل [] و ()عوامل تحويل النوعمراجعة - Matrix Class9القوالب
قوالب الدوالقوالب الأصنافتخصيص القوالبالقوالب المتغيرةأساسيات SFINAE و Type Traitsمراجعة - الحاويات العامة