2010-11-19 102 views
1

我正在構建「系統」,以便稍後可以在「基於操作」的環境中編寫。我想要的是給我的實例(即「汽車」)一定的狀態(即停車,駕駛,起步)。那麼在某些情況下,應該根據狀態執行代碼。將常規類成員轉換爲靜態類成員

我不想使用一個開關/的if-then-else語句,因爲這是很容易出錯&難以擴展。 (爲了允許更多的狀態)。相反,我想使用函數指針。

我的代碼(忽略的功能sillyness,他們證明):

#define CALL_MEMBER_FN(object,ptrToMember) ((object).*(ptrToMember)) 
enum State {Set, Add, Mul}; 
class car { 
public: 
    typedef void (car::*MemFn)(int v); 
    car(int v, State _s) : val(v), s(_s) { 
     posFunctions.insert(std::make_pair(State(Set),&car::SetVal)); 
     posFunctions.insert(std::make_pair(State(Add),&car::AddVal)); 
    } 
    void DoIt(int v) { 
     //MemFn t = &car::SetVal; 
     MemFn t = posFunctions.find(s)->second; 
     CALL_MEMBER_FN(*this,t)(v); 
    } 
    int val; 
    State s; 
protected: 
    std::map<State,car::MemFn> posFunctions; 
    void SetVal(int v) { 
     val = v; 
    } 
    void AddVal(int v) { 
     val += v; 
    } 
    void MulVal(int v) { 
     val *= v; 
    } 
}; 

這個工程,我期望的那樣。 (我可以調用創建一個汽車對象,給它一個特定的狀態,然後調用「doit - 這將是該事件觸發的功能」來執行這些操作)。

然而,有1件很煩人的事情:我創建函數映射(映射與功能的狀態來執行),每節車廂的對象獨立。這實際上並不「真實」(事實上,每個汽車在狀態&事件相同時總是執行相同的操作),因此容易出錯/難看。

我試圖使「posFunctions」靜態地圖,並使用用於2線在構造的靜態初始化功能。

main.obj:錯誤LNK2001:無法解析的外部符號 「受保護:靜態類的std ::地圖,一流的std ::分配器>>汽車:: posFunctions」?(posFunctions @汽車@@ 1V $ @地圖W4State @@ P8car @@ @ AEXH ZU?$ @少@@@ W4State STD @@ V'$分配器@ U&$對@ $$ CBW4State @@ P8car @@ AEXH @ Z @ STD @@@ 4 @@性病@@ A) 我想這是因爲我訪問一個非靜態成員函數 - 即使它是指向?

是它可能使地圖靜態(或全球)?

謝謝你的幫助, paul23

+0

你的鏈接錯誤放在一邊(其他人已經在下面回答了),你有沒有考慮使用狀態模式來建模?可能會做出更清晰的實施。 http://en.wikipedia.org/wiki/State_pattern – razlebe 2010-11-19 17:02:24

+0

感謝大家的答案,我真的需要更加小心這些事情。 – paul23 2010-11-19 17:14:25

+0

如果您的編譯器沒有它,請使用std :: function或boost :: function。 – 2010-11-19 17:16:45

回答

1

這是可能的 - 你必須在1處(本類最有可能的CPP文件)定義靜態變量。

std::map<State,car::MemFn> car::posFunctions; 

你在頭文件中有哪些僅僅是一個聲明

這類似於你必須提供一個功能定義在每個.cpp文件的方式工作,你在頭聲明。如果你錯過了任何函數體,連接器將會在每個缺少的函數上給出相同的錯誤。

要初始化按需這種結構,(如果需要在一個線程安全的方式)提供被從你的類構造函數,但檢查稱爲靜態成員函數,不管它是被稱爲前。

void car::initFunctions() 
{ 
    static bool done(false); 
    if (done) 
    return; 

    // first pass, set up the map 
    done = true; 
} 
3

只要你宣佈你map靜態的,你需要添加下面一行在您的實現文件:

std::map<State,car::MemFn> car::posFunctions;

下面是相關C++ FAQ項的鏈接。

+0

這剛剛爲我解決了一個令人討厭的編譯錯誤,+1謝謝 – Freddie 2011-08-04 12:56:13

2

你忘了在地圖上定義一個全球範圍內,即

std::map<State,car::MemFn> car::posFunctions;

在您定義的車.cpp文件

一般來說,當你做出這樣的結構時,問問自己 - 你可以用多態性來代替嗎?