الفرق بين Call by Value و Call by Reference

الفرق الرئيسي بين الاتصال حسب القيمة والاتصال حسب المرجع

  • في طريقة الاتصال حسب القيمة، لا يتم تعديل القيمة الأصلية، بينما في طريقة الاتصال حسب المرجع، يتم تعديل القيمة الأصلية.
  • في الاتصال حسب القيمة، يتم تمرير نسخة من المتغير، بينما في الاتصال حسب المرجع، يتم تمرير المتغير نفسه.
  • في الاتصال حسب القيمة، سيتم إنشاء الوسائط الفعلية والرسمية في مواقع ذاكرة مختلفة، بينما في الاتصال حسب المرجع، سيتم إنشاء الوسائط الفعلية والرسمية في نفس موقع الذاكرة.
  • الاتصال حسب القيمة هو الطريقة الافتراضية في لغات البرمجة مثل C++وPHP وVisual Basic NET وC#، بينما يتم دعم الاتصال حسب المرجع فقط في Java لغة.
  • يتم تمرير متغيرات الاتصال حسب القيمة باستخدام طريقة مباشرة، بينما تكون مؤشرات الاتصال حسب المرجع مطلوبة لتخزين عنوان المتغيرات.

الفرق بين Call by Value و Call by Reference

في لغات البرمجة، يمكن استدعاء الوظائف بطريقتين: ما يعرف بالاستدعاء حسب القيمة والاستدعاء حسب المرجع.

ما هي طريقة الاتصال حسب القيمة؟

تقوم طريقة الاستدعاء حسب القيمة بنسخ قيمة الوسيطة إلى المعلمة الرسمية لتلك الوظيفة. لذلك، لا تؤثر التغييرات التي تم إجراؤها على معلمة الوظيفة الرئيسية على الوسيطة.

في طريقة تمرير المعلمات هذه، يتم نسخ قيم المعلمات الفعلية إلى المعلمات الرسمية للوظيفة، ويتم تخزين المعلمات في مواقع ذاكرة مختلفة. لذا فإن أي تغييرات يتم إجراؤها داخل الوظائف لا تنعكس في المعلمات الفعلية للمتصل.

ما هي طريقة الاتصال حسب المرجع؟

تقوم طريقة الاتصال حسب المرجع بنسخ عنوان الوسيطة إلى المعلمة الرسمية. في هذه الطريقة، يتم استخدام العنوان للوصول إلى الوسيطة الفعلية المستخدمة في استدعاء الوظيفة. وهذا يعني أن التغييرات التي تم إجراؤها في المعلمة تغير وسيطة التمرير.

في هذه الطريقة، يكون تخصيص الذاكرة مماثلاً للمعلمات الفعلية. يتم تنفيذ جميع العمليات في الدالة على القيمة المخزنة في عنوان المعلمة الفعلية، وسيتم تخزين القيمة المعدلة في نفس العنوان.

C Code مثال على طريقة الاستدعاء حسب القيمة

