Я использую следующий дизайн для отправки сообщения между 2 приложениями.
class InternalMessage
{
public:InternalMessage(unsigned int messageId, unsigned int messageSize, INTERNAL_MESSAGE_TYPE messageType)
: messageId_(messageId), messageSize_(messageSize), messageType_(messageType) {}
virtual ~InternalMessage() {}protected:
unsigned int messageId_;
unsigned int messageSize_;
INTERNAL_MESSAGE_TYPE messageType_;
};
И затем есть несколько других сообщений, которые используют наследование:
class KeyPressMessage : public InternalMessage
{
public:
KeyPressMessage () : InternalMessage(RADIO_KEY_PRESS_MESSAGE_ID, sizeof(KeyPressMessage ), EVENT_MESSAGE_TYPE),
key_(INVALID_KEY) {}
virtual ~KeyPressMessage () {}}private:
KEY key_;
};
При получении сообщения мы используем указатель базового класса:
MsgHandler(InternalMessage* )
При отправке сообщения мы используем производный класс sizeof inorder для вычисления количества байтов для отправки:
sizeof(KeyPressMessage )
Кажется, что использование такого дизайна плохо, потому что размер производного класса включает в себя виртуальную таблицу (которая может меняться между 32-битной и 64-битной ОС).
Я хотел бы спросить, есть ли лучший способ для реализации ICD обработчика сообщений и отправителя / получателя? Нужна ли мне сериализация / десериализация?
sizeof()
может давать разные результаты даже на одной и той же ОС при использовании разных компиляторов / опций сборки. При написании кода, который работает по сети или с внешними процессами, вам НЕОБХОДИМО написать код сериализации / десериализации.
В вашем примере ситуация еще хуже: вы пишете указатели (VTBL), которые не имеют никакого значения для другого процесса — он может иметь разную структуру памяти и функции будут по разным адресам.
Существует два подхода к обработке сериализации:
Пишите и читайте поля по одному.
Довольно простой и очень портативный. Хотя объем кода несколько больше, чем в других вариантах, он дает преимущества для управления длиной и порядком байтов.
Используйте упакованные структуры данных POD.
Что ж, только примитивные типы, компилятор вынужден не выравнивать их, поэтому они всегда имеют одинаковый размер (при условии, что типы данных фиксированы).
Чтобы убедиться, что все работает всегда, вы должны:
int
, использование int32_t
и аналогично с99.Кроме того, виртуальные указатели не будут указывать на правильный адрес в новом процессе, так что все дело пойдет не так. Это UB и вообще ужасная идея. Вам нужно правильно сериализовать его в какой-то формат, а не просто memcpy
вокруг.