Полиморфный Enum в C ++ - PullRequest
       19

Полиморфный Enum в C ++

6 голосов
/ 25 июня 2010

У меня есть эти объявления Enum:

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
};

Очевидно, я повторяю элементы в Enum.Есть ли способ предотвратить это?

РЕДАКТИРОВАТЬ: я использую "MessageType" в классе общего назначения, чтобы отправить его через сеть, с другой стороны, я анализирую объект этого класса и отправлять сообщения.Но у меня разные клиенты;некоторые ожидают только объекты с членом типа «Request», а некоторые ожидают только объекты с членом типа «Response».

Используя класс «Message», я создаю «DispatcherRequest».

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


struct DispatcherRequest
{
..........
    Request type;
};

Ответы [ 9 ]

6 голосов
/ 25 июня 2010

Почему бы не попробовать что-то подобное?

enum MainType{  
    REQUEST,
    RESPONSE
};

enum SubType{
    LOGIN,
    GET_FIELD
};

class Message {
   MainType type;
   SubType sub_type;
   ...
};
4 голосов
/ 25 июня 2010

Трудно сказать, не зная идеи этого дизайна, но вы могли бы рассмотреть более объектно-ориентированный подход. Что-то вроде:

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

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

class Response : public Message {
    public:
        virtual void send();
}
2 голосов
/ 25 июня 2010

Если мой комментарий к ответу PeterK такой же ясный, как и грязь, вот код:

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;
};
2 голосов
/ 25 июня 2010

Вы намекаете на полиморфные перечисления, почему бы просто не использовать одно перечисление и назвать его так, как вы планировали назвать базовое перечисление, скажем «Тип сообщения»?Это удержит вас от повторения элементов.

0 голосов
/ 08 марта 2013

возможно, подход, который я дал в ответ на этот вопрос , может лучше соответствовать вашим целям проектирования.Для ясности вот код, адаптированный к вашему вопросу.

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;

Единственное предостережение, с которым я столкнулся до сих пор, заключается в том, что поля типа Request и типа Response можно напрямую сравнивать сдруг с другом, используя == или !=, независимо от того, что 2 являются разными типами.

Это может быть не так при реализации строго типизированных перечислений в C ++ 11, но мой компилятор не поддерживает эту функцию, поэтому я не могу проверить.

Надеюсь, это поможет.Ура!

0 голосов
/ 25 июня 2010

Возможно, не используя перечисления?

Я всегда чувствую себя ограниченным перечислениями C ++ ... они просто не дают достаточной гибкости для моих вкусов.поведение, и вы можете ограничить клиента:

void someServerFunc(MessageType const& type);

void someClientFunc(RequestType const& type);

Тадааам!

0 голосов
/ 25 июня 2010

почему бы вам просто не сделать что-то вроде этого:

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

Простая перегрузка?

0 голосов
/ 25 июня 2010

В вашем примере кода значения из перечисления Request и enum Response имеют одинаковые значения (0 для REQ_LOGIN и RES_LOGIN и 1 для REQ_GET_FIELD и RES_GET_FIELD), а их значения не соответствуют значениям в перечислении MessageType (0 для REQ_LOGIN, 1 для REQ_GET_FIELD, 2 для RES_LOGIN и 3 для RES_GET_FIELD). Разве это не проблема?

Если вы хотите иметь одинаковое число перечислений, вы можете попробовать следующий подход:

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

это перечисление MessageCategories и const int Watermark являются общими для всех классов. Теперь вы можете переопределить свои перечисления следующим образом:

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,
}

В этом случае вам не нужен ваш перечислимый MessageType, потому что все ваши перечислимые коды согласованы.

0 голосов
/ 25 июня 2010

Шпион из Java (извините за черновой просмотр):

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
{
};
...