开发者

Polymorphic Enum in C++

I have these Enum declarations:

enum MessageType{  
    REQ_LOGIN,
    REQ_GET_FIELD,       

    RES_LOGIN,
    RES_GET_FIELD
}

enum Request{
    REQ_LOGIN,
    REQ_GET_FIELD
};

enum Respond{
    RES_LOGIN,
    RES_GET_FIELD
};

Obviously I'm repeating elements in Enum's. Is there any way to prevent this?

EDIT: I'm using "MessageType" on a general purpose class to send it through network, on the other side I parse the object of this class and dispatch message. But I have different clients; some expects only objects with "Request" type member and some expects only objects with "Response" type member.

Using "Message" class, I'm creating "DispatcherRequest"s.

class Message
{
public:
……….
    MessageType messageType;
}


struct DispatcherRequest开发者_开发百科
{
..........
    Request type;
};


Why not try something like this?

enum MainType{  
    REQUEST,
    RESPONSE
};

enum SubType{
    LOGIN,
    GET_FIELD
};

class Message {
   MainType type;
   SubType sub_type;
   ...
};


This is hard to say without knowing the idea behind this design, but you might consider a more object-oriented approach. Something along the lines of:

class Message {
    public:
        virtual void send() = 0;
};

class Request : public Message {
    public:
        virtual void send();
}

class Response : public Message {
    public:
        virtual void send();
}


You allude to polymorphic enumerations, why not just use one enumeration and name it whatever you had planned on naming the base enumeration, say "Message Type"? This would keep you from repeating elements.


In case my comment on PeterK's answer is as clear as mud, here's the resulting code:

class Message {
public:
    enum MainType {  
        REQUEST,
        RESPONSE
    };
    Message(MainType type_): type(type_) {}
    virtual void send() = 0;
private:
    MainType type;
};

class Request: public Message {
public:
    enum SubType {
        LOGIN,
        GET_FIELD
    };
    Request(SubType sub_type_): Message(Message::REQUEST), 
        sub_type(sub_type_) {}
    virtual void send();
private:
    SubType sub_type;
};

class Response: public Message {
public:
    enum SubType {
        LOGIN,
        GET_FIELD
    };
    Response(SubType sub_type_): Message(Message::RESPONSE), 
        sub_type(sub_type_) {}
    virtual void send();
private:
    SubType sub_type;
};


Spy from java (sorry for draft view):

class MessageType
{  
protected:
    MessageType(int value);//visible for descending classes only
    MessageType(const MessageType& other);
public:
    static const MessageType REQ_LOGIN, //assign later with integer value
    REQ_GET_FIELD,       

    RES_LOGIN,
   RES_GET_FIELD;
}

clas Request : public MessageType
{
};

clas Respond : public MessageType
{
};


In your code example, values from enum Request and enum Response have the same values (0 for REQ_LOGIN and RES_LOGIN and 1 for REQ_GET_FIELD and RES_GET_FIELD), and their values do not comply with values in enum MessageType (0 for REQ_LOGIN, 1 for REQ_GET_FIELD, 2 for RES_LOGIN and 3 for RES_GET_FIELD). Isn't this a problem?

If you want to have consistent numbers of enums, you can try the following aproach:

enum MessageCategories
{
Request = 0,
Response,
AnythingElse
}
const int Watermark = 100;

this enum MessageCategories and const int Watermark are common to all classes. Now you can redefine your enums like following:

enum Request
{
REQ_LOGIN = MessageCategories::Request * Watermark,
REQ_GET_FIELD,
REQ_LAST_ITEM,
}
enum Response
{
RES_LOGIN = MessageCategories::Response * Watermark,
RES_GET_FIELD,
RES_LAST_ITEM,
}

In this case, you don't need your enum MessageType, because all your enum codes are consistent.


why won't you just do something like this:

void sendMessage(Request); void sendMessage(Respond);

Simple overload?


Perhaps by not using enums ?

I always feel constrained with C++ enums... they just don't offer enough flexibility for my tastes.

class MessageType
{
public:
  virtual ~MessageType();
  bool operator==(MessageType const& rhs) const;
  bool operator!=(MessageType const& rhs) const;
protected:
  MessageType(const char* type);
private:
  const char* mType;
};

class RequestType: public MessageType
{
public:
  static RequestType const Login() { return RequestType("Login"); }
  static RequestType const GetField { return RequestType("GetField"); }
protected:
  RequestType(const char* type);
};

// same for ResponseType

Here you have polymorphic behavior, and you can restrict the client:

void someServerFunc(MessageType const& type);

void someClientFunc(RequestType const& type);

Tadaaam!


perhaps the approach I gave in response to this question might better suit your design goals. For clarity, here is the code adapted to your question.

typedef struct{
    enum {
        LOGIN,
        GET_FIELD
    };
}MessageType;

typedef struct : public MessageType {
    //this struct inherits the fields of MessageType,
    //and can be accessed in code like so, Request::LOGIN or Request::GET_FIELD

    //omit this enum declaration if you do not wish to extend the base enum
    enum {
        //additional fields here
    };
}Request;

typedef struct : public MessageType {
    enum {
        //additional fields here
    };
}Response;

The only caveat I've encountered so far is that the fields of the Request type and Response type can be directly compared to each other using == or !=, regardless of the 2 being distinct types.

This might not be the case if implementing strongly typed enums in C++11, but my compiler doesn't support that feature, so I can't test.

Hope this helps. Cheers!

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