C++ - 将静态映射初始化为私有类成员

22

假设有一个深夜我感到相当无聊,凝视着电脑屏幕几个小时之后,我决定实现一个C++聚合类来管理绘制像素的颜色,因为我显然已经疯了。首先,我们将告诉(可能是单例的)ColorManager对象我们想要使用哪种颜色,它将返回一个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对象,而VC++ 2010似乎不喜欢您尝试的任何内容。所以问题是,我该如何在哪里初始化此映射?

显然,这是一个编造的例子,但除此之外,也许为作为单例函数的类定义静态变量不值得麻烦。或者,也许我可以将变量声明为getColor()内的静态变量,因为那是唯一使用它的函数,并且只会在第一次调用函数时产生开销(虽然对于这个简单的示例来说,这并没有比在其中放置一个巨大的switch语句要好多少)。

无论如何,我感谢您的反馈。

6个回答

18
#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();

或者使用 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;
}();

9

std::map有一个构造函数,它以一对迭代器作为参数,因此您可以使用一组键值对数组初始化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);

在C++0x中,您将能够简单地执行以下操作:
ColorManager::ColorMap ColorManager::colorMap({{RED, Color(...)},
                                               {BLUE, Color(...)},
                                               {GREEN, Color(...)},
                                               ...});

6

使用一个静态方法来创建一个初始化的映射:

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

其中makeColorMap是以下静态方法:

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

  return retval; 
}

我将ildjarn的答案标记为已接受,但这是在大约同一时间给出的相同解决方案,因此进行了点赞。 - Shaun
谢谢!我注意到我们同时提交了类似的解决方案。 - Andre Holzner

1
一种选择是将 ColorMaptypedef 更改为自己的自定义类型,并使用正确初始化映射内容的构造函数。这样,当您静态初始化 ColorMap 时,构造函数将用正确的数据填充它,并且任何尝试使用 ColorManager 的操作都将看到正确配置的 ColorMap

1
你可以这样做,而不需要使用类:
Color getColor(COLOR color)
{
      static std::map<COLOR, Color> colorMap;
      if(colorMap.empty()) // Only runs once.
      {
          colorMap[BLUE] = Color();
          // ... etc ...
      }

      return colorMap[color];
}

实际上,我在我的问题中提到了这种方法。但是,ColorManager是一个更大、更复杂、具有更多功能的类的模拟器,因此我并不想将其去除。 - Shaun

-2

你可以在 .cpp 文件中进行初始化,如下:

ColorManager::ColorMap ColorManager::colorMap;

ColorManager 构造函数中,您创建所有 Color 实例并填充它们。

在VS2010中,这会导致xtree在运行时发生内存访问违规,可能是在类构造函数中分配值时发生的。虽然它确实可以编译。 - Shaun
@SHaun 显然你在构造函数中做错了什么...小心不要依赖其他静态变量。 - littleadv

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接