С++ - Инициализация статической карты как частного члена класса
Скажем, мне было очень скучно один поздний вечер и после того, как я кататонически смотрел на монитор компьютера в течение нескольких часов, я решил реализовать совокупный класс С++ для управления цветами для рисования пикселей, потому что я, очевидно, сошел с ума. Во-первых, мы просто скажем объекту ColorManager (возможно, singleton), какой цвет мы хотим использовать, и он вернет объект Color, что бы это ни было. Простая реализация:
#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;
};
Итак, надеюсь, этот простой код:
ColorManger colorManager;
Color blue = colorManager.getColor(BLUE);
должно помочь нам сделать все, что угодно, для чего вам нужны объекты Color.
Проблема заключается в том, что вам нужно инициализировать свою старую конфиденциальную ColorMap где-нибудь, чтобы каждое перечисление COLOR соответствовало правильному объекту Color, а VС++ 2010, похоже, не нравится, что вы пытаетесь. Итак, вопрос в том, как и где я инициализирую эту карту?
Очевидно, что это надуманный пример, но помимо этого, возможно, определение статических переменных для класса, который функционирует как одноэлементный, не стоит проблем. Или, возможно, я мог бы просто объявить переменную static внутри getColor(), поскольку она единственная функция, которая ее использует, и просто накладывает накладные расходы при первом вызове функции (хотя для этого простого примера это не намного лучше чем просто поставить гигантское выражение о переключении). В любом случае, я ценю отзывы.
Ответы
Ответ 1
#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();
Или с С++ 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;
}();
Ответ 2
используйте статический метод, который создает инициализированную карту:
ColorManager::colorMap(ColorManager::makeColorMap());
где makeColorMap
- следующий статический метод:
ColorManager::ColorMap ColorManager::makeColorMap()
{
ColorMap retval;
retval[...] = ...;
retval[...] = ...;
...
return retval;
}
Ответ 3
std:: map имеет конструктор, который принимает пару итераторов в качестве аргументов, поэтому вы можете инициализировать карту с помощью, например, массива пар:
#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);
В С++ 0x вы сможете просто сделать это:
ColorManager::ColorMap ColorManager::colorMap({{RED, Color(...)},
{BLUE, Color(...)},
{GREEN, Color(...)},
...});
Ответ 4
Один из вариантов - изменить ColorMap
с typedef
на свой собственный тип с конструктором, который правильно инициализирует содержимое карты. Таким образом, когда вы статически инициализируете ColorMap
, конструктор заполнит его соответствующими данными, а любые операции, которые пытаются использовать ColorManager
, будут отображаться правильно настроенными ColorMap
.
Ответ 5
Вы можете сделать это так, не требуя класса:
Color getColor(COLOR color)
{
static std::map<COLOR, Color> colorMap;
if(colorMap.empty()) // Only runs once.
{
colorMap[BLUE] = Color();
// ... etc ...
}
return colorMap[color];
}
Ответ 6
Вы инициализируете его в .cpp, как
ColorManager::ColorMap ColorManager::colorMap;
а в конструкторе ColorManager
вы создаете все экземпляры Color
и заполняете его.