2012-06-07 52 views
1

我需要定义一个生成唯一标识符的C++类。这个想法是,每个可见类的每个实例都将被一个唯一的整数值标记。我们称之为实例的“句柄”。该句柄在系统中的所有实例中必须是唯一的。使用受保护的构造函数的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)不编译(锵3.X)。编译器拒绝静态变量的内联初始化。修复很简单,在实现文件中离线初始化它。所以我的课不能只是标题,但我可以忍受。

  • line(1)定义了我的特殊常量实例。不幸的是,编译器失败,说“预期的参数声明”。

我也试过:static const Handle kUndefHandle = 0;但随后的编译器抱怨“变量具有不完全类型‘拉手’”,即使我把它放在一个子类。我不能像在Ruby中那样用C++重新打开一个类。

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

但是,这只适用于如果我建立行(2)公共构造函数。我不想那样。我不想让程序员用任意值构造句柄。

有什么建议吗?

+0

的常用方法提供的句柄目的是利用其指针值,这是保证是唯一的。 “unset”值自然是NULL。你有想过吗? –

+0

当然,我有。但是这些值在文件中是可见的,并且必须可以跨文件/机器/网络传输。我觉得用这种方式使用指针会感到不舒服。当指针大小在不同机器上不同时,这也会导致头痛。 (是的'int'在这方面也是不好的选择,我使用的实际整型更好)。 –

回答

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

+1这个漏洞更糟糕,它不仅允许恶意代码打破独特的句柄合约,而且还允许错误的代码执行它。此外,由于在Handle层没有显式拷贝构造函数或赋值操作符,对象的拷贝将全部共享句柄值(可能不需要) –

0

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

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; 
相关问题