تحميل الوظائف الزائد

في بعض لغات البرمجة ، يُتيح تحميل الدوال أو تحميل الأساليب إمكانية إنشاء دوال متعددة تحمل الاسم نفسه ولكن بتنفيذات مختلفة. عند استدعاء دالة مُحمّلة، يتم تشغيل تنفيذ مُحدد لتلك الدالة يتناسب مع سياق الاستدعاء، مما يسمح باستدعاء دالة واحدة بأداء مهام مختلفة تبعًا للسياق.

التعريف الأساسي

على سبيل المثال، تُعتبر الدالتان `doTask()` و` doTask(object o)` دالتين مُحمّلتين. لاستدعاء الدالة الثانية، يجب تمرير كائن كمعامل ، بينما لا تتطلب الدالة الأولى أي مُعامل، ويتم استدعاؤها بحقل مُعامل فارغ. من الأخطاء الشائعة تعيين قيمة افتراضية للكائن في الدالة الثانية، مما يؤدي إلى خطأ استدعاء غامض ، حيث لن يعرف المُصرّف أيًّا من الدالتين يجب استخدامه.

مثال آخر هو دالة Print(object o) التي تُنفّذ إجراءات مختلفة بناءً على ما إذا كانت تطبع نصًا أو صورًا. يمكن إعادة تعريف الدالتين على النحو التالي: Print(text_object T)؛ Print(image_object P) . إذا كتبنا دوال الطباعة المُعاد تعريفها لجميع الكائنات التي سيطبعها برنامجنا، فلن نضطر أبدًا للقلق بشأن نوع الكائن، وسيكون استدعاء الدالة الصحيح دائمًا: Print(something) .

اللغات التي تدعم التحميل الزائد

تشمل اللغات التي تدعم تحميل الدوال الزائدة، على سبيل المثال لا الحصر:

تشمل اللغات التي لا تدعم تحميل الدوال الزائد C و Python و Rust و Zig .

قواعد تحميل الدوال الزائدة

  • يتم استخدام نفس اسم الدالة لأكثر من تعريف دالة واحدة في وحدة نمطية أو فئة أو مساحة اسم معينة
  • يجب أن يكون للدوال توقيعات أنواع مختلفة ، أي تختلف في عدد أو أنواع معاملاتها الرسمية (كما في لغة C++) أو بالإضافة إلى ذلك في نوع القيمة المرجعة (كما في لغة Ada). [ 9 ]

يرتبط تحميل الدوال عادةً بلغات البرمجة ذات الكتابة الثابتة التي تفرض التحقق من أنواع البيانات عند استدعاء الدوال . الدالة المحملة هي مجموعة من الدوال المختلفة التي يمكن استدعاؤها بنفس الاسم. في كل استدعاء، يحدد المترجم الدالة المحملة التي سيستخدمها ويحسم هذا الأمر أثناء الترجمة . ينطبق هذا على لغات برمجة مثل جافا. [ 10 ]

يختلف تحميل الدوال عن أشكال تعدد الأشكال حيث يتم الاختيار في وقت التشغيل، على سبيل المثال من خلال الدوال الافتراضية ، بدلاً من الاختيار الثابت.

مثال: تحميل الدوال الزائدة في لغة C++

استيراد std ؛// حجم المكعب. int volume ( int s ) { return s * s * s ; }// حجم الأسطوانة. double volume ( double r , int h ) { return std :: numbers :: pi * r * r * static_cast < double > ( h ); }// حجم متوازي المستطيلات (منشور مستطيل). long volume ( long l , int b , int h ) { return l * b * h ; }int main () { std :: println ( "{}" , volume ( 10 )); std :: println ( "{}" , volume ( 2.5 , 8 )); std :: println ( "{}" , volume ( 100l , 75 , 15 )); }

في المثال أعلاه، يتم حساب حجم كل مكون باستخدام إحدى الوظائف الثلاث المسماة "الحجم"، مع الاختيار بناءً على العدد والنوع المختلفين للمعلمات الفعلية.

التحميل الزائد للمنشئ

