📘 قراءة كتاب البرمجة الهدفية بلغة سي++c أونلاين
برمجة هدفية التوجه بلغة ++C
ترجمة وإعداد:أ.فھد أحمد آل قاسم
fhdalqasem@yahoo.com
الجزء اكبر مأخوذ من كتاب :
(Introduction To Object Oriented Programming In C++)
BPB PUBLICATION من منشوراتYashavant Kanetkar لمؤلفه
OBJECT ORIENTED PRORAMMING IN C++ 2
-١ -
الفئات والكائنات )(: Class & Object
مقدمة:
يعتبر مفھوم الفئة classواحدا من أفضل ميزات لغة سي++ )++ (Cالتي لم تكن موجودة في لغة ) ،(Cالفئة ھي
مجموعة من البيانات Dataوالدوال ) (Functionsالتي تعمل على ھذه البيانات، أما الكائن ) (objectفھو تطبيق
محجوز في الذاكرة يستخدم وفقا لتعريف الفئة النوع .
في لغة سي ++ )++ 2(Cيوجد فرق عملي بين التركيبات ) (structuresوالفئات ) ،(classesخاصة بعد قابلية
التركيبات 5حتواء دوال ) (Functionsضمن متغيراتھا كإضافة جديدة للغة سي ++ )++(Cعلى لغة سي ) ،(Cولذلك
فبإمكان ك 8منھما ا5ستخدام تبادليا، لكن معظم مبرمجي لغة سي ++))++ ((Cيستخدمون التركيبات من أجل إحتواء
البيانات فقط )كما كانت عليه في لغة سي ،(Cويستخدمون الفئات للتعامل مع ك 8من البيانات والدوال.
(Declaration of Class) التصريح عن فئة
التصريح عن الفئة يحدد أعضاءھا من دوال وبيانات، كما يقوم بتحديد المدى) (Member Scopeلكل عضو من
أعضاء الفئة الشكل العام للتصريح عن الفئة كالتالي:
class class_name
{
private:
DataMembers declaration;
FunctionMembers declaration;
public:
DataMembers declaration;
FunctionMembers declaration;
};
إن الكلمة المحجوزة ) (classتخبر المترجم) (Compilerأن ما يليھا ھو إسم فئة ومابعده ھو تصريحات أعضاء
تلك الفئة، وكما ھو الحال مع التركيب فإن التصريح عن ا2عضاء يحاط بحاصرتين وينتھي بفاصلة منقوطة.
أعضاء الفئة ) :(class membersھي المكونات ذات ا2نواع المعروفة التي يتم التصريح عنھا في جسم الفئة،
وھي إما بيانات ) (Dataاو دوال ) ،(Functionsبعض المؤلفين يسمون الدالة الخاصة بالفئة او الكائن بالطريقة
) ،(methodبينما سنقوم ھنا بتسمية البيانات التابعة لفئة بأعضاء البيانات) (Data Membersوالتابعة لفئة باCعضاء
.(Member functions) الدوال
أما الكلمتين المحجوزيتين )(privateو) (publicفھما وسيلة البرمجة الھدفية في تغليف الكائن والفئة
) (Encapsulationأو ما يسمى بإخفاء البيانات ) ،(data hidingوھما مصطلحان يقصد بھما عملية أمنية البيانات
وجعلھا حصرية في النطاق المطلوب، فاCعضاء )من بيانات ودوال (التي تأتي بعد الكلمة ) (privateتكون أعضاء
حصرية لDستخدام على مستوى الفئة وأعضائھا من بيانات ودوال أيظا، أما الكلمة المحجوزة ) (publicفتعني ان
OBJECT ORIENTED PRORAMMING IN C++ 3
اCعضاء التالية غير حصرية ا2ستخدام، أي ان مدى ا5ستخدام والتعامل ) (scopeمدى عام، سواء على مستوى الدالة
الرئيسية ) (Mainأو الفئات ا2خرى، إن الوضع التلقائي ھو الوضع الخاص المحلي ) (privateبالنسبة لمحتوى الفئة.
واIن لنرى بناء جملة تحتوي على فئة في المثال التالي:
class rectangle
{ private:
int len,br;
public:
void getdata();
void setdata(int I,int b);
void displaydata( );
void area_peri( );
};
لقد أنشأنا اIن نوع بيانات جديد إسمه ) ،(RECTANGLEيتكون نوع البيانات الجديد ھذا من ستة أعضاء،
عضوي البيانات )(brو) (lenوھما من النوع العددي الصحيح، وأربعة أعضاء كلھا إجراءات، كتبت التصريحات
الخاصة بھا ولم يتم تسجيل التعريف الخاص بعمل كل واحدة.
سنقوم فيما بعد بكتابة محتوى كل واحدة من ا5جراءات/الدوال المصرح عنھا في جسم الفئة) ،(class bodyمن
الم8حظ ان الدوال جميعھا معرفة في خانة اCنواع العامة) ،(publicبينما المتغيرات )البيانات( معرفة في جانب النوع
ذي المدى الحصري على مستوى الفئة) ،(privateوھذه ھي العادة الغالبة على مستخدمي البرمجة الھدفية، إذ ان
المطلوب في الغالب ھو كتابة أعضاء دوال تنفذ خارجيا وبيانات تستخدمھا ھذه الدوال .
وھذا 2يعني ان ھناك قواعد تحتم كون البيانات اCعضاء في الفئة ذات مدى محلي، والدوال اCعضاء ذات مدى
عام، إذ يمكن للمبرمج في أحيان أخرى التصريح عن أعضاء خاصة/محلية وبيانات عامة أو عن بيانات ودوال عامة
حسب رغبة المبرمج.
إنشاء مثال/متغير عن الفئة ):(class instance
إن نوع البيانات ) (floatمث ً8يعرف طريقة معينة للتعامل مع البيانات التي من ذلك النوع، ولو عرفنا متغيرا y
من ذلك النوع Cستخدمنا الجملة :
Float y;
في ھذه الجملة ندعو المتغير yبأنه مثال للنوع floatيحجز موقعا في الذاكرة بذات مواصفات ذلك النوع
)المسجلة مسبقا(، بنفس الطريقة نقوم بتعريف مثال ) (instanceللفئة التي نرغب بتعريف مثال عنھا، مث ً8نقوم
بتعريف مثال عن الفئة السابقة )فئة نوع البيانات( المعرف أع8ه با5سم ) ،(rectangleوذلك بنفس الطريقة:
rectangle r1,r2;
إننا بھذه الجملة قد عرفنا )متغيرين r1و (r2من النوع ) ،(rectangleوكل متغير ھو مثال عن الفئة المعرفة
أع8ه، أي أننا نعرف كائن يقوم بنفس الدور المرسوم له في تعريف الفئة ) ،(rectangleوھي طريقة مشابھة للتصريح
عن متغير كما تعودنا في المتغيرات ا2ساسية للغة ++ ،cولكن الفارق ھنا ان نوع البيانات معرف عن طريق المستخدم
نفسه.
عندما نعرف متغير من نوع صحيح مث ،8فإنه يحجز في الذاكرة حيزا يسع ٢بايت من البيانات )يعتمد حجم نوع
البيانات المحجوز على المترجم ونظام التشغيل المستخدم، ولنتذكر الدالة )( ،(sizeofوھذا يعني بنفس الطريقة انه عند
تعريف كائن objectفإنه يقوم بحجز حيز من الذاكرة، في حالة الكائن r1مث 8فإن الحيز من الذاكرة يساوي مجموع
ا2نواع القياسية المعرفة في التصريح العام عن الفئة، وعند تعريف الكائن اIخر r2فإنه يتم حجز مساحة مشابھة تماما
للكائن السابق بنفس الطريقة.
OBJECT ORIENTED PRORAMMING IN C++ 4
من المھم التأكيد على ان التصريح عن فئة 2 classيؤدي لحجز اي نطاق فعلي في الذاكرة، وأن ذلك يحدث فقط
عند تعريف كائن) (instance objectمن تلك الفئة.
(: Accessing class members)الوصول إلى أعضاء الفئة
إذا كان عضو الفئة من النطاق المحلي ،privateفإننا 2نستطيع الوصول إليه على مستوى الدالة الرئيسة
)( ،mainإن ا2عضاء المحلية تكون قابلة الوصول لديھا متاحة فقط على مستوى تعريف الفئة، فDسناد قيم أو إط8ق
قيم Cعضاء محلية )بيانات كانت او دوال ( فإننا نستخدم الدوال الخاصة بالفئة نفسھا.
و5ستخدام دالة عضو في كائن نستخدم إسم الكائن ملحوقا بنقطة dotثم إسم ذلك الدالة ))((object.function
كما ھو موضح في المثال التالي بخصوص الكائن :r1
r1.setdata(10,20); r2.setdata(4,5);
إن المتغيرين brو lenيحجزان موقعين في الذاكرة كمتغيرين صحيحين مرة ضمن الكائن r1ومرة ضمن الكائن
r2حسب الشكل التالي:
تعريف )اCعضاء الدوال ( للفئة:
با5مكان تعريف وكتابة محتوى العضو الدالة في الفئة إما ضمن الحاصرتين في الفئة نفسھا أو خارج حاصرتي
الفئة حسب ما سوف توضحه اCمثلة التالية، لنعد لمثال المستطيل السابق، ولنعرف محتوى الدوال التي فيه ضمن
حاصرتي الفئة ليكون شكل التصريح عن الفئة كالتالي :
Class rectangle
{
private:
int len,br;
public:
void getdata()
{
cout< cin>>len>>br;
}
void setdata(int I,int b)
{
len=I;
br=b;
}
void displaydata()
{
cout< cout< }
void area_peri()
r1 r2
Len br
10 20
Len br
4 5
OBJECT ORIENTED PRORAMMING IN C++ 5
{
Int a,p;
a=len*br;
p=2*(len+br);
cout< cout< }
};
ولكتابة الدوال خارج حاصرتي الفئة فإننا نستخدم المؤثر :: ھذا المؤثر يعني أن الدالة على يساره ھو عضو في
الفئة المذكورة قبله على الصورة:
Return-type calss_name::function_name(argument lis)
{
…..function body…..
}
حيث أن Return-typeتعني نوع البيانات الذي يعيده الدالة ) voidأو intأو charأو غيره من ...(
calss_nameإسم الفئة التي ينتمي إليھا الدالة
:: المؤثر المذكور
function_nameإسم ال ةدال المقصود كتابة محتواه.
argument lisقائمة المتغيرات المدخلة ضمن الدالة )إن وجدت.(
تمرين :
أعد كتابة المثال السابق بطريقة تعريف الدوال خارج حاصرتي الفئة، مع أخذ الم8حظة رقم ١أدناه با5عتبار.
م8حظات :
.١من أجل كتابة الدالة خارج حاصرتي التصريح عن الفئة ،class declarationيجب كتابة تصريحات عن
الدوال اCعضاء ضمن إطار التصريح عن الفئة كما ھو موضح في أو مثال عن الفئات.
.٢الدوال أو الدوال المعرفة في الفئة ضمن الحاصرتين ھي من النوع ) ،(inlineأما الدوال المعرفة خارج إطار
حاصرتي الفئة فليست من النوع ،inlineولكي يتم تعريفھا كدوال من تلك الصفة، يتم كتابة الكلمة المحجوزة inline
قبل تعريف الدالة فيصبح الشكل العام أع8ه كالتالي:
Inline Return-type calss_name::function_name(argument lis) {}
ما ھي الدوال من النوع inline؟
.٣من المفيد جدا تعريف الدوال خارج إطار حاصرتي الفئة وذلك في حالة الفئات الكبيرة، إذ انه يتم عادة كتابة
تصريحات الفئة ضمن ملف رأسي )) (headfile(*.hويتم كتابة محتوى الدوال )التعريف( ضمن ملفات مصدرية
) (*.cppوذلك عند تأسيس المكتبات librariesالمحتوية على عدد كبير من الفئات.
.٤الفئة المحلية ) (local classھي الفئة التي يتم التصريح عنھا داخل الدالة الرئيس ) ،(mian functionو2
يصح في حالة التصريح عن فئة محلية أن يتم التصريح عن الدوال ا2عضاء فقط من أجل التعريف خارج جسم الفئة.
الكائنات والدوال :
كما درسنا في الدوال ،functionsفإننا نعلم انھا مجموعة أوامر يكتبھا المستخدم، وتقبل مجموعة من
المتغيرات، وتقوم بتنفيذ مجموعة اCوامر تلك، ثم تعيد) (returnمجموعة من المتغيرات الناتجة.
نحن نعلم ان بعض الدوال 2تقبل متغيرات، كما أنه با5مكان أن 2تعيد بعض الدوال اي متغير، إن تعامل
الكائنات مع ھذه الدوال يعتمد على مدى العضو ) (scope of the memberالمستخدم.
OBJECT ORIENTED PRORAMMING IN C++ 6
أما بخصوص الدوال التي تقبل أو تعيد متغيرات، فھي تتعامل مع الكائنات .. ولكن كيف؟
تمرير كائن كمتغير في دالة:
كما ھو الحال مع المتغيرات في ا2نواع القياسية المعروفة، فإن من الممكن تمرير كائن إلى دالة إما بالقيمة ) by
(valueأو بالمرجع ) ،(by referenceفي المثال التالي يقوم البرنامج المكتوب بتعريف فئة ثم القيام بإستخدام دوال
المكتبة ) (string.hفي دمج قيم كائنين من نوع تلك الفئة، )أي قيم عضوي بيانات في كائنين بالطبع :(
#include
#include
Class str
{
private:
char s[50];
public:
void set (char *ss)
{
strcpy(s,ss);
}
void print()
{
cout< }
void concat (str s2)
{
strcat(s,s2.s);
}
};
void main()
{
str s1,s2;
s1.set("hand in");
s2.set("hand");
s1.concat(s2);
s1.print();
}
تحتوي الفئة strعلى متغير محلي ھو عبارة عن سلسلة نصية )مصفوفة محارف ،( array of characters
وعلى ث8ثة دوال تقوم الدالة )( setبقبول سلسلة نصية وخزنھا )بنسخھا( في المتغير المحلي، كما تقوم الدالة )(print
بطباعة محتوى السلسلة النصية، في حين تقوم الدالة )( concatبدمج محتوى تلك السلسلة النصية لھذه الفئة)الكائن
بالطبع( مع سلسلة نصية مشابھة لكائن من نفس نوع الفئة)اي انه يشترط ان يحتوي على سلسلة بنفس ا2سم والنوع.(
OBJECT ORIENTED PRORAMMING IN C++ 7
في الدالة الرئيس )( mainيتم إسناد سلسلة نصية للكائن s1عبر الدالة )( ، setونفس العملية بالنسبة للكائن
s2ثم يتم في السطر الرابع إستخدام الدالة العضو في الكائن s1لتنفيذ عملية دمج السلسلتين في الكائنين، ومن ثم في
السطر الخامس طباعة محتوى السلسلة في الكائن s1بعد الدمج.
نتيجة البرنامج السابق ھي )(. hand in hand
ولكن ما الذي سينتج؟ .. إذا تم إستبدال الكائن s2بالكائن s1في السطرين الرابع والخامس كالتالي:
s2.concat(s1);
s2.print();
م8حظة : 2توجد ع8قة بين الكائن s2المعرف في أول سطر بالدالة الرئيس )( ،mainوالكائن بنفس ا2سم
مال مرر في تعريف الدالة ) ،void concat (str s2حتى لو تم إستخدام نفس المحارف للتسمية، إذ أن الكائن في تصريح
تلك الدالة ھو مجرد كائن وھمي يستخدم )كما ھو الحال في الدوال ( لتوضيح ا5جراءات المستخدمة في حال تم تمرير
كائن من النوع ،strوذلك دون ان يتم إعتباره كائنا فعليا، بينما الكائن s2المستخدم في الدالة الرئيس ھو كائن حقيقي
من النوع .str
تمرير مصفوفة كائنات كمتغيرات في دالة:
بالتأكيد كما في التركيب نستطيع إنشاء مصفوفة كائنات، مستخدمين نفس طريقة بناء الجملة في
التصريح عن مصفوفة أعداد صحيحية أو حقيقية) ،(integers or floatsسوف يقوم البرنامج التالي بتعريف
دالة عادية تقبل مصفوفة كائنات ممره إليه:
class sample
{
private:
int i;
public:
void set(int ii)
{
i=ii;
}
void print()
{
cout< }
};
void show(sample *p)//non-memeber function..
{
for (int j=0;j<5;j++)
p[j].print();
}
void main()
{
sample s[5];
int x;
OBJECT ORIENTED PRORAMMING IN C++ 8
for(int j=0;j<5;j++)
{
cin>>x;
s[j].set(x);
}
show(s);
}
++++++++++++++++++++++
OBJECT ORIENTED PRORAMMING IN C++ 9
-٢ -
(Constructors & Destructors) الباني والھادم
مقدمة:
قبل الدخول في تفاصيل الباني والھادم دعونا نتذكر الطرق المختلفة للتصريح عن متغير عادي، تابع CحداCنواع
القياسية المعروفة :
int x;
مث 8المتغير xيحمل قيم مختلفة حسب المترجم compilerالمستخدم، إذا يمكن ان تكون صفرا أو أقل قيم النوع
الصحيح MIN_INTوھذه القيمة أيضا تعتمد على الحيز الذي تحتله ا2عداد الصحيحة في الذاكرة حسب المترجم ونظام
التشغيل المستخدم.
من العادات البرمجية الجيدة عملية إط8ق initializationقيم إبتدائية initial valuesللمتغير، وذلك بإحدى
طريقتين إما بعد التصريح عنه :
int x;
x=5;
أو بنفس عبارة التصريح بأحد طريقتين إما:
int x=5;
أو بطريقة مكافئة :
int x (5);
إن فكرة الباني ھي فكرة مشابھة لما سبق إ 2ان خصوصية الفئات تتطلب مفاھيما أعقد من ذلك بكثير.
دعونا نتأمل ھذا البرنامج البسيط:
#include
class stack
{
private:
int i;
int a[10];
public:
void init()
{
i=0;
}
void push (int d)
{
a[i]=d;
i++;
}
void print()
{
for (int j=0;j cout< }
};
void main()
{
OBJECT ORIENTED PRORAMMING IN C++ 10
stack s;
s.init();
s.push(10);
s.push(20);
s.print();
}
ھذا البرنامج يعرف في المتغيرات العامة ،globalفئة تحت ا5سم ،stackتتكون ھذه الفئة الـ classمن احدى
عشر عضو بيانات كلھا صحيحة )عدد صحيح ومصفوفة من عشرة اعداد(، ويتكون كذلك من مجموعة من اCعضاء
الدوال في ھذه الفئة stackتعمل كالتالي:
ـ : pushتعبئ أعضاء البيانات/عناصر المصفوفة aبالمدخ8ت.
ـ : initيقدم قيمة إبتدائية لعضو البيانات iما تصطلح عليه التسمية با5ط8ق .initialization
ـ : printطباعة عناصر المصفوفة )عضو البيانات في الفئة ،(stackحسب العناصر المدخلة.
إن من المستحسن دائما إعطاء قيمة إبتدائية للعناصر اCعضاء ) (data membersبمجرد تعريف الكائن، وذلك
Cن القيم ا2بتدائية تساعد على استقرار المتغير المحجوز في الذاكرة وسھولة التعامل معه، ھناك دالة عضوة في الفئة
تقدمھا )++ ،(Cتقوم بعمل إط8ق ) (intializationقيم إبتدائية Cعضاء بيانات في الفئة، وذلك بإستدعائھا بعد التصريح
عن الكائن في الدالة الرئيسية، ھكذا:
stack s;
s.init();
إن الدالة ;)( initتقوم بدور الدالة الباني كما سيأتي، مع فارق بسيط ھو أننا ـ في حالة الباني ـ لن نحتاج بعد ذلك
إلى إستدعاء دالة إضافية في الفئة .. إذا يتم تنفيذ الدالة العضوة )دالة الباني ( بمجرد تعريف الكائن .. فالسطرين
السابقين في البرنامج اع8ه، سوف يتم إختصارھما بسطر واحد ھو:
stack s;
وكي نستفيد من ھذه الفكرة في تعديل البرنامج السابق .. نحتاج إلى تعريف دالة باني في جسم الفئة بنفس محتوى
الدالة )(.init
:Declaring and defining constructors التصريح عن الباني وتعريفه
يتم تعريف الباني عن طريق دالة عضوة ) (member functionضمن الفئة ا2صلية بنفس إسمھا كالمثال التالي :
Stack()
{
I=0;
}
في المثال السابق يتم إستبدال الدالة العضوة )( initبالدالة العضوة أع8ه، إن ھذه الدالة )( 2 stackتحتاج إلى
إستدعاء Cنھا تنفذ بشكل طبيعي بمجرد تعريف كائن وحجز موقع له في الذاكرة، وبطبيعة الحال عند تعريف كائن آخر من
نفس الفئة، يتم تنفيذ الدالة العضوة الخاصة به وإط8ق محتواھا.
الدالة السابقة في المثال، تنفذ بمجرد تنفيذ السطر :
stack s;
تكمن أھمية الباني constructorفي عملية ا5ط8ق التلقائي للقيم، الذي يسھل عملية التعامل مع الذاكرة، كما ھو
الحال مع أھمية إط8ق قيم إبتدائية للمتغيرات القياسية فالجملة التالية:
Int x=3; //the same statement like int x (3);
أفضل بكثير ـ كم ذكرنا سابقا ـ من المقطع البرمجي التالي:
Int x;
x=0;
OBJECT ORIENTED PRORAMMING IN C++ 11
ومن ناحية أخرى فإن مبدأ التغليف الذي يساعد على حماية محتويات الفئة يشجع على إستخدام الباني )وكذلك الھادم
كما سيأتي( من أجل مأمونية التعامل مع البيانات ا2عضاء الخاصة بالفئة .. ونذكر أن تطبيق مبدأ التغليف
: يعنيencapsulation
.١حماية أكثر للعناصر اCعضاء.
.٢أخطاء أقل من قبل المبرمج نفسه، أو الفئات اIخرى.
وCن الباني ھو دالة تنفذ بمجرد التصريح عن كائن، فإننا نكون مقيدين بشروط دالة الباني عند التصريح عن كائن
من تلك الفئة، وذلك من جھة كون الدالة تحتاج إلى مدخ8ت )بارميترات( أم .. 2وبعدد المتغيرات المطلوبة ك، ما سيأتي.
ن8حظ أننا نستطيع تعريف الباني خارج إطار تعريف الفئة بالطريقة التي تعلمناھا سابقا وذلك بإستخدام المؤثر )::(
كالتالي:
stack::stack ()
{
I=0;
}
: characteristics of constructer خصائص الباني
(aيعتبر الباني دالة خاصة عضوة في الفئة، تسمح لنا بإط8ق قيم إبتدائية عند التصريح عن
الكائن.
(bيتم إستدعاء دالة الباني تلقائيا )آليا( بمجرد التصريح عن الكائن.
(cبشكل إجباري يتم تسمية الدالة الباني بنفس تسمية الفئة، واي دالة )عضوة في فئة( تحمل إسم
الفئة فھي دالة باني.
2 (dتحمل دالة الباني أي مخرجات، و 2حتى من النوع ،voidكإصط8ح تعريف.
(eالدالة الباني دائما تأخذ المدى ) ... ،publicلماذا؟(.
(fرغم كون دالة الباني 2تحمل اي مخرجات .. إ 2أنھا تأخذ اي نوع من المدخ8ت .. سواء
مدخ8ت صفرية ) ١(zero-argumentsأو مدخ8ت متعددة )مدخل واحد أو أكثر ( -parameterized
. arguments
(gيحق لنا وضع قيم تلقائيا ) (default valueلمدخ8ت دالة الباني، كما تعلمنا بخصوص أي دالة
أخرى.
(hكذلك وكأي دالة أخرى .. يمكن لنا جعل دالة الباني متعددة اCسماء ).(overloading
:order of constructor invocation ترتيب تنفيذ دالة الباني
في وقت التصريح عن كائن يتم في البداية حجز موقع في الذاكرة للكائن نفسه، ومن ثم يبدأ إستدعاء دالة الباني،
ويتم التصريح عن دوال الباني للكائنات العامة ) (gloabal scopeأو ،2وذلك حسب ترتيب التصريح عنھا، البرنامج
التالي يبين بعض ھذه التفاصيل:
#include
class sample
{
private:
Int i;
public:
sample(int ii)
{
I=ii;
Cout< }
١ـ المصطلح zero-argumentsيعني عدم وجود مدخ ت للدالة.
OBJECT ORIENTED PRORAMMING IN C++ 12
};
sample s1 (1);
sample s2(2);
void main()
{
sample s3 (3);
sample s4(4);
};
أما عملية الھدم ) destructedتنفيذ دالة الھادم( فتتم بطريقة معاكسة لعملية البناء، اي يتم البدء من الكائنات
المحلية ثم العامة )سنأتي لمفھوم الھادم 2حقا(.
: types of constructors أنواع دوال الباني
(١الباني التلقائي ) : (default constructorعندما 2نقوم بتعريف دالة باني لفئة ما، مالذي يحصل عند
التصريح عن كائن من نوع تلك الفئة؟، كما حصل معنا في البرامج السابقة.
إن المترجم يقوم بنفسه من تعريف دالة باني )بدون أي محتوى(، تقوم ھذه الدالة بالعمل فور التصريح عن
أي كائن .. إن ھذا النوع من دوال الباني يسمى بدالة الباني التلقائي، وھي دالة بدون مدخ8ت و 2محتوى ..
فقط من الشكل:
Function ()
{}
ولكن عند تعريف أي دالة باني بواسطة المبرمج فإن المترجم 2ينشى دالة الباني التلقائية، سواء كانت دالة
الباني الخاصة بالمستخدم تحتوي على مدخ8ت صفرية ) (zero-argumetnsأو متعددة المدخ8ت
) ،(parameterized-argumentsأو حتى عند إنشاء اكثر من دالة باني بطريقة تعدد ا2سماء
. كما سيأتي٢(overloading)
(٢الباني متعدد المدخ8ت : parameterized
أحيانا نكون في حاجة إلى إط8ق قم إبتدائية مختلفة لكل كائن على حده )من نفس نوع الفئة(، فلو كان لدينا
على سبيل المثال الفئة طالب، وكان الطالب اCول يبدأ بقيمة إبتدائية تشكل درجته في مادة، وكان الكائن
الثاني )الطالب الثاني( يبدأ تصريحه بقيمتين إبتدائيتن ھم درجته في مادة مث 8و قيمة مصروفه اليومي ..
وكان الطالب الثالث 2يحتاج إلى اي قيم إبتدائية.
إننا في ھذه الحالة نحتاج إلى اكثر من دالة باني .. تحتمل كل واحدة عدد مختلف من المدخ8ت حسب الكائن
الذي يستدعيھا كما سيوضحه لنا المثال التالي:
#include "iostream.h"
class sample
{
private :
int i;
float f;
public:
sample()
{
i=0;
f=0.0;
}
٢
ـ يتم ترجمة المصطلح overloadingحرفيا إلى التحميل الزائد، ولكن المفھوم 2يحتمل ھذه الترجمة الحرفية، إذا أن الترجمة المناسبة للمفھوم
ھو إعادة التسمية )أو تعدد اسماء( كنوع من أنوع تعدد ا2شكال ،ploymorphisimكما سنأتي إليه 2حقا.
OBJECT ORIENTED PRORAMMING IN C++ 13
sample(int ii,float ff)
{
i=ii;
f=ff;
}
void print ()
{
cout< }
};
void main()
{
sample s1;
sample s2 (10, 16.78)
}
2حظ عملية تعريف الكائنين s1,s2بطريقتين مختلفتين .. حسب دالة الباني التي يتم إستدعائھا، يسمى
الباني ھنا بالباني متعدد ا2سماء ) ،(overloaded constructorحيث يحمل اكثر من تعريف بنفس ا2سم
والفارق ھنا )كما ھو معروف في الدوال من ھذا النوع( ھو عدد المتغيرات للتمييز بين الباني واIخر عند
ا5ستدعاء.
فالكائن ا2ول s1قام بإستدعاء الباني اCول )( sampleوالكائن الثاني s2قام بإستدعاء الباني الثاني
.sample(int,float)
الفائدة اCخرى من إستخدام الباني متعدد ا2سماء ) ،(overloaded constructorھو تحاشي إط8ق
بعض القيم 2نحتاج إلى إط8قھا في الوقت الحالي .. عند التصريح عن الكائن.
من المھم م8حظة التالي:
.١عند تعريف ـ فقط ـ دالة باني من النوع متعدد المدخ8ت، ف 8يحق لنا عندئذ التصريح عن الكائن بالطريقة
التقليدية ); (sample s1إذ ان تمرير المتغيرات أصبح )في ھذه الحالة( غير إختياري.
في ھذه الحالة ولتجنب الوقوع في الخطأ نقوم بتعريف ھادمين بطريقة تعدد ا2سماء overloaded
،constructorيكون أحدھما بدون مدخ8ت ،zero-argumentsوذلك لتحاشي ھذه المشكلة المتوقعة ..
كما فعلنا في المثال أع8ه.
.٢إن العبارة );) (sample s1 (2تكافئ تماما العبارة ); ، (sample s1=2وأي منھما تستخدم لعملية
التصريح عن كائن يطلق دالة باني بمتغير/مدخل واحد .. كحالة محددة.
: copy constructor ( باني النسخ٣
لنفترض أننا أردنا التصريح عن كائن وبعد مجموعة من العمليات عليه قمنا بنسخ محتوياته )آخر قيم
للبيانات اCعضاء( إلى كائن جديد من نفس النوع.
سوف نستخدم الجملة:
callstype obj1;
……..
…….
classtype obj2=obj1;
وذلك على إفتراض أن الكائن القديم ھو obj1وتم نسخ محتوياته إلى الكائن الجديد .obj2
ولكننا نعلم أن الجملة اCخيرة ); (classtype obj2=obj1ھي عبارة عن إط8ق باني مفترض للفئة
calsstypeتقوم دالة ھذا الباني بإستقبال مدخل واحد من نوع الفئة نفسه، ونسخ محتوياته إلى الكائن
obj2الذي اطلق ھذه الدالة.
ولكن عند تطبيق مثال على البرنامج أع8ه نجد اننا لسنا بحاجة إلى كتابة دالة باني تقوم بھذه العملية، إنھا
دالة باني ھامة يسمى باني النسخ) ،(copy constructorيقوم مترجم لغة ++ Cبتنفيذھا تلقائيا، دون أن
يضطر المبرمج إلى كتابتھا.
OBJECT ORIENTED PRORAMMING IN C++ 14
الفائدة اCخرى من دالة باني النسخ ھي عملية تمرير كائن إلى دالة )أخرى .. سواء كانت عضوة في فئة أو
،(2خاصة إذا كان التمرير بطريقة التمرير بالقيمة ) ،(passing by valueإن التمرير بالقيمة كما نعلم
يقوم بأخذ نسخة من المتغير الممر ، وإجراء العمليات عليه .. في حالة كان المتغير الممر ھو كائن ..فإن
دالة باني النسخ تقوم بعملھا تلقائيا، دون أن يصدع المبرمج دماغه بكتابتھا.
و كذلك عملية إرجاع القيمة من دالة .. ) .. (Return Valueتمر بنفس عمليات النسخ سابقة الذكر.
السؤال اIن :
تمرين: قم بكتابة فئة لنوع طالب، تحتوي على عناصر أعضاء )كالعمر والدرجة مث ،(8وتحتوي على دالة
باني واحدة تقوم بدور دالة باني النسخ وذلك بنسخ محتويات الكائن الحالي إلى كائن جديد.
مساعدة:
الكائن الممرر لدالة باني النسخ يجب ان يكون بطريقة التمرير بالمرجع ).. (passing by reference
لماذا؟
وذلك Cن تمرير الكائن بطريقة التمرير بالقيمة .. يعني .. عمل نسخة من ذلك الكائن .. النسخة نفسھا سوف
تستدعي دالة الباني التل
حجم الكتاب عند التحميل : 255.9 كيلوبايت .
نوع الكتاب : pdf.
عداد القراءة:
اذا اعجبك الكتاب فضلاً اضغط على أعجبني و يمكنك تحميله من هنا:
شكرًا لمساهمتكم
شكراً لمساهمتكم معنا في الإرتقاء بمستوى المكتبة ، يمكنكم االتبليغ عن اخطاء او سوء اختيار للكتب وتصنيفها ومحتواها ، أو كتاب يُمنع نشره ، او محمي بحقوق طبع ونشر ، فضلاً قم بالتبليغ عن الكتاب المُخالف:
قبل تحميل الكتاب ..
يجب ان يتوفر لديكم برنامج تشغيل وقراءة ملفات pdf
يمكن تحميلة من هنا 'http://get.adobe.com/reader/'