تحويل الأنواع في سي بلس بلس : (type casting) وهي عبارة عن مجموعة طرق للتحويل من نوع إلى نوع معين في لغة ++C , مثلها مثل أي لغة أخرى , وبما أن لغة ++C لغة مميزة عن غيرها فلها طرق تحويل خاصة بها ,ويجب عليك كمبرمج لغة ++C أن تعرف كيف تتعامل مع هذه التحويلات بدقة لكي لا تكون برامجك عرضة للأخطاء التي أحيانا قد لاتكتشفها أثناء كتابة برنامجك .
التحويل الضمني
التحويل الضمني (Implicit conversion) لايتطلب أي معامل , ويتم تنفيذها تلقائيا عندما يتم نسخ قيمة من نوع معين إلى نوع آخر موافق .
short s = 1000; int a; a = s;
هنا القيمة تم ترقيتها من short إلى int ,مع أننا لم نفوم باستخدام أي معامل للتحويل type_casting , هذا التحويل يسمى بالتحويل القياسي Implicit conversion ,وهو يؤثر في الأنواع الأساسية للبيانات , مثل تحويل الأنواع العديّدة (short to int, int to float, double to int) ويمكن تحويلهم أيضا إلى النوع المنطقي bool . مع ذلك هذه التحويلات تعد غير دقيقة أي يمكن أحيانا أن يطلق المترجم رسائل تحذيرية ,ولتجنب ذلك يجب أن نستخدم التحوي الصريح explicit conversion .
أيضا يمكن أن يتضمن التحويل الضمني التحويل بين مشيدات الفئات (classes) إذا كان في إحد مشيد الفئة كائن للفئة الأخرى , مثال على ذلك :
class A {}; class B { public: B (A a) {} }; A a; B b = a;
في الكود السابق حدث تحويل بين كائنين A , B لأن مشيد الفئة B تحتوي على بارمتر من نوع A .لذلك التحويل الضمني مسموح فقط من A إلى B.
التحويل الصريح
(Explicit conversion) العديد من التحويلات , خاصة تلك التي تعبر عن تفسيرات مختلفة في القيمة ,مثل هذه التحويلات تحتاج إلى تحويل صريح . يوجد نمطين للتحويل الصريح هو الوظيفي (الدالي) functional وc-like :
short s = 1000; int a; a = (int) s; // c-like cast notation a = int(s); // functional notation
معاملات التحويل الصريح يمكن استخدامها لمعظم أنواع البيانات الأساسية , ولكن يمكن أن تطبق بشكل عشوائي على الكائنات ومؤشرات الكائنات ,أي يمكن أن تكون صحيحة من حيث التركيب ولكن تسبب في حدوث خطأ وقت التشغيل run-time :
class A { float x,y; }; class B { int i,j; public: B (int a, int b) { i = a; j = b; } int result() { return i + j; } }; int main() { A d; B *b; b = (B) &d; //Error cout <<b->result(); return 0; }
هذا الكود يقوم بتصريح مؤشر إلى الكائن B ,وبعد ذلك يسند له مرجع من كائن آخر A غير متوافق معه بالنوع :
b = (B) &d;
التحويل الصريح التقليدي يمكن أن يحول أي مؤشر إلى مؤشر آخر , ولكن بصرف النظر عن ذلك . إن استدعاء الدالة result قد تعطي خطأ في وقت التشغيل أو أنها تعطي قيمة غير متوقعة ,لأجل السطيرة على هذه التحويلات التي تتم بين الفئات ,لدينا أربع معاملات :
dynamic_cast وreinterpret_cast وstatic_cast وconst_cast
لديها صيغة خاصة فيها ,فيتم تمرير النوع داخل أقواس الزاوية <> ,وبعدها مباشرة يتم كتابة التعبير المراد تحويله بين قوسين .
dynamic_cast <new_type> (expression) reinterpret_cast <new_type> (expression) static_cast <new_type> (expression) const_cast <new_type> (expression)
أما التحويل الصريح فأن صيغته كالتالي :
(new_type) expression new_type (expression)
وكل نوع من أنواع التحويل لديها مايميزها عن الآخر .
التحويل الديناميكي
(dynamic_cast) يمكن أن يستخدم التحويل الديناميكي فقط مع المؤشرات والمراجع إلتي تشير إلى الكائنات Object , الغرض منه هو ضمان أن تكون نتيجة التحويل صالحة وصحيحة بالنسبة للفئة المطلوبة ,ولذلك dynamic_cast دائما تعطيك نتيجة صحيحة عندما تريد التحويل بين الفئة المشتقة إلى واحدة من الفئات الأساسية.
class CBase { }; class CDerived: public CBase { }; CBase b; CBase* pb; CDerived d; CDerived* pd; pb = dynamic_cast<CBase*>(&d); // ok: derived-to-base pd = dynamic_cast<CDerived*>(&b); // wrong: base-to-derived
في الكود السابق ينتج المترجم خطأ بسبب التحويل الثاني لأن التحويل من فئة أساسية إلى فئة مشتقة غير مسموح . إلا إذا كانت الفئة متعددة الأشكال (نمط من أنماط oop). عندما تكون الفئة متعددة الأشكال polymorphic , فإن Dynamic_cast يقوم بحفص دقيق خلال وقت التشغيل للتأكد بأن القيمة المعادة صحيحة وصالحة للفئة المطلوبة ,مثال على ذلك :
// dynamic_cast #include <iostream> #include <exception> using namespace std; class CBase { virtual void dummy() {} }; class CDerived: public CBase { int a; }; int main () { try { CBase * pba = new CDerived; CBase * pbb = new CBase; CDerived * pd; pd = dynamic_cast<CDerived*>(pba); if (pd==0) cout <<"Null pointer on first type-cast" <<endl; pd = dynamic_cast<CDerived*>(pbb); if (pd==0) cout <<"Null pointer on second type-cast" <<endl; } catch (exception& e) {cout <<"Exception: " <<e.what();} return 0; }
النتائج :
Null pointer on second type-cast
انظر أيضاً
وصلات خارجية
- Casting in ABAP
- Casting in Ada
- Casting in C++
- C++ Reference Guide Why I hate C++ Cast Operators, by Danny Kalev
- Casting in Java
- Implicit Conversions in C#
- Implicit Type Casting at Cppreference.com
- Static and Reinterpretation castings in C++