Typedef'ing enum не делает видимыми значения enum

У меня есть класс, в котором у меня есть перечисление, определенное следующим образом:

class X
   {
   public:
      enum Direction {DIR_LEFT, DIR_RIGHT};
   };

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

class Y
   {
   public:
      typedef X::Direction Direction;
   };

Как и ожидалось, использование Y:: Direction работает правильно, например:

void myFunction (Y::Direction dir)
{
}

Но значения в перечислении не кажутся "скопированными" вместе с typedef. Если я напишу следующее, я получаю ошибки компиляции:

myFunction (Y::DIR_LEFT);

Вместо этого я должен снова ссылаться на исходное место перечисления, например:

myFunction (X::DIR_LEFT);

Что поражает мою цель typdefing перечисления.

Единственное решение, которое я вижу, это переместить перечисление из класса X и поместить его в другой класс (например, MyEnums), поэтому его можно повторно использовать с помощью X и Y (хотя они все равно должны использовать MyEnums:: DIR_LEFT и MyEnums:: DIR_RIGHT), но по крайней мере код больше не зависит от класса X.

Почему сами значения перечисления не отображаются через typedef?

Существуют ли другие шаблоны для управления перечислениями в разных классах?

Ответ 1

К сожалению, С++ не вводит новую область с enum, хотя С++ 0x улучшает ситуацию.

Практически это означает, что вы не можете typedef перечислить и получить также перечисленные значения.

Что вы можете сделать, это использовать вложенную структуру с именем, которое вы хотите для перечисления и typedef THAT.

class X
{
public:
    struct Direction { enum EnumType {LEFT, RIGHT}; };
};

class Y
{
public:
    typedef X::Direction Direction;
};

Теперь вы можете сделать: myFunction (Y::Direction::LEFT);

Назначение вложенной структуры заключается в создании "поддельной" области, которая должна содержать имя перечисления и его значения.

Ответ 2

Все, что разделяется более чем одним классом, должно учитываться вне классов и, возможно, в родительском классе.

direction.hpp:

#ifndef DIRECTION_HPP
enum Direction {DIR_LEFT, DIR_RIGHT};
#endif

x.hpp:

#ifndef X_HPP
#include "direction.hpp"

class X
{
  Direction dir;
};
#endif // X_HPP

y.hpp

#ifndef Y_HPP
#include "direction.hpp"

class Y
{
  Direction dir;
};
#endif // Y_HPP

Ответ 3

Вот мое понимание того, как перечисления работают на С++. (Или, по крайней мере, мое наблюдаемое поведение перечислений в Microsoft Visual С++.)

Ключевое слово enum не создает область действия так же, как это делают классы.

Полное имя для вашего перечисления "Направление" - это X:: Direction. Значения внутри этого перечисления по-прежнему являются частью класса, поэтому они X:: DIR_LEFT и X:: DIR_RIGHT.

Когда вы набираете перечисление в другом классе, это не меняет область значений перечисления.

Я предлагаю вам поместить enum внутри пространства имен в файл заголовка, если вы хотите разделить его в нескольких местах.

Ответ 4

Если вы хотите, чтобы значения перечисления являлись членами обоих классов, решение состоит в том, чтобы определить отдельный класс с перечислением, и наследовать от него, например:

class MyEnums
{
protected:
    ~MyEnums() {} //  Prevent delete through pointer to this class
public:
    enum Direction
    {
        DIR_LEFT,
        DIR_RIGHT
    };
};

class X : public MyEnums
{
    // ...
};

class Y : public MyEnums
{
    // ...
};

Пользователи будут видеть X:: Direction, X:: DIR_LEFT и Y:: Direction, Y:: DIR_LEFT. Конечно, они все равно смогут пройти a Y:: DIR_LEFT для функции, ожидающей X:: Direction; в предотвратите это, сделайте MyEnums шаблоном, с производным классом как аргумент шаблона.

Ответ 5

Если оригинальное объявление:

    class X
    {
    public:
      enum Direction {DIR_LEFT, DIR_RIGHT};
    };

встроен в большую устаревшую базу кода, тогда нам может понадобиться решение, которое не изменяет никаких существующих применений X:: Direction. В этом случае довольно уродливый:

    class Y
    {
    public:
       typedef enum X::Direction Direction;
       static const enum X::Direction DIR_LEFT = X:DIR_LEFT;
       static const enum X::Direction DIR_RIGHT = X:DIR_RIGHT;
    }

работает...

Определенно не рекомендуется для нового кода, однако!