المعـامل (::) :هـناك معـامل آخر لم نتعرض له وهـو معـامل الوصول إلى المتغيرات العامـة
وهـو :: ، انظر إلى هذا المثال:
int a=10;
void function( )
{ int a= 5 }
كما تلاحـظ فـإن هــناك متغيـر خـاص أو محلـي لـه اسـم a للتـابع function ،
وهــناك أيضـاً متغيـر عـام ، السـي بلـس بلـس تسـمح لـك بفعـل ذلـك ولكـن
المتغيــر العــام ســيتم إســتبعاده أو إخفــاءه وســتكون الأولويـــة فــي التــابع
function للمتغيــرات المحليــة ولــيس للمتغيــرات العامـــة ، وحتــى تســتطيع
الوصول إلى المتغير العام ضمن كتلة التابع function فعليـك أن تقـوم بكتابـة
المعامل :: حتى تصل إليه أنظر لهذا الأمر الذي نفترض أنـه ضمن كتلـة التـابع
: function
cout << ::a ;
لن يقـوم هـذا الأمـر بطباعــة القيمــة الخاصـة بـالمتغير الخـاص بـل بالقيمــة
الخاصـة بالمتغير العام لأننا قمنا بكتابة المعامل :: قبل اسم المتغير.
الوسائط الإفتراضيـة:
أحــد أهــم أهــداف أي برمجــة هــو إعـادة الاسـتخدام ، أي إعـادة اسـتخدام
الاكواد السابقـة وحتى نصل إلى هذا الهـدف فلا بد علينا من جعـل اسـتخدام
هذه الأكواد السابقة بسيطاً للغايـة وبـدون أي تعقيـد ، انظـر مـثلاً للكـائن cin
وكيف أن إستخدامه بسـيط وميسـر وأيضـاً للدالـة ( )printf فـي لغـة السـي
ومدى سهولتها وهذا أيضاً ما نحـاول الوصول إليه من خلال هذا الكتاب.
بإمكاننا تسهيل استخدام أي دالة بواسطـة الوسائط الافتراضيـة (البارامترات
الافتراضية) وهذه الأداة تمكننا من تسـهيل الكــود لدرجـة كبيـرة ، هـل تتـذكر
التابع ( )getline ، هذا التابع يحتـوي علـى ثـلاث بـارمترات ، ولكنـك تسـتطيع
التعامل معـه على أنه يستقبل بارامترين اثنـين وتسـتطيع إذا أردت اسـتخدام
ثلاث بارامترات ، نفس الأمر ينطبق هـنا ، بإمكاننا إنشاء توابـع بتلـك الطريقــة
ووسيلتنا لذلك هـي الوسائط الافتراضية.
سـنقوم الآن بكتابـة مثـال كــودي وهـذه المـرة سـيقوم هـذا المثـال بحسـاب
النسـبة المئويــة ، حيـث أنــه سـيقوم بحسـاب النسـبة مـن 100 افتراضــياً ،
وبإمكان المستخدم حساب النسبة من 100 أو أي رقم آخر يريده.
1. float rate(float a,float b ,float c=100)
2. {
3. float j=0;
4. j= (a*c)/b;
5. return j;
6. }
انظر إلى السطر الأول تجـد أن البارامتر الثالث غريب بعض الشيء حيث قمنا
باسناد البارامتر إلـى القيمــة 100 ، وبـذلك سـيكون بإمكانـك اسـتخدام هـذه
القيمـة افتراضياً ، بإمكانك استدعاء هذا التابع بهذا الشكل:
rate ( 50 , 100)
أو بهذا الشكل إن أردت:
rate ( 20, 100 , 1000)
والفـرق بـين الاسـتدعائين أن البـارامتر الثالـث للتـابع المسـتدعى الأول هــو
سيكون افتراضياً بقيمـة 100 ، أمـا التـابع الثالـث فلقـد أراد المسـتخدم تغييـر
هذه القيمـة وبالتالي فلقد قام البرنـامج باسـتبعاد القيمـة الافتراضـية ووضـع
القيمة التي قام المستخدم بوضعها.
سنرى الآن كيف سيكون استخدامنا لهذا التابع فـي وسـط برنـامج حقيقـي ،
عليـك أن تعلـم أن القيمــة الافتراضــية لا تكتـب أبـداً فـي رأس التـابع إلا فـي
النموذج المصغر فقط ، أما تعريف التابع فلا تقم بكتابة القيمـة الافتراضـية وإلا
فـإن المتـرجم سيصـدر خــطأ ، انظــر لهـذا المثـال ، وكيـف تـم تطبيـق الكـلام
الحالي:
CODE
1. #include <iostream>
2. using namespace std;
3.
4.
5. float rate (float a,float b,float c=100);
6.
7. void main()
8. {
9. float i,j,k,avg;
10. cout << "Please Enter the number?\n";
11. cin >> i;
12. cout << "from:\t";
13. cin >> j;
14. cout << "the Avrege:";
15. cin >> avg;
16.
17. k=rate (i ,j,avg);
18. cout << endl << k << endl;
19.
20. }
21.
22. float rate(float a,float b ,float c)
23. {
24. float j=0;
25. j= (a*c)/b;
26. return j;
27. }
قارن بين رأس التابع في السطر 22 والنموذج المصـغر للتـابع فـي السـطر 5
تستنتج أن النمـوذج المصـغر بإمكانـه الاحتـواء علـى قـيم افتراضـية أمـا رأس
التابع أو تعريف التابع فليس بإمكانـه الاحتـواء على أي قيمـة افتراضية.
إعادة أكثر من قيمـة بواسطـة المؤشرات أو المرجعيات:
الآن سنأتي إلى التطبيق الفعلي للمؤشرات ؛ هل تتـذكر التوابـع ألـيس فـي
نهايـة كل تابع مالم يكـن void العبارة التاليـة: return (Value);
حيث value القيمة المعادة.
كما ترى فإن جميع الدوال أو الإجراءات لا تعـود إلا بقيمـة واحـدة ولا تسـتطيع
العـودة بأكثر من قيـمـة ، الآن سنفكر بطريقـة تمكننا من جعـل التوابـع تعــود
بأكثر من قيمـة.
ما رأيك الآن بدلاً من أن نمرر للتوابع القـيم أن نمـرر لهـا عــناوين تلـك القيــم ؛
سنكتب برنامج هذا البرنامج يحــوي تابعـان التـابع main وتـابع آخـر سـنطلق
عليه plus سيعــيد هـذا الإجـراء قيمتـين وسـيقوم الإجـراء main بطباعتهــما
وليس التابع plus .
1 #include < iostream.h>
2 void plus (int num1,int num2,int *plus1,int *plus2)
3 {
4 *plus1=num1 + num2;
5 *plus2=num1*num2;
6 }
78
void mian ( )
9 {
10 int num1,num2,plus1,plus2;
11 plus (num1,num2, &plus1 , & plus2);
12 cout << plus1 << endl;
13 cout << plus2 << endl;
14 }
الآن وكما ترى فإن قيم plus1 و plus2 ستؤدي المطلـوب منهـا حيـث plus1
يجمع عـددان و plus2 يضـرب عـددان بالرغــم مـن أن المعالجــة لا تتــم فـي
التابع ()main بل فـي التـابع plus وكمـا تلاحـظ فـإن التـابع plus لا يعــود أي
قيمـة لأنه void ؛ كما تلاحظ أعـلنا عـن عددان مهيئان مسبقاً وعددان لم يهيئا
في السطر العاشر ؛ بعـد ذلـك قمنـا بتمريـر قيمــة العــددان num1 و num2
إلى الإجراء plus أما بالنسبة للعــددان الآخـران فلـم نمـرر قيمهــما بـل مررنـا
عـناوين تلك القيـم كما هـو واضح من السطر الحادي عشر ؛ كما درسـنا فـي
هذا الموضوع (موضوع التوابع) أنهـا تنشأ نسخ مـن المتغيـرات الممـررة إليهـا
أما في هذه الحالة فهي لم تقوم بإنشاء نسخــة بـل أخـذت النسـخ الأصليــة
من تلـك المتغيـرات وهــي عــناوينها ... الآن يتفـرع البرنـامج إلـى التـابع plus
والذي عرفناه في السطر الثاني وكما تلاحظ فهــو يحتــوي عـددان مـن نــوع
int ومتغيران آخران لكن مؤشرات هـذه المـرة وليسـا متغيـرات عاديــة .. هـل
تعرف لماذا .. كما تلاحـظ فلقـد مررنـا عــناوين تلـك المتغيـرات ؛ البرنـامج الآن
وهـو :: ، انظر إلى هذا المثال:
int a=10;
void function( )
{ int a= 5 }
كما تلاحـظ فـإن هــناك متغيـر خـاص أو محلـي لـه اسـم a للتـابع function ،
وهــناك أيضـاً متغيـر عـام ، السـي بلـس بلـس تسـمح لـك بفعـل ذلـك ولكـن
المتغيــر العــام ســيتم إســتبعاده أو إخفــاءه وســتكون الأولويـــة فــي التــابع
function للمتغيــرات المحليــة ولــيس للمتغيــرات العامـــة ، وحتــى تســتطيع
الوصول إلى المتغير العام ضمن كتلة التابع function فعليـك أن تقـوم بكتابـة
المعامل :: حتى تصل إليه أنظر لهذا الأمر الذي نفترض أنـه ضمن كتلـة التـابع
: function
cout << ::a ;
لن يقـوم هـذا الأمـر بطباعــة القيمــة الخاصـة بـالمتغير الخـاص بـل بالقيمــة
الخاصـة بالمتغير العام لأننا قمنا بكتابة المعامل :: قبل اسم المتغير.
الوسائط الإفتراضيـة:
أحــد أهــم أهــداف أي برمجــة هــو إعـادة الاسـتخدام ، أي إعـادة اسـتخدام
الاكواد السابقـة وحتى نصل إلى هذا الهـدف فلا بد علينا من جعـل اسـتخدام
هذه الأكواد السابقة بسيطاً للغايـة وبـدون أي تعقيـد ، انظـر مـثلاً للكـائن cin
وكيف أن إستخدامه بسـيط وميسـر وأيضـاً للدالـة ( )printf فـي لغـة السـي
ومدى سهولتها وهذا أيضاً ما نحـاول الوصول إليه من خلال هذا الكتاب.
بإمكاننا تسهيل استخدام أي دالة بواسطـة الوسائط الافتراضيـة (البارامترات
الافتراضية) وهذه الأداة تمكننا من تسـهيل الكــود لدرجـة كبيـرة ، هـل تتـذكر
التابع ( )getline ، هذا التابع يحتـوي علـى ثـلاث بـارمترات ، ولكنـك تسـتطيع
التعامل معـه على أنه يستقبل بارامترين اثنـين وتسـتطيع إذا أردت اسـتخدام
ثلاث بارامترات ، نفس الأمر ينطبق هـنا ، بإمكاننا إنشاء توابـع بتلـك الطريقــة
ووسيلتنا لذلك هـي الوسائط الافتراضية.
سـنقوم الآن بكتابـة مثـال كــودي وهـذه المـرة سـيقوم هـذا المثـال بحسـاب
النسـبة المئويــة ، حيـث أنــه سـيقوم بحسـاب النسـبة مـن 100 افتراضــياً ،
وبإمكان المستخدم حساب النسبة من 100 أو أي رقم آخر يريده.
1. float rate(float a,float b ,float c=100)
2. {
3. float j=0;
4. j= (a*c)/b;
5. return j;
6. }
انظر إلى السطر الأول تجـد أن البارامتر الثالث غريب بعض الشيء حيث قمنا
باسناد البارامتر إلـى القيمــة 100 ، وبـذلك سـيكون بإمكانـك اسـتخدام هـذه
القيمـة افتراضياً ، بإمكانك استدعاء هذا التابع بهذا الشكل:
rate ( 50 , 100)
أو بهذا الشكل إن أردت:
rate ( 20, 100 , 1000)
والفـرق بـين الاسـتدعائين أن البـارامتر الثالـث للتـابع المسـتدعى الأول هــو
سيكون افتراضياً بقيمـة 100 ، أمـا التـابع الثالـث فلقـد أراد المسـتخدم تغييـر
هذه القيمـة وبالتالي فلقد قام البرنـامج باسـتبعاد القيمـة الافتراضـية ووضـع
القيمة التي قام المستخدم بوضعها.
سنرى الآن كيف سيكون استخدامنا لهذا التابع فـي وسـط برنـامج حقيقـي ،
عليـك أن تعلـم أن القيمــة الافتراضــية لا تكتـب أبـداً فـي رأس التـابع إلا فـي
النموذج المصغر فقط ، أما تعريف التابع فلا تقم بكتابة القيمـة الافتراضـية وإلا
فـإن المتـرجم سيصـدر خــطأ ، انظــر لهـذا المثـال ، وكيـف تـم تطبيـق الكـلام
الحالي:
CODE
1. #include <iostream>
2. using namespace std;
3.
4.
5. float rate (float a,float b,float c=100);
6.
7. void main()
8. {
9. float i,j,k,avg;
10. cout << "Please Enter the number?\n";
11. cin >> i;
12. cout << "from:\t";
13. cin >> j;
14. cout << "the Avrege:";
15. cin >> avg;
16.
17. k=rate (i ,j,avg);
18. cout << endl << k << endl;
19.
20. }
21.
22. float rate(float a,float b ,float c)
23. {
24. float j=0;
25. j= (a*c)/b;
26. return j;
27. }
قارن بين رأس التابع في السطر 22 والنموذج المصـغر للتـابع فـي السـطر 5
تستنتج أن النمـوذج المصـغر بإمكانـه الاحتـواء علـى قـيم افتراضـية أمـا رأس
التابع أو تعريف التابع فليس بإمكانـه الاحتـواء على أي قيمـة افتراضية.
إعادة أكثر من قيمـة بواسطـة المؤشرات أو المرجعيات:
الآن سنأتي إلى التطبيق الفعلي للمؤشرات ؛ هل تتـذكر التوابـع ألـيس فـي
نهايـة كل تابع مالم يكـن void العبارة التاليـة: return (Value);
حيث value القيمة المعادة.
كما ترى فإن جميع الدوال أو الإجراءات لا تعـود إلا بقيمـة واحـدة ولا تسـتطيع
العـودة بأكثر من قيـمـة ، الآن سنفكر بطريقـة تمكننا من جعـل التوابـع تعــود
بأكثر من قيمـة.
ما رأيك الآن بدلاً من أن نمرر للتوابع القـيم أن نمـرر لهـا عــناوين تلـك القيــم ؛
سنكتب برنامج هذا البرنامج يحــوي تابعـان التـابع main وتـابع آخـر سـنطلق
عليه plus سيعــيد هـذا الإجـراء قيمتـين وسـيقوم الإجـراء main بطباعتهــما
وليس التابع plus .
1 #include < iostream.h>
2 void plus (int num1,int num2,int *plus1,int *plus2)
3 {
4 *plus1=num1 + num2;
5 *plus2=num1*num2;
6 }
78
void mian ( )
9 {
10 int num1,num2,plus1,plus2;
11 plus (num1,num2, &plus1 , & plus2);
12 cout << plus1 << endl;
13 cout << plus2 << endl;
14 }
الآن وكما ترى فإن قيم plus1 و plus2 ستؤدي المطلـوب منهـا حيـث plus1
يجمع عـددان و plus2 يضـرب عـددان بالرغــم مـن أن المعالجــة لا تتــم فـي
التابع ()main بل فـي التـابع plus وكمـا تلاحـظ فـإن التـابع plus لا يعــود أي
قيمـة لأنه void ؛ كما تلاحظ أعـلنا عـن عددان مهيئان مسبقاً وعددان لم يهيئا
في السطر العاشر ؛ بعـد ذلـك قمنـا بتمريـر قيمــة العــددان num1 و num2
إلى الإجراء plus أما بالنسبة للعــددان الآخـران فلـم نمـرر قيمهــما بـل مررنـا
عـناوين تلك القيـم كما هـو واضح من السطر الحادي عشر ؛ كما درسـنا فـي
هذا الموضوع (موضوع التوابع) أنهـا تنشأ نسخ مـن المتغيـرات الممـررة إليهـا
أما في هذه الحالة فهي لم تقوم بإنشاء نسخــة بـل أخـذت النسـخ الأصليــة
من تلـك المتغيـرات وهــي عــناوينها ... الآن يتفـرع البرنـامج إلـى التـابع plus
والذي عرفناه في السطر الثاني وكما تلاحظ فهــو يحتــوي عـددان مـن نــوع
int ومتغيران آخران لكن مؤشرات هـذه المـرة وليسـا متغيـرات عاديــة .. هـل
تعرف لماذا .. كما تلاحـظ فلقـد مررنـا عــناوين تلـك المتغيـرات ؛ البرنـامج الآن