【问题标题】:C++ constant instance using a protected constructor?使用受保护构造函数的 C++ 常量实例?
【发布时间】:2012-06-07 15:51:49
【问题描述】:

我需要定义一个生成唯一标识符的 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)。编译器拒绝静态变量的内联初始化。修复很简单,在实现文件中离线初始化它。所以我的课程不能只包含标题,但我可以忍受。

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

我也尝试过:static const Handle kUndefHandle = 0; 但随后编译器会抱怨“变量的 'Handle' 类型不完整”,即使我将它放在子类中。而且我不能像在 Ruby 中那样在 C++ 中重新打开一个类。

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

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

有什么建议吗?

【问题讨论】:

  • 提供对象句柄的常用方法是使用它的指针值,它保证是唯一的。 “未设置”值自然为 NULL。你有想过吗?
  • 我当然知道。但是这些值在文件中是可见的,并且必须可以跨文件/机器/网络传输。以这种方式使用指针让我感到不舒服。当不同机器的指针大小不同时,这也会让人头疼。 (是的int 从这方面来说也是一个糟糕的选择。我使用的实际整数类型更好)。

标签: c++ constants instance protected


【解决方案1】:

这对我有用:

标题

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 漏洞更严重,它不仅允许恶意代码破坏句柄唯一性的约定,而且还允许错误代码这样做。此外,由于Handle 级别没有显式的复制构造函数或赋值运算符,对象的副本将全部共享句柄值(这可能是不需要的)
【解决方案2】:

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

【讨论】:

    【解决方案3】:

    这是一个帮助您入门的框架:

    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;
    

    【讨论】:

      猜你喜欢
      • 2014-04-22
      • 2011-05-30
      • 2016-01-26
      • 1970-01-01
      • 2013-10-06
      • 2017-01-09
      • 1970-01-01
      • 2011-10-23
      • 2012-06-04
      相关资源
      最近更新 更多