Прохождение производных экземпляров классов как пустота * до общих обратных вызовов в C ++

StackOverflow https://stackoverflow.com/questions/2680310

Вопрос

Это немного связанной проблемы, поэтому я сделаю все возможное, чтобы объяснить, что происходит. Если я что-то скучаю, скажи мне, чтобы я мог уточнить.

У нас есть система обратного вызова, в которой на одной стороне модуль или приложение предоставляет «сервис», и клиенты могут выполнять действия с помощью этой услуги (очень элементарный 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!
}

Проблема в том, что SomediskProvider наследует диск, но обработчик обратного вызова не может принимать этот тип (поскольку указатель функции обратного вызова должен быть универсальным).

RTTI и шаблоны помогают здесь?

Любые предложения будут ценны.

Это было полезно?

Решение

Пока я не намного уверен, что я думаю, что Static_cast из T * в Void * и обратно к исходному типу указателя T * должен работать. Когда я вижу это, проблема в том, что ReinterPret_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 Используйте оба Casts:

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