AudaNix

دالة بناء الفئة (الجزء الثاني) Constructors -Part II

2 ردود في هذا الموضوع

دالة بناء الفئة (الجزء الثاني)

Constructors (Part II)

دالة بناء خاصة Private constructors

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

class Book
{
private:
int m_nPages;

// دالة البناء هذة يمكن فقط لاعضاء فئة Book استخدامها.
Book() // دالة بناء الفئة الافتراضية الخاصة
{
m_nPages = 0;
}

public:
// دالة بناء الفئة هذة يكمن لاي احد استخدامها
Book(int nPages) // دالة بناء عامة وليست الافتراضية
{
m_nPages = nPages;
}
};
int main()
{
// كود خطأ لان دالة بناء الفئة Book() الافتراضية دالة خاصة Private أى
لايمكن استدعائها من خارج الفئة نفسها
Book cMyBook;
// كود صحيح لان دالة بناء الفئة Book(int) دالة بناء عامة اي يسمح
بأستدعائها من خارج كود الفئة
Book cMyOtherBook(242); //
return 0;
}

مشكلة دوال البناء العامة لايوجد بها اي طريقة للتحكم بعدد عدد الكائنات التي يمكن انشائها من هذة الفئة. لو ان دالة البناء العامة موجودة بالفئة هذا يسمح بانشاء اي عدد من الكائنات من الفئة كما تشاء. فى بعض الاحيان من المفيد ان تسمح فقط بأنشاء كائن واحد فقط من الفئة تسمي هذة بــ الفئة الوحيدة singletons . هناك الكثير من الطرق لكتابة الفئة الوحيدة ولكن اغلبهم يتستخدم دالة البناء الخاصة أو دالة البناء المحمية لكي لايسمح للمستخدمين من انشاء كائنات من الفئة كما يريد.

ربط دوال البناء ومشاكل التحميل اﻻبتدائي Constructor chaining and initialization issues

عند انشاء نسخة كائن جديد يقوم مترجم سي++ بأستدعاء دالة بناء الكائن بشكل صريح. فلنلقي نظرة على حالتين غالبا ما تسبب مشاكل للمبرمجين الجدد:

اوﻻً: احياناً لديك دالة بناء فئة تقوم بنفس عمل دالة بناء اخري باﻻضافة الى عمل آخر بسيط!. ان علمية استدعاء دالة بناء فئة الى دالة بناء فئة اخري تسمي ربط دوال البناء constructor chaining. علما ان سي# تدعم ربط دوال بناء الفئة لكن سي++ ﻻتدعم ذلك. ان حاولت القيام بربط دوال البناء غالبا سوف يتم ترجمتة ولكنة لن يعمل بشكل صحيح. وعلما ان دوال بناء الفئة مسموح لها بأستدعاء دوال اعضاء الفئة التي تعمل بها. فقط كن متأكد من ان الدول اﻻعضاء (وهي الدوال اﻻخرى بخلاف دوال البناء) قد تم تحميلهم بالقيم اﻻبتدائية.

قد تفكر في محاولة نسخ الكود من دالة البناء اﻻولى الى دالة البناء الثانية لحل المشكلة السابقة لكن فكرة تكرار الكود تعمل على صعوبة فهم وصيانة الفئة. الحل اﻻفضل لهذة المشكلة هو انشاء دالة عضو اخري تقوم بالعمل المشترك بين الدوال مثل علميات التحميل اﻻبتدائية للمتغيرات وغيرها ثم تقو باستدعاء هذة الدالة بواسطة دالتي بناء الفئة.

مثال:

class Foo
{
public:
Foo()
{
// أكود للقيام بالمهمة A
}

Foo(int nValue)
{
// أكود للقيام بالمهمة A
// أكواد للقيام بالمهمة B
}
};

تصبح:

class Foo
{
public:
Foo()
{
DoA();
}

Foo(int nValue)
{
DoA();
// أكواد للقيام بالمهمة B
}

void DoA()
{
// أكود للقيام بالمهمة A
}
};

كما تلاحظ فان علميات تكرار الكود تصبح فى ادني حد ممكن لها وﻻ حاجة الى ربط دوال بناء الفئة.

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

class Foo
{
public:
Foo()
{
Init();
}

Foo(int nValue)
{
Init();
// قم بأضافة اكود للتعامل مع nValue
}

void Init()
{
// قم بأضافة اكواد عملية تحميل الفئة بالقيم اﻻبتدائة
}
};

منتشر جدا بين المبرمجين اضافة دالة بأسم Init() لتحميل المتغيرات اﻻعضاء بالقيم اﻻبتدائية ثم تقوم دالة بناء الفئة باستدعاء دالة Init() قبل القيام بأي مهمة . هذا يقلل عملية تكرار الكود ويسمح لك باستدعاء Init() فى الوقت المناسب وكما تشاء.

يوجد تحذير واحد بسيط: كن حذرا عن استخدامك دوال Init() والحجز الديناميكي للذاكرة. ﻻن دوال Init() يمكن ﻷي احداً استدعائها فى اي وقت.أو ان علمية الحجز الديناميكي قد تم حجزها او ﻻ عند استدعائك لــ Init() . ركز فى التحكم فى هذة المشكلة بشكل مناسب قد تكون شئ مربك قليلا. واحذر المؤشرات التى لا تشيرالى شئ non-null لانها قد تشير الى ذاكرة ديناميكية او قد تم الغاء القيمة الابتدائية المسندة اليها.

ﻻحظ: ان سي++11 تدعم ربط دوال البناء عن طريق وظيفة delegating constructors .

تم تعديل بواسطه محمد عودة
0

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه

واصل ...بارك الله فيك ...ووفقك إلى ما يحبه ويرضاه ..

تقبل تحياتي

0

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه

  • يستعرض القسم حالياً   0 members

    لا يوجد أعضاء مسجلين يشاهدون هذه الصفحة .