هبوط الهواء

في البرمجة القائمة على الأصناف ، يُعرف التحويل التنازلي ، أو تحسين النوع، بتحويل مرجع الصنف الأساسي أو الأصل إلى مرجع صنف مشتق أكثر تقييدًا . [ 1 ] يُسمح بهذا فقط إذا كان الكائن بالفعل نسخة من الصنف المشتق، ولذلك فإن هذا التحويل عرضة للخطأ بطبيعته. في المقابل، يُعد التحويل التصاعدي ، أي التعامل مع الكائن صراحةً كما لو كان نسخة من أحد أصنافه الأصلية، ممكنًا دائمًا. [ 2 ]

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

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

تمنع بعض اللغات، مثل OCaml ، التحويل إلى نوع فرعي. [ 3 ]

أمثلة

جافا

public class Fruit {} // الفئة الأب public class Apple extends Fruit {} // الفئة الابنpublic static void main ( String [] args ) { // ما يلي هو تحويل ضمني لأعلى: Fruit parent = new Apple (); // ما يلي هو تحويل لأسفل. هنا، يعمل لأن المتغير `parent` // يحتوي على نسخة من Apple: Apple child = ( Apple ) parent ; }

لغة سي++

// الفئة الأصلية: class Fruit { public : // يجب أن تكون متعددة الأشكال لاستخدام التحويل الديناميكي الذي يتم التحقق منه أثناء التشغيل. virtual ~ Fruit () = default ; };// الفئة الفرعية: class Apple : public Fruit {};int main ( int argc , char * argv []) { // ما يلي هو تحويل ضمني لأعلى: Fruit * parent = new Apple (); // ما يلي هو تحويل لأسفل. هنا، يعمل لأن المتغير `parent` // يحتوي على نسخة من Apple: Apple * child = dynamic_cast < Apple *> ( parent ); delete parent ; }

الاستخدامات

يُعدّ التحويل التنازلي مفيدًا عندما يكون نوع القيمة المُشار إليها بواسطة المتغير الأصل معروفًا، ويُستخدم غالبًا عند تمرير قيمة كمعامل. في المثال أدناه، تأخذ الدالة objectToString معاملًا من نوع Object، والذي يُفترض أنه من نوع String.

public static String objectToString ( Object myObject ) { // لن يعمل هذا إلا إذا كانت قيمة myObject الحالية من نوع سلسلة نصية. return ( String ) myObject ; }public static void main ( String [] args ) { // سيعمل هذا الكود لأننا مررنا سلسلة نصية، وبالتالي فإن قيمة myObject هي سلسلة نصية. String result = objectToString ( "My String" ); Object iFail = new Object (); // سيفشل هذا الكود لأننا مررنا كائنًا لا يحتوي على قيمة سلسلة نصية. result = objectToString ( iFail ); }

في هذا الأسلوب، يمنع التحويل التنازلي المُصرّف من اكتشاف خطأ محتمل، ويتسبب بدلاً من ذلك في حدوث خطأ أثناء التشغيل. لم يكن تحويل myObject إلى String ('(String)myObject') ممكنًا أثناء الترجمة، لأن myObject يكون أحيانًا من نوع String، لذا لا يمكننا تحديد ما إذا كانت القيمة المُمرّرة منطقية إلا أثناء التشغيل. مع أنه يُمكننا أيضًا تحويل myObject إلى String أثناء الترجمة باستخدام الدالة العامة java.lang.Object.toString()، إلا أن هذا يُعرّضنا لخطر استدعاء التنفيذ الافتراضي للدالة toString() في مواضع غير مُجدية أو غير آمنة، ولن تتمكن معالجة الاستثناءات من منع ذلك.

في لغة C++، يتم التحقق من أنواع البيانات أثناء التشغيل باستخدام الدالة dynamic_cast . أما التحويل التنازلي أثناء الترجمة فيتم باستخدام الدالة static_cast ، ولكن هذه العملية لا تُجري أي فحص لأنواع البيانات. وإذا استُخدمت بشكل غير صحيح، فقد ينتج عنها سلوك غير مُعرَّف.

الاعتبارات

ومن الأمثلة الشائعة على التصميم سيئ التفكير حاويات الأنواع العليا ، مثل حاويات جافا قبل إطلاق جافا العامة ، والتي تتطلب تحويل الكائنات الموجودة بداخلها إلى نوع أدنى حتى يمكن استخدامها مرة أخرى.

انظر أيضاً

مراجع

  1. تايلر إم إس إف تي (2021-08-03). "كيفية استخدام safe_cast في C++/CLI" . learn.microsoft.com . تم الاطلاع عليه بتاريخ 2023-12-01 .
  2. ليانغ، واي. دانيال (2015). مقدمة في برمجة جافا، النسخة الشاملة ( الطبعة العاشرة). بيرسون. ص 427. ISBN   978-0-13-376131-3.
  3. فويون، جيروم؛ ريمي، ديدييه؛ غاريغ، جاك (12 سبتمبر 2013). "الكائنات في OCaml" . إصدار نظام OCaml 4.01 : الوثائق ودليل المستخدم .