void main() {
        int a = 10,
        void increment(int);
        Cout << "before function calling" << a;
        increment(a);
        Cout << "after function calling" << a;
        getch();

        void increment(int x) {
            int x = x + 1;
            Cout << "value is" << x;
        }

الإخراج:

before function calling 10
value is 11
after function calling 1-0

لأن المتغير المُعلن 'a'in main() يختلف عن المتغير 'x' في increment(). في هذا البرنامج، تتشابه أسماء المتغيرات فقط، لكن عنوان ذاكرتها مختلف ويتم تخزينها في مواقع ذاكرة مختلفة.

Java Code مثال على طريقة الاستدعاء بالإشارة

Public static void main(string args[]) {
    int a = 10;
    System.out.println("Before call Value of a = ", a);
    Void increment();
    System.out.println("After call Value of a = ", a);
}

Void increment(int x) {
    int x = x + 1;
}

الإخراج:

Before call Value of a =10
After call Value of a =11

لأن المتغير المُعلن "a" يشير/يشير إلى المتغير "a" في main(). يختلف اسم المتغير هنا، لكن كلاهما يشير/يشير إلى نفس مواقع عناوين الذاكرة.

الاتصال حسب القيمة مقابل الاتصال حسب المرجع

المعاملات اتصل بالقيمة اتصل بالإشارة
تعريف أثناء استدعاء دالة، عندما تقوم بتمرير القيم عن طريق نسخ المتغيرات، يُعرف ذلك باسم "الاستدعاء حسب القيم". أثناء استدعاء دالة، في لغة البرمجة بدلاً من نسخ قيم المتغيرات، يتم استخدام عنوان المتغيرات المعروف باسم "Call By References".
الحجج في هذه الطريقة، يتم تمرير نسخة من المتغير. في هذه الطريقة، يتم تمرير المتغير نفسه.
تأثير التغييرات التي تم إجراؤها في نسخة المتغير لا تؤدي أبدًا إلى تعديل قيمة المتغير خارج الوظيفة. يؤثر التغيير في المتغير أيضًا على قيمة المتغير خارج الدالة.
تغيير القيمة لا يسمح لك بإجراء أي تغييرات في المتغيرات الفعلية. يسمح لك بإجراء تغييرات في قيم المتغيرات باستخدام استدعاءات الوظائف.
تمرير المتغير يتم تمرير قيم المتغيرات باستخدام طريقة مباشرة. متغيرات المؤشر مطلوبة لتخزين عنوان المتغيرات.
تعديل القيمة القيمة الأصلية لم يتم تعديلها. تم تعديل القيمة الأصلية.
موقع الذاكرة الحجج الفعلية والرسمية
سيتم إنشاؤها في مختلف
موقع الذاكرة
الحجج الفعلية والرسمية
سيتم إنشاؤها في نفس
موقع الذاكرة
سلامة تبقى الحجج الفعلية
آمنة لأنها لا يمكن تعديلها
بطريق الخطأ.
الحجج الفعلية ليست كذلك
آمن. يستطيعون
تم تعديله عن طريق الخطأ، لذا يجب عليك التعامل مع عمليات الوسيطات بعناية.
الترتيب الافتراضي في العديد من البرمجة
لغات مثل C++.بي إتش بي. فيجوال بيسك نت و سي#.
وهو مدعوم من قبل معظم
لغات البرمجة مثل JAVA، ولكن
ليس كافتراضي.

مزايا استخدام طريقة Call by value في C

إيجابيات/فوائد المكالمة حسب القيمة في لغة C:

  • لا تغير الطريقة المتغير الأصلي، لذا فهي تحافظ على البيانات.
  • عندما يتم استدعاء دالة، لا تؤثر أبدًا على المحتويات الفعلية للوسائط الفعلية.
  • قيمة الوسائط الفعلية التي تم تمريرها إلى الوسائط الرسمية، لذا فإن أي تغييرات يتم إجراؤها في الوسيطة الرسمية لا تؤثر على الحالات الحقيقية.

مزايا استخدام الاتصال بالطريقة المرجعية

إيجابيات استخدام طريقة الاتصال حسب المرجع:

  • يمكن للوظيفة تغيير قيمة الوسيطة، وهو أمر مفيد للغاية.
  • لا يقوم بإنشاء بيانات مكررة للاحتفاظ بقيمة واحدة فقط مما يساعدك على توفير مساحة الذاكرة.
  • في هذه الطريقة، لا توجد نسخة من الوسيطة التي تم إجراؤها. ولذلك تتم معالجتها بسرعة كبيرة.
  • يساعدك على تجنب التغييرات التي تم إجراؤها عن طريق الخطأ
  • لا يعرف الشخص الذي يقرأ الكود أبدًا أنه يمكن تعديل القيمة في الوظيفة.

عيوب استخدام طريقة الاتصال بالقيمة

فيما يلي أهم سلبيات/عيوب طريقة الاستدعاء حسب القيمة:

  • يمكن أن تؤدي التغييرات التي يتم إجراؤها على المعلمات الفعلية أيضًا إلى تعديل متغيرات الوسيطة المقابلة
  • في هذه الطريقة، يجب أن تكون الوسائط متغيرات.
  • لا يمكنك تغيير متغير مباشرة في نص الوظيفة.
  • في بعض الأحيان يمكن أن تكون الحجة عبارة عن تعبيرات معقدة
  • هناك نسختان تم إنشاؤها لنفس المتغير وهي ليست ذات كفاءة في الذاكرة.

عيوب استخدام الاتصال بالطريقة المرجعية

فيما يلي سلبيات رئيسية لاستخدام طريقة الاتصال حسب المرجع:

  • ضمان قوي بعدم وجود قيمة فارغة. يجب على الوظيفة التي تستقبل مرجعًا التأكد من أن المدخلات ليست فارغة. لذلك، لا يلزم إجراء فحص عدم وجود قيمة فارغة.
  • التمرير بالرجوع يجعل الوظيفة غير نقية من الناحية النظرية.
  • يعد الضمان مدى الحياة مشكلة كبيرة فيما يتعلق بالمراجع. يعد هذا أمرًا خطيرًا بشكل خاص عند العمل مع برامج lambdas والبرامج متعددة الخيوط.

تلخيص هذه التدوينة بـ: