2011-03-15 9 views
13

tengo una clase en la que tengo una enumeración, que se define así:typedef'ing una enumeración no hace que los valores de enumeración visibles

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

Ahora quiero que esta enumeración sea reutilizado en otra clase, de esta manera:

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

como era de esperar, mediante Y :: Dirección funciona correctamente, por ejemplo:

void myFunction (Y::Direction dir) 
{ 
} 

Pero los valores dentro de la ENU meration no parece ser 'copiado' junto con typedef. Si escribo lo siguiente, tengo errores de compilación:

myFunction (Y::DIR_LEFT); 

En cambio, tengo que referir al lugar original de la enumeración de nuevo, como esto:

myFunction (X::DIR_LEFT); 

lo que contradice mi propósito de typdefing la enumeración.

La única solución que veo es sacar la enumeración de la clase X y ponerla en otra clase (por ejemplo, MyEnums), para que pueda ser reutilizada por X e Y (aunque todavía deben usar MyEnums :: DIR_LEFT y MyEnums :: DIR_RIGHT), pero al menos el código ya no depende de la clase X.

¿Por qué los valores de la enumeración en sí no están expuestos a través de typedef?

¿Hay algún otro patrón para administrar enumeraciones en diferentes clases?

Respuesta

14

Desafortunadamente C++ no introduce un nuevo alcance con un enum aunque C++ 0x está mejorando las cosas.

Prácticamente, esto significa que no se puede tipear una enumeración y obtener también los valores enumerados.

Lo que puede do es utilizar una estructura anidada con el nombre que desea para el enum y typedef THAT.

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

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

Ahora usted puede hacer: myFunction (Y::Direction::LEFT);

El propósito de la estructura anidada es la creación de un ámbito de "falso" a holld tanto el nombre de enumeración y sus valores.

+3

Probablemente deberías eliminar el prefijo 'DIR_' porque era un" espacio de nombre de pobre "artificial:' struct Dirección {enum {LEFT, RIGHT};}; '- solo un poco más sucio que la sintaxis de C++ 0x' enum class Dirección {LEFT, RIGHT}; ' – anatolyg

+0

@anatolyg De hecho, es una buena idea, hice ese cambio. –

0

Cualquier cosa compartida por más de una clase se debe tener en cuenta fuera de las clases y quizás en una clase principal.

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 
+0

¿No estás ahora contaminando el espacio de nombres global con tu enumeración? La versión del OP no tenía este problema. – JBentley

0

Aquí está mi comprensión de cómo funcionan las enumeraciones en C++. (O al menos mi comportamiento observado de enumeraciones en Microsoft Visual C++.)

La palabra clave enum no crea un ámbito de la misma manera que las clases.

El nombre completo para su enum 'Dirección', es X :: Dirección. Los valores dentro de esa enumeración todavía forman parte del alcance de la clase, por lo que son X :: DIR_LEFT y X :: DIR_RIGHT.

Cuando tipea la enum en otra clase, esto no cambia el alcance de los valores de la enumeración.

Le sugiero que ponga la enumeración dentro de un espacio de nombres en un archivo de encabezado si desea compartirlo en varias ubicaciones.

0

Si desea que los valores de enumeración de ser miembros de ambas clases, la solución es definir una clase separada con la enumeración y heredan de ella, por ejemplo:

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

Los usuarios verán X: : Dirección, X :: DIR_LEFT e Y :: Dirección, Y :: DIR_LEFT. Por supuesto, aún podrán pasar un Y :: DIR_LEFT a una función que espera una X :: Dirección; a evitar eso, haga de MyEnums una plantilla, con la clase derivada como el argumento de la plantilla.

+3

ciertamente parece un mal uso de la herencia:/ –

+0

@Matthieu M. ¿Para qué definición de "mal uso"? Es una técnica más o menos estándar en C++ para usar la herencia para compartir declaraciones , ver std :: iterator, por ejemplo. –

+0

no es porque el estándar lo haga necesariamente es bueno. El destructor 'protected' debe protegerse de una serie de problemas, pero aún así es" extraño ", en el sentido de que ahora puedo pasar clases polimórficas que no están relacionadas. El 'typedef' parece una alternativa superior aquí. –

0

Si la primera declaración:

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

se incorpora en una base de código gran legado, a continuación, lo que se quiere una solución que no cambio de los usos existentes de X :: Dirección. En ese caso, el poco agraciado:

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

obras ...

embargo

Definitivamente no recomendado para nuevo código,!

+0

Esto es más o menos lo mismo que volver a definir la enumeración de nuevo. –

+1

Es cierto, excepto que si se cambia la definición original (izquierda y derecha dados diferentes valores, por ejemplo), el código que utiliza la clase Y continúa funcionando correctamente. –

Cuestiones relacionadas