السلام عليكم
أعتقد أنه الموضوع باين من عنوانه ايش هو الفرق بينهم ومتى استخدمهم.
السلام عليكم
أعتقد أنه الموضوع باين من عنوانه ايش هو الفرق بينهم ومتى استخدمهم.
:: الاستدعاء بالقيمة ( by Value ) و الاستدعاء بالمرجع ( by Reference ) ::
إذا أردنا أن ندخل مجموعة من القيم إلى داخل تابع ما .. كنا نستخدم لذلك المتحولات الوسيطة .. و عند استدعاء التابع كنا نرسل القيم التي نريدها عن طريق المتحولات الوسيطة الفعلية ( راجع فقرة المتحولات الوسيطة ) .. و لكن ما معنى الاستدعاء بالقيمة و الاستدعاء بالمرجع ؟
الاستدعاء بالقيمة ( by Value ) :
و هو الوضع الافتراضي لإرسال القيم للتوابع عن طريق المتحولات الوسيطة .. و لكن ما معناها ؟ انظر الاستدعاء التالي للتابع avr و الذي يحسب متوسط عددين ( لا يعيد قيمة ) و بفرض أن x و y هما العددين الذين سنحسب متوسطهما :
void avr(int a, int b)
{
int c = ( a+b ) / 2;
cout << c << endl;
}
void main()
{
int x, y;
x = 10; y = 20;
avr( x, y );
}عند الاستدعاء .. سيتم إجراء نسخة عن كل من x و y و إرسالها إلى المتحولات الوسيطة a و b الخاصين بالتابع avr .. و بالتالي لن يتأثر المتغيرين x و y بنتائج عمليات التابع ( أي لن تتغير قيمتهما حتى بعد الانتهاء من التابع ) لأن المترجم قام بنسخ قيم x و y و وضعها في المتحولين الوسيطين a و b .. و بالتالي نستنتج أيضاً أنه سيتم تحميل الذاكرة بقيمتين مشابهتين تماماً لقيم x و y .
و لكن افرض مثلاً أنك تريد إرسال بيانات كبيرة ( كالكائنات أو السجلات مثلاً ) عبر تلك المتحولات الوسيطة .. فسيتم بهذه الطريقة إجراء نسخة أخرى لتلك القيم .. و بهذا سيزداد العبء على الذاكرة و سيزداد حجمها .. و لكن ما الحل لمعالجة هذه المشكلة ؟ الحل هو عن طريق الاستدعاء بالمرجع .. و تفيدنا تلك الطريقة أيضاً في إرجاع أكثر من قيمة بدلاً من قيمة واحدة فقط ( انظر الفقرة التالية ) .
الاستدعاء بالمرجع ( by Reference ) :
يختلف الاستدعاء بالمرجع عن الاستدعاء بالقيمة بأنه هذا الاستدعاء ( بالمرجع ) سيقوم بالتعامل مع عنوان المتحول الوسيط الفعلي في الذاكرة .. و بالتالي إذا حدثت أي تغييرات على المتحول الوسيط الشكلي فإن هذا التغير سيطرأ أيضاً على المتحول الوسيط الفعلي .. أي أن قيمة المتحول الوسيط الشكلي ستعطى للمتحول الوسيط الفعلي . انظروا المثال .
قاعدة / يمكنك استخدام الاستدعاء بالمرجع عن طريق وضع العلامة ( & ) قبل اسم المتحول الوسيط الشكلي الموجود في تعريف التابع .
void f1( int &a )
{
}مثال / لتابع ندخل عليه عدد ما فيعطينا العدد الذي يليه :
void num( int &a )
{
a++;
}
void main()
{
int x;
cin >> x;
num( x );
cout << x << endl;
}ملاحظة / لاحظ أننا لم نستخدم التوابع التي تعيد قيمة لإخراج الناتج .. بل استخدمنا الاستدعاء بالمرجع .
شرح المثال :
في هذا المثال .. سيدخل المستخدم عدد ما ( x ) ثم سنرسل هذا العدد كمرجع إلى التابع num .. و بهذه الطريقة سيتم إخراج الناتج عن طريق ( x ) أيضاً .. و لكن لن يتم هنا إجراء نسخة مطابقة للمتغير x بل سيتم تعديلها فقط عن طريق المتحول الشكلي a .. فإذا تغيرت a تتغير x و كأن a هي اسم آخر لـ x أي يتم التعامل معه و كأنه المتحول x .
و أريد التأكيد على معنى المرجعية .. قلنا فيما سبق أن المتغيرات تستخدم لتخزين قيم في الذاكرة و بالتالي لكل متغير في الذاكرة معلومتين : الأولى و هي القيمة التي يحملها .. و الثانية هي عنوانه في الذاكرة ( مكان وجوده ) .. و بالتالي عند استخدام الاستدعاء بالمرجع نكون قد وضعنا متغير آخر ( الشكلي ) يشير إلى نفس القيمة المرسلة فإذا تغيرت قيمة أحد المتغيرين ( الفعلي و الشكلي ) يكون قد تغير الأخر و كأننا وضعنا عنوانين في الذاكرة يشيران إلى نفس القيمة .. و هذا يعني أنه لن يتم نسخ قيمة المتحول الفعلي كما هو الحال في الاستدعاء بالقيمة .. حيث يتم في ذلك الاستدعاء إجراء نسخة كاملة عن المتحول الفعلي و وضعها في المتحول الشكلي بحيث يكون لها عنوان مختلف و قيمة مستقلة عن المتحول الفعلي .. و بالتالي إذا تغير أحدهم لن يتغير الأخر .
و في هذا المثال .. إذا فرضنا أن المستخدم أدخل العدد 5 فسيظهر على الشاشة العدد 6 .. و هكذا .
قاعدة 1 / من أجل القيم صغيرة الحجم يمكنك إرسال تلك القيم إلى التوابع باستخدام الاستدعاء بالقيمة .. بينما ينصح باستخدام الاستدعاء بالمرجع بالنسبة للقيمة الكبيرة .. و أيضاً من أجل إرجاع أكثر من قيمة ( أي تكون مخرجات التابع أكثر من قيمة ) .
من شرح Wolf Sniper .. أرجو أن يفيدك
الله يجزاك ألف خير أخوي تبسيط
مشكور وماقصرت.
هذا الموضوع مغلق.