Я работаю над базовым клиент-серверным приложением на C ++, используя сокеты, которые будут запускать игру на линкоре. Все взаимодействие между клиентом и сервером происходит в форме простой иерархии объектов, которая выглядит примерно так:
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 (). Может кто-то указать мне верное направление?
sizeof(message)
дает размер указателя, который обычно составляет 32-разрядный или 64-разрядный в зависимости от вашей машины. Ты хочешь
sizeof(BattleshipMessage)
который дает размер класса. Даже тогда, я не уверен, что это правильный подход, так как каждый объект класса будет содержать указатель на виртуальную таблицу, которая обрабатывает динамические диспетчерские / виртуальные вызовы функций, и отправка класса между компьютерами с использованием используемого метода прямого приведения приведет к аннулированию этот указатель.
Я думаю, что вы должны сначала сериализовать свой объект (т.е. преобразовать его в поток символов) перед отправкой его по сети, а затем десериализовать, чтобы восстановить класс:
Можно ли сериализовать и десериализовать класс в C ++?
Избавьтесь от всех виртуальных методов и сохраните MessageType как переменную-член в BattleshipMethod. Тогда ваш код должен работать.