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

من أرابيكا، الموسوعة الحرة
اذهب إلى التنقل اذهب إلى البحث

تحويل الأنواع في سي بلس بلس : (بالإنجليزية: type casting)‏ وهي عبارة عن مجموعة طرق للتحويل من نوع إلى نوع معين في لغة ++C , مثلها مثل أي لغة أخرى , وبما أن لغة ++C لغة مميزة عن غيرها فلها طرق تحويل خاصة بها ,ويجب عليك كمبرمج لغة ++C أن تعرف كيف تتعامل مع هذه التحويلات بدقة لكي لا تكون برامجك عرضة للأخطاء التي أحيانا قد لاتكتشفها أثناء كتابة برنامجك .[1]

التحويل الضمني

التحويل الضمني (بالإنجليزية: 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

انظر أيضًا

مراجع

  1. ^ Computer Science With C++ Programming - Class Xi (بEnglish). Allied Publishers. ISBN:978-81-7023-959-8. Archived from the original on 2020-07-01.