تُستخدم الدوال البانية لإنشاء نسخ من كائن ما، ويمكن أيضًا تحميلها بشكل زائد في بعض لغات البرمجة كائنية التوجه . ولأن اسم الدالة البانية في العديد من اللغات مُحدد مسبقًا باسم الصنف، فقد يبدو أنه لا يمكن أن يكون هناك سوى دالة بانية واحدة. ولكن عند الحاجة إلى دوال بانية متعددة، يجب تنفيذها كدوال مُحمّلة بشكل زائد. في لغة C++ ، لا تأخذ الدوال البانية الافتراضية أي معلمات، بل تُنشئ أعضاء الكائن بقيمها الافتراضية المناسبة، "والتي عادةً ما تكون صفرًا للحقول الرقمية وسلسلة نصية فارغة للحقول النصية". [ 11 ] على سبيل المثال، قد تُحدد الدالة البانية الافتراضية لكائن فاتورة مطعم مكتوب بلغة C++ نسبة الإكرامية إلى 15%.

الفاتورة : البقشيش { 0.15 الإجمالي { 0.0 } { }

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

مقهى بيل ؛ بقشيش المقهى = 0.10 ؛ إجمالي المقهى = 4.00 ؛

من خلال إعادة تعريف الدالة البانية، يمكن تمرير الإكرامية والإجمالي كمعاملات عند إنشاء الكائن. يوضح هذا المثال الدالة البانية المعاد تعريفها بمعاملين. تُوضع هذه الدالة في نفس فئة الدالة البانية الأصلية التي استخدمناها سابقًا. يعتمد اختيار الدالة المستخدمة على عدد المعاملات المُقدمة عند إنشاء كائن الفاتورة الجديد (لا شيء، أو معاملان).

الفاتورة ( إكرامية مضاعفة ، إجمالي مضاعف ) : الإكرامية { إكرامية الإجمالي { الإجمالي } {}

الآن، يمكن لدالة إنشاء كائن Bill جديد أن تمرر قيمتين إلى المُنشئ وتُعيّن قيم أعضاء البيانات في خطوة واحدة. يوضح ما يلي عملية الإنشاء وتعيين القيم:

مقهى بيل ( 0.10 ، 4.00 

يمكن أن يكون هذا مفيدًا في زيادة كفاءة البرنامج وتقليل طول الكود.

سبب آخر لتحميل المُنشئات بشكل زائد هو فرض استخدام أعضاء بيانات إلزامية. في هذه الحالة، يُعلن عن المُنشئ الافتراضي كمُنشئ خاص أو محمي (أو يُفضل حذفه منذ C++11 ) لجعله غير قابل للوصول من الخارج. بالنسبة للفاتورة المذكورة أعلاه، قد يكون الإجمالي هو مُعامل المُنشئ الوحيد - نظرًا لعدم وجود قيمة افتراضية منطقية للإجمالي في الفاتورة - بينما القيمة الافتراضية للبقشيش هي 0.15.  

المضاعفات

هناك مشكلتان تتفاعلان مع عملية تحميل الوظائف وتزيدان من تعقيدها: إخفاء الاسم (بسبب النطاق ) والتحويل الضمني للنوع .

إذا تم تعريف دالة في نطاق معين، ثم تم تعريف دالة أخرى بنفس الاسم في نطاق داخلي، فهناك سلوكان طبيعيان محتملان للتحميل الزائد: إما أن يُخفي التعريف الداخلي التعريف الخارجي (بغض النظر عن التوقيع)، أو أن يشمل التحميل الزائد كلاً من التعريف الداخلي والخارجي، بحيث يُخفي التعريف الداخلي التعريف الخارجي فقط في حال تطابق التوقيع. يُعتمد السلوك الأول في لغة C++: "في C++، لا يوجد تحميل زائد عبر النطاقات." [ 12 ] ونتيجة لذلك، للحصول على مجموعة تحميل زائد تتضمن دوالًا مُعرّفة في نطاقات مختلفة، يجب استيراد الدوال صراحةً من النطاق الخارجي إلى النطاق الداخلي باستخدام الكلمة usingالمفتاحية.

يؤدي التحويل الضمني للأنواع إلى تعقيد عملية تحميل الدوال الزائدة لأنه إذا لم تتطابق أنواع المعلمات تمامًا مع توقيع إحدى الدوال المحملة بشكل زائد، ولكن يمكن أن تتطابق بعد تحويل النوع، فإن الحل يعتمد على نوع التحويل الذي تم اختياره.

قد تتداخل هذه الأمور بطرق مربكة: على سبيل المثال، يمكن لتطابق غير دقيق مُعلن عنه في نطاق داخلي أن يخفي تطابقًا دقيقًا مُعلنًا عنه في نطاق خارجي. [ 12 ]

على سبيل المثال، لإنشاء فئة مشتقة تحتوي على دالة مُحمّلة تأخذ قيمة من النوع a doubleأو من النوع an int، باستخدام الدالة التي تأخذ قيمة من النوع an intمن الفئة الأساسية، في لغة C++، يمكن كتابة ما يلي:

class Base { public : void fn ( int i ); };class Derived : public Base { public : using Base :: fn ; void fn ( double d ); };

عدم تضمين usingالنتائج في intمعلمة تم تمريرها إلى fnالفئة المشتقة التي يتم تحويلها إلى عدد عشري مزدوج ومطابقة الدالة في الفئة المشتقة، بدلاً من الفئة الأساسية؛ تضمين usingالنتائج في دالة محملة زائدة في الفئة المشتقة وبالتالي مطابقة الدالة في الفئة الأساسية.

محاذير

إذا صُممت دالة بعدد كبير من الصيغ المتعددة، فقد يصعب على المطورين تحديد الصيغة المستخدمة بمجرد قراءة الكود. ويزداد هذا الأمر صعوبةً إذا كانت بعض المعاملات المُحمّلة من أنواع موروثة من معاملات أخرى محتملة (مثل "object"). يمكن لبيئة التطوير المتكاملة (IDE) إجراء عملية تحديد الصيغة المتعددة وعرض الصيغة الصحيحة (أو الانتقال إليها).

قد يؤدي التحميل الزائد القائم على النوع أيضًا إلى إعاقة صيانة الكود، حيث يمكن لتحديثات الكود أن تغير عن طريق الخطأ أي تحميل زائد للطريقة يختاره المترجم. [ 13 ]

انظر أيضاً

الاقتباسات

  1. "Clojure - Learn Clojure - Functions" . clojure.org . تم الاطلاع عليه بتاريخ 13-06-2023 .
  2. "وثائق كريستال" . crystal-lang.org .
  3. "إمباركاديرو دلفي" . embarcadero.com .
  4. "مواصفات لغة كوتلين" . kotlinlang.org .
  5. بلوخ 2018 ، ص 238-244، §الفصل 8 البند 52: إزالة التحذيرات غير المدققة.
  6. "دليل لغة نيم" . nim-lang.org .
  7. "37.6. تحميل الدوال الزائد" . وثائق PostgreSQL . 12-08-2021 . تم الاطلاع عليه بتاريخ 29-08-2021 .
  8. "دليل المستخدم وقاعدة بيانات PL/SQL" . docs.oracle.com . تم الاطلاع عليه بتاريخ 29-08-2021 .
  9. وات، ديفيد أ.؛ فيندلاي، ويليام (1 مايو 2004). مفاهيم تصميم لغات البرمجة . جون وايلي وأولاده، ص 204-207 . ISBN  978-0-470-85320-7.
  10. بلوخ 2018 ، ص 238-244، §الفصل 8 البند 52: استخدم التحميل الزائد بحكمة.
  11. تشان، جيمي (2017). تعلم لغة سي شارب في يوم واحد وأتقنها جيدًا ( طبعة منقحة). ص 82. ISBN   978-1518800276.
  12. 1 2 ستروستروب، بيارن . "لماذا لا يعمل التحميل الزائد للفئات المشتقة؟" .
  13. براخا، جلعاد (3 سبتمبر 2009). "الحمل الزائد النظامي" . الغرفة 101.

مراجع

  • بلوخ، جوشوا (2018). "جافا الفعّالة: دليل لغة البرمجة" (  الطبعة الثالثة). أديسون-ويسلي. ISBN 978-0134685991.