التحويل في c++

التحويل في c++
تحويل الأنواع في سي بلس بلس : وهي عبارة عن مجموعة طرق للتحويل من نوع إلى نوع معين في لغة ++C , مثلها مثل أي لغة أخرى , وبما أن لغة ++C لغة مميزة عن غيرها فلها طرق تحويل خاصة بها ,ويجب عليك كمبرمج لغة ++C أن تعرف كيف تتعامل مع هذه التحويلات بدقة لكي لا تكون برامجك عرضة للأخطاء التي أحيانا قد لاتكتشفها أثناء كتابة برنامجك .
التحويل الضمني
التحويل الضمني لايتطلب أي معامل , ويتم تنفيذها تلقائيا عندما يتم نسخ قيمة من نوع معين إلى نوع آخر موافق .
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.
التحويل الصريح
العديد من التحويلات , خاصة تلك التي تعبر عن تفسيرات مختلفة في القيمة ,مثل هذه التحويلات تحتاج إلى تحويل صريح .
يوجد نمطين للتحويل الصريح هو الوظيفي (الدالي) 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)
وكل نوع من أنواع التحويل لديها مايميزها عن الآخر .
التحويل الديناميكي
يمكن أن يستخدم التحويل الديناميكي فقط مع المؤشرات والمراجع إلتي تشير إلى الكائنات 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
انظر أيضًا
لغة السي
الكائنات في لغة ++C
المتغيرات في لغة ++C
أنواع البيانات في لغة ++C
مراجع
أنواع البيانات
قواعد لغة سي++
مشغلات (برمجة)
نظرية النمط