2011-06-02 36 views
14

Digamos que estaba bastante aburrido una tarde por la noche y después de mirar catatónicamente el monitor de la computadora por unas horas, decidí implementar una clase agregada de C++ para administrar colores para dibujar píxeles porque obviamente me he vuelto loco Para empezar, le diremos al objeto ColorManager (probablemente único) el color que queremos usar y devolverá un objeto Color, cualquiera que sea. Una sencilla IMPLEMENTACIÓN sigue:C++ - Inicializando un mapa estático como miembro de clase privada

#include "Color.h" 
#include <map> 

enum COLOR { RED = 0, BLUE, GREEN, YELLOW, ORANGE, WHITE, BLACK, 
    BRICKS_FROM_A_DISTANCE_ON_AN_UNUSUALLY_SUNNY_AFTERNOON, 
    // etc 
    COLOR_COUNT }; 

class ColorManager 
{ 
public: 
    ColorManager(); 
    ~ColorManager(); 
    Color getColor(COLOR color) const; 
private: 
    typedef std::map<COLOR, Color> ColorMap; 
    static ColorMap colorMap; 
}; 

Por lo tanto, es de esperar, este código simple:

ColorManger colorManager; 
Color blue = colorManager.getColor(BLUE); 

debería hacer que sea muy fácil para nosotros hacer cualquier tontería para el que se necesitaría objetos de color.

El problema es que debe inicializar su ColorMap privado estático en alguna parte para que cada ENUM de COLOR corresponda a un objeto Color adecuado, y no parece que VC++ 2010 le guste nada de lo que intenta. Entonces, la pregunta es, ¿cómo y dónde inicializo este mapa?

Obviamente, este es un ejemplo artificial, pero más allá de eso, quizás la definición de variables estáticas para una clase que funciona como singleton no vale la pena. O, quizás, también podría declarar la variable estática dentro de getColor() ya que esa es la única función que lo usa, y solo incurrir en la sobrecarga la primera vez que se llama a la función (aunque para este simple ejemplo, eso no es mucho mejor) que simplemente poner una declaración de cambio gigante allí). En cualquier caso, agradezco los comentarios.

Respuesta

12
#include <map> 
#include "Color.h" 

enum COLOR 
{ 
    RED = 0, BLUE, GREEN, YELLOW, ORANGE, WHITE, BLACK, 
    BRICKS_FROM_A_DISTANCE_ON_AN_UNUSUALLY_SUNNY_AFTERNOON, 
    // etc 
    COLOR_COUNT 
}; 

class ColorManager 
{ 
    typedef std::map<COLOR, Color> ColorMap; 

public: 
    ColorManager(); 
    Color getColor(COLOR color) const; 

private: 
    static ColorMap createColorMap(); 
    static ColorMap colorMap; 
}; 

// in some .cpp file: 

ColorManager::ColorMap ColorManager::createColorMap() 
{ 
    ColorMap ret; 
    // populate ret 
    return ret; 
} 

ColorManager::ColorMap ColorManager::colorMap = ColorManager::createColorMap(); 

O con C++ 11:

#include <map> 
#include "Color.h" 

enum COLOR 
{ 
    RED = 0, BLUE, GREEN, YELLOW, ORANGE, WHITE, BLACK, 
    BRICKS_FROM_A_DISTANCE_ON_AN_UNUSUALLY_SUNNY_AFTERNOON, 
    // etc 
    COLOR_COUNT 
}; 

class ColorManager 
{ 
    using ColorMap = std::map<COLOR, Color>; 

public: 
    ColorManager(); 
    Color getColor(COLOR color) const; 

private: 
    static ColorMap colorMap; 
}; 

// in some .cpp file: 

ColorManager::ColorMap ColorManager::colorMap = [] 
{ 
    ColorMap ret; 
    // populate ret 
    return ret; 
}(); 
1

Una opción sería cambiar ColorMap de un typedef en su propio tipo personalizado con un constructor que inicializa correctamente el contenido del mapa. De esta forma, cuando inicialice de manera estática el ColorMap, el constructor lo completará con los datos correctos y cualquier operación que intente usar el ColorManager verá el ColorMap configurado correctamente.

-2

inicializar en el .cpp, como

ColorManager::ColorMap ColorManager::colorMap; 

y en el ColorManager constructor que crea todas las instancias de Color y llenarlo.

+0

en VS2010, esto provoca una violación de acceso de memoria en tiempo de ejecución XTree, presumiblemente cuando los valores se asignan en el constructor de la clase. Sin embargo, compila. – Shaun

+0

@SHaun obviamente está haciendo algo mal en el constructor ... Tenga cuidado de no confiar en otras variables estáticas. – littleadv

1

Se podía hacerlo de esta manera, sin la necesidad de una clase:

Color getColor(COLOR color) 
{ 
     static std::map<COLOR, Color> colorMap; 
     if(colorMap.empty()) // Only runs once. 
     { 
      colorMap[BLUE] = Color(); 
      // ... etc ... 
     } 

     return colorMap[color]; 
} 
+0

De hecho, mencioné este método en mi pregunta. Sin embargo, ColorManager es un análogo para una clase mucho más grande, mucho más complicada y con mucha más funcionalidad, así que no estoy buscando deshacerme de ella. – Shaun

6

utilizan un método estático que crea un mapa inicializado :

ColorManager::colorMap(ColorManager::makeColorMap()); 

donde makeColorMap es la siguiente método estático:

ColorManager::ColorMap ColorManager::makeColorMap() 
{ 
    ColorMap retval; 
    retval[...] = ...; 
    retval[...] = ...; 
    ... 

    return retval; 
} 
+0

Marqué la respuesta de ildjarn como aceptada, pero esta es la misma solución que se dio aproximadamente al mismo tiempo, por lo que se votó en sentido ascendente. – Shaun

+0

gracias! Me di cuenta de que al mismo tiempo estábamos presentando soluciones similares. –

6

std :: mapa tiene un constructor que toma un par de iteradores como argumentos, por lo que pudo inicializar el mapa con, por ejemplo, un array de pares:

#include "Color.h" 

#include <map> 

enum COLOR { RED = 0, BLUE, GREEN, YELLOW, ORANGE, WHITE, BLACK, 
    BRICKS_FROM_A_DISTANCE_ON_AN_UNUSUALLY_SUNNY_AFTERNOON, 
    // etc 
    COLOR_COUNT }; 

class ColorManager 
{ 
public: 
    ColorManager(); 
    ~ColorManager(); 
    Color getColor(COLOR color) const; 
private: 
    typedef std::map<COLOR, Color> ColorMap; 
    static ColorMap colorMap; 
}; 

using std::make_pair; 
using std::pair; 

std::pair<COLOR, Color> colorPairs[] = {make_pair(RED, Color(...)), 
             make_pair(BLUE, Color(...)), 
             make_pair(GREEN, Color(...)), 
             ...}; 

ColorManager::ColorMap ColorManager::colorMap(colorPairs, colorPairs + COLOR_COUNT); 

en C++ 0x, usted será capaz de simplemente hacer esto:

ColorManager::ColorMap ColorManager::colorMap({{RED, Color(...)}, 
               {BLUE, Color(...)}, 
               {GREEN, Color(...)}, 
               ...}); 
Cuestiones relacionadas