Проблемы с динамическим приведением от родителя к ребенку
Я работаю над базовым клиент-серверным приложением на языке C++, использующим сокеты, которые будут запускать игру battleship. Вся коммуникация между клиентом и сервером осуществляется в виде простой иерархии объектов, которая выглядит примерно так:
namespace Message {
enum MessageType { BASE, RESULT };
class BattleshipMessage {
public:
virtual MessageType get_type() { return BASE; }
virtual ~BattleshipMessage() {}
};
class ResultMessage : public BattleshipMessage {
public:
char _attackResult;
ResultMessage( char result ) : _attackResult( result ) {}
virtual MessageType get_type() { return RESULT; }
~ResultMessage() {}
};
}
При получении объекта, отправленного через сокет, я хотел бы иметь возможность получить его как универсальный BattleshipMessage, а затем на основе MessageType, возвращенного get_type (), привести его к соответствующему дочернему классу, чтобы получить все, что угодно дополнительная информация, которая может понадобиться для обработки сообщения. Я боюсь, что C# сделал меня мягким, поскольку я сделал это с легким синтаксисом, таким как ResultMessage result = message as ResultMessage
, однако я застрял, пытаясь заставить мою реализацию C++ работать.
BattleshipMessage* message;
recv( hAccepted, reinterpret_cast<char*>( &message ), sizeof(message), 0 );
switch ( message->get_type() ) {
case RESULT:
if ( ResultMessage* result = dynamic_cast<ResultMessage*>(message)) {
std::string celebration = "HOORAY!";
}
break;
}
Я получаю Access violation reading location
, когда разыменовываю указатель и пытаюсь вызвать get_type(). Может ли кто-нибудь указать мне правильное направление?
2 ответа:
sizeof(message)
Задает размер указателя, который обычно является 32-разрядным или 64-разрядным в зависимости от вашей машины. Вы хотите
sizeof(BattleshipMessage)
, что дает размер класса. Даже тогда я не уверен, что это правильный подход, так как каждый объект класса будет содержать указатель на vtable, который обрабатывает вызовы динамической диспетчерской/виртуальной функции, и отправка класса через машины с использованием метода необработанного приведения, который вы используете, сделает этот указатель недействительным.
Я думаю, что вы должны сначала сериализовать ваш объект (т. е. преобразовать его в поток символов) перед отправкой по сети, а затем десериализовать для восстановления класса: можно ли сериализовать и десериализовать класс В C++?