سؤال

هذه مشكلة متورطة ، لذلك سأبذل قصارى جهدي لشرح ما يجري. إذا فاتني شيء ما ، من فضلك قل لي حتى أتمكن من التوضيح.

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

typedef int (*callback)(void*); // This is NOT in our code, but makes explaining easier.

installCallback(string serviceName, callback cb); // Really handled by a proper management system

sendMessage(string serviceName, void* arg); // arg = value to pass to callback

هذا يعمل بشكل جيد للأنواع الأساسية مثل الهياكل أو المدمجة.

لدينا بنية MI مثل هذا:

Device <- Disk <- MyDiskProvider

class Disk : public virtual Device
class MyDiskProvider : public Disk

قد يكون المزود أي شيء من برنامج تشغيل الأجهزة إلى القليل من الغراء الذي يتولى صور القرص. النقطة هي أن الفئات ترث القرص.

لدينا "خدمة" يجب إخطارها بجميع الأقراص الجديدة في النظام ، وهذا هو المكان الذي تنهار فيه الأشياء:

void diskHandler(void *p)
{
    Disk *pDisk = reinterpret_cast<Disk*>(p); // Uh oh!

    // Remainder is not important
}

SomeDiskProvider::initialise()
{
    // Probe hardware, whatever...

    // Tell the disk system we're here!
    sendMessage("disk-handler", reinterpret_cast<void*>(this)); // Uh oh!
}

المشكلة هي ، يومًا ما يرث القرص ، لكن معالج رد الاتصال لا يمكن أن يتلقى هذا النوع (حيث يجب أن يكون مؤشر وظيفة رد الاتصال عامًا).

هل يمكن أن تساعد RTTI والقوالب هنا؟

فإن أي اقتراحات موضع تقدير كبير.

هل كانت مفيدة؟

المحلول

على الرغم من أنني لست متأكدًا بنسبة 100 ٪ ، فأنا أعتقد أن static_cast من t* إلى void* والعودة إلى نوع المؤشر الأصلي t* يجب أن يعمل. كما أراها ، فإن المشكلة تكمن في أن إعادة PRETPRET_CAST تغير فقط نوع المؤشر دون تغيير قيمته الفعلية و static_cast في حالة الميراث يجب أن يعدل مؤشرًا بحيث يشير إلى بداية الكائن.

تنصل: أنت على الجانب المظلم من اللغة هنا ولا يمكنني ضمان أنها ستعمل على الإطلاق.

نصائح أخرى

الرمز الخاص بك يبدو محفوف بالمخاطر. المشكلة هي أنك تلمي SomeDiskProvider * إلى void * ثم يلقيها مرة أخرى إلى Disk *.

يجب أن تعود إلى النوع الدقيق الذي ألقيته منه. لذلك يمكنك أولاً أن تلقي بك SomeDiskProvider * إلى Disk *:

reinterpret_cast<void*>(static_cast<Disk *>(this))

أو قمت بالعودة إلى أ SomeDiskProvider *:

SomeDiskProvider *pDisk = reinterpret_cast<SomeDiskProvider*>(p);

reinterpret_cast<> على ما يرام إذا كنت تتحول من some_type * إلى void * والعودة مرة أخرى. ومع ذلك ، قلت إنك تستخدم ميراثًا متعدد ، وفي هذه الحالة this في فصل واحد في التسلسل الهرمي قد لا يكون له نفس القيمة this في فصل آخر ؛ dynamic_cast<> تم تصميمه للسير في شجرة الميراث ويمنحك الإجابة الصحيحة.

لذلك ، في SomeDiskProvider استخدم كلا الممثلين:

SomeDiskProvider::initialise()
{
    // Gets the right value for 'this' for the Disk part of SomeDiskProvider.
    Disk *pDisk = dynamic_cast<Disk *>(this);

    // OK, since the callback converts it back to Disk *
    sendMessage("disk-handler", reinterpret_cast<void*>(this));
}

رد الاتصال هو بالضبط كما أوضحت في سؤالك.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top