Прохождение производных экземпляров классов как пустота * до общих обратных вызовов в C ++
-
30-09-2019 - |
Вопрос
Это немного связанной проблемы, поэтому я сделаю все возможное, чтобы объяснить, что происходит. Если я что-то скучаю, скажи мне, чтобы я мог уточнить.
У нас есть система обратного вызова, в которой на одной стороне модуль или приложение предоставляет «сервис», и клиенты могут выполнять действия с помощью этой услуги (очень элементарный 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));
}
Обратный вызов точно так, как вы показали его в вашем вопросе.