views:

172

answers:

8

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;
};
+4  A: 

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();
}
Thomas
I need Enums as class members, I don't see your point.
metdos
Sorry about that, but I don't see your point either. Maybe if you elaborated the thoughts behind your design a bit more, show us what these enums are modelling and how this code is used?
Thomas
@Thomas, Edited
metdos
I think you forgot `: public Message` in two places.
Mike DeSimone
@Mike DeSimone: So I did, thanks!
Thomas
@metdos: Since you already have a class `Message`, why can't you inherit those two subclasses from it and remove the `messageType` field?
Thomas
If you want to get rid of `messageType`, you could replace it with a `virtual int getMessageType() = 0;` in `Message` and `virtual int getMessageType() { return REQUEST; }` in `Request`, for example. I wonder which would perform better; my money's on `messageType`. Too bad C++ doesn't let you do `virtual static const int messageType = 0;` in `Message` and `virtual static const int messageType = REQUEST;` in `Request`, i.e. let you store the constants in the vtables instead of the objects... ^_-
Mike DeSimone
+1  A: 

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.

nathan
I don't want client to know other elements of general enumeration.
metdos
I understand your point, but from the code posted it looks as if your attempt to isolate the clients from the other elements may be overkill. As coded, if you change either enumeration your clients will have to be re-compiled. Additionally, on the client side, they don't necessarily have to "know" about the other enumeration values. They can just ignore the ones they don't care about.
nathan
+6  A: 

Why not try something like this?

enum MainType{  
    REQUEST,
    RESPONSE
};

enum SubType{
    LOGIN,
    GET_FIELD
};

class Message {
   MainType type;
   SubType sub_type;
   ...
};
PeterK
+1. I think this is a neat solution, but maybe with some information it can be refined further.
Skurmedel
+1. Although, it is not what I exactly need, it is an innovative solution.
metdos
You could combine this answer with Thomas's. Define `enum MainType` in `class Message` and define `enum SubType` in `class Request` and `class Response`. Move `SubType sub_type` from `Message` into `Request` and `Response`. This allows each message type to have its own distinct subtypes (read: only the legal ones). Then the enum values in the code look like `Message::REQUEST` and `Response::GET_FIELD`, which is about as readable as you can get.
Mike DeSimone
A: 

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
{
};
Dewfy
A: 

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.

Haspemulator
Yes it is a problem, but in your solution how can I use void sendMessage(MessageType mes); function? Do you propose to use "int" instead of enum in function headers?
metdos
Yes, you have to use 'int' instead of enum in general functions, which deal with all enum values. However, you still can use specific enums for specific functions.
Haspemulator
A: 

why won't you just do something like this:

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

Simple overload?

Kamil Klimek
What will be happen to MessageType member in Message Class.
metdos
+2  A: 

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;
};
Mike DeSimone
A: 

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!

Matthieu M.