使用受保护的构造函数的C ++常量实例?

时间:2012-06-07 15:51:49

标签: c++ const instance protected

我需要定义一个生成唯一标识符的C ++类。我们的想法是每个可见类的每个实例都将由唯一的整数值标记。我们称之为实例的“句柄”。句柄在系统中的所有实例中必须是唯一的。

某些实例可能与其他实例相关,在这种情况下,它们的类定义了一个成员来存储其亲属的句柄。

但并非所有实例都有亲戚。所以我需要一个特殊的句柄值来代表一个“未定义的”亲戚。

我需要帮助来定义该特殊实例。这是我试过的:

class Handle {
public:
  Handle(): mValue(newValue()) {};

  static const Handle kUndefHandle(0);         // (1)

protected:
  Handle(int val): mValue(val) {};             // (2)
  int mValue;
  static int mNextValue = 1000; // start at 1000. (3)

  static int newValue() { return mNextValue++; }
};

注意:

  • 第(3)行不编译(Clang 3.x)。编译器拒绝静态变量的内联初始化。修复很简单,在实现文件中将其初始化。所以我的班级不能只是标题,但我可以忍受。

  • line(1)定义了我的特殊常量实例。不幸的是,编译器失败了,说“Expected parameter declarator”。

我也试过:static const Handle kUndefHandle = 0;然后编译器抱怨“变量有不完整类型'Handle'”,即使我把它放在子类中也是如此。而且我不能像在Ruby中一样用C ++重新打开一个类。

我可以通过将const实例声明放在类之外来使其工作。我失去了班级范围,但这是一个小缺点。如果我关心,我仍然可以使用命名空间。

然而,这仅在我将第(2)行中的构造函数设为公开时才有效。我不希望这样。我不想让程序员构造具有任意值的句柄。

有什么建议吗?

3 个答案:

答案 0 :(得分:2)

这对我有用:

标题

class Handle {
public:
  Handle(): mValue(newValue()) {};

  static const Handle kUndefHandle;

protected:
  Handle(int val): mValue(val) {};
  int mValue;
  static int mNextValue;

  static int newValue() { return mNextValue++; }
};

实施

const Handle Handle::kUndefHandle(0);

int Handle::mNextValue = 1000;

初始化静态类成员实际上被认为是在类的范围内,因此您可以在该上下文中访问私有和受保护的构造函数。


请注意,您应该将构造函数设为私有,因为当前存在一个漏洞,人们可以通过这个漏洞构造具有任意值的句柄:派生类,链到受保护的构造函数,然后转换结果对象到Handle。 (See an example on ideone

class FakeHandle : public Handle
{
public:
  FakeHandle(int val) : Handle(val) { }
};

现在可以做到:

Handle badHandle = FakeHandle(5);

答案 1 :(得分:0)

static const成员只有在它们是整数类型时才能在类中初始化。这是一种特殊情况,一般规则是你必须将初始化放在.cpp文件中(以及你的静态非const)。

答案 2 :(得分:0)

这是一个让你入门的骨架:

class Foo
{
    static int const undef_handle;
    static int next_handle;
    static int get_handle() { return ++next_handle; }

    int const my_handle;
    int const related_handle;

public:

    Foo()
    : my_handle(get_handle())
    , related_handle(undef_handle)
    { }

    Foo(int h)
    : my_handle(get_handle())
    , related_handle(h)
    { }

    // Copy/move constructors, assignment, ...
};

int Foo::next_handle = 1000;
int const Foo::undef_handle = 0;