2013-04-21 2 views
3

전함을 사용하는 소켓을 사용하여 C++에서 기본 클라이언트 서버 응용 프로그램을 만들고 있습니다. 소켓을 통해 전송 객체를 수신 할 때부모와 자식의 dynamic_cast 관련 문제

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로받을 수 있도록하고 싶습니다 : 클라이언트와 서버 사이의 모든 통신은 다음과 같이 보입니다 간단한 객체 계층 구조의 형태로 get_type()에 의해 반환 된 MessageType을 기반으로 적절한 자식 클래스에 캐스트하면 메시지를 처리하는 데 필요한 추가 정보를 검색 할 수 있습니다. 나는 C#이 부드럽게 만들었 기 때문에 ResultMessage result = message as ResultMessage과 같은 쉬운 문법으로 이런 종류의 일을 해냈다.하지만 나는 내 C++ 구현을 시도하려고 애써왔다. 내가 포인터 역 참조) (get_type를 호출 할 때

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를 얻을. 누구든지 올바른 방향으로 나를 가리킬 수 있습니까?

+0

'message'가 이미 포인터이기 때문에'reinterpret_cast (message)'하지 않아야합니까? 그렇지 않으면'message'가 가리키는 데이터 대신'message' 주소를 변경합니다. 대답은 또한 좋은 지적을 제기합니다. – loganfsmyth

답변

3

은 포인터 크기를 제공하며, 일반적으로 컴퓨터에 따라 32 비트 또는 64 비트입니다. 원하는 크기

sizeof(BattleshipMessage) 

클래스의 크기를 제공합니다. 그럼에도 불구하고 각 클래스 객체가 동적 디스패치/가상 함수 호출을 처리하는 vtable에 대한 포인터를 포함하고 있으므로 사용하는 원시 형 변환 접근법을 사용하여 클래스를 전송하는 클래스가 무효화되므로 올바른 접근 방식인지는 확실하지 않습니다. 그 포인터. , Is it possible to serialize and deserialize a class in C++?

+0

sizeof를 변경하려고 시도했지만 여전히 동일한 액세스 위반 메시지가 표시됩니다. 내가 게시 한 직렬화 기술을 살펴 보겠습니다. 그러나 BattleshipMessage (포인터와 반대)를 처리 할 때 객체가 char *로 형 변환되고 문제없이 네트워크를 통해 전송되므로 문제가 있는지 확실하지 않습니다. –

+1

vtable에 대한 포인터가 절대로 직접 액세스 할 수 없더라도 vtable의 포인터가 클래스의 메모리 풋 프린트의 일부이기 때문에 객체를 캐스팅 할 수 없습니다. 캐스팅은 예를 들어 다음과 같이 컴파일되고 실행될 수 있습니다. 클래스에 의해 점유 된 공간이 '\ 0'문자를 구성하는 비트를 포함하는 후에 메모리 주소에 저장되지만, 보내고있는 것은 stil 쓰레기입니다. 직렬화가 바로이 이유 때문입니다. – maditya

+0

이 링크를 직렬화 링크에 대한 답으로 표시 할 것입니다. 부스트 버전을 아직 구현하지 않았지만 항상 함께 플레이 한 C# 분산 애플 리케이션에서 직렬화 된 객체를 전달하는 것에 의존했습니다. 시간이 더 필요하다면 여기에서 확실히 적용 할 것입니다. 왜냐하면 더 복잡한 메시징 시스템이 작동하는 올바른 방법을 알고 있기 때문입니다. –

0

모든 가상 메서드 제거하십시오 :

나는 다음 클래스를 재구성하는 역 직렬화, 네트워크를 통해 전송하기 전에 (즉, 문자의 스트림으로 변환) 먼저 개체를 직렬화해야한다고 생각 MessageType을 BattleshipMethod의 멤버 변수로 저장합니다. 그러면 코드가 작동합니다.

+0

BattleshipMessage가 다형성 클래스로 간주되지 않았기 때문에 원래 시도한 것이지만 dynamic_cast를 사용할 수 없었습니다. 또한 포인터를 역 참조하여 메시지 유형을 검사하려고 할 때 동일한 오류 메시지가 나타납니다. –