2012-06-07 107 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; 
相關問題