2011-01-26 18 views
0

我有下面的代碼實現了一個基本的邁爾斯singletone:C++邁爾斯單未定義參考

#ifndef _cConfigFile_HH 
#define _cConfigFile_HH 

class cConfigFile { 
public: 
    static cConfigFile& getInstance() { 
    static cConfigFile instance; 
    return instance; 
    }; 
private: 
    cConfigFile(); 
}; 

#endif 

我的編譯器不允許我編譯此,給了以下錯誤:

/include/cConfigFile.hh:7: undefined reference to `cConfigFile::cConfigFile()' 

從錯誤我知道我需要在.cpp文件中聲明「實例」,但無法聲明cConfigFile ::實例,因爲編譯器說:

‘cConfigFile cConfigFile::instance’ is not a static

我在做什麼錯?我迷失在這裏..

+1

爲什麼在`static`關鍵字前面有`-`? – 2011-01-26 18:31:15

+0

對不起,我從emacs粘貼它,其中一個小模式以這種方式格式化源代碼。編輯。 – 2011-01-26 18:32:53

+4

很明顯,這表明vi是優越的;-) – 2011-01-26 18:46:48

回答

9

你忘了實現你的構造函數。

-2

您需要在頭文件的底部初始化靜態實例:

cConfigFile cConfigFile ::實例;

而且你需要採取的靜態實例的聲明中的getInstance()函數之外。

class cConfigFile{ 
public: 
    static cConfigFile instance; //declare 

    cConfigFile & getInstance(){ 

    return instance; 
    } 
private: 
    cConfigFile(){} 
}; 

cConfigFile cConfigFile::instance(); //initialize 
-1

第一條錯誤消息意味着您缺少實例的構造函數。

至於第二:這將是一個很好的主意,包括在.cpp代碼在您試圖定義實例。但是這聽起來像是你試圖將實例變量定義爲一個靜態類,你不應該這樣做。

來實例化實例中一個.cpp,你想有這樣的事情在你的.hh文件:

class cConfigFile { 
public: 
    static cConfigFile& getInstance(); 
private: 
    cConfigFile() {} // Note: define the constructor -- this is probably not enough! 
}; 

這在您的.cpp文件:

cConfigFile& cConfigFile::getInstance() 
{ 
    // Define the singleton as a local static 
    static cConfigFile instance; 

    return instance; 
} 

注意:你真的在.cpp文件來定義getInstance方法,而不是作爲一個內聯函數。將其定義爲內聯將爲您提供一個instance的實例,用於使用標題的每個.cpp文件。這破壞了試圖讓它成爲單身人士的目的!

-2

這不完全是一個答案,只是評論時間太長了其他評論的反應,這是有關這個問題。

請不要使用Singleton。您陳述的理由是您將使用它來存儲配置信息,並且該配置信息需要在程序中的任何地方訪問。

這是一個全局變量的原因(雖然,恕我直言,不一定一個偉大的),但不是一個Singleton的理由。存在配置的多個對象有什麼危害?如果所有用戶使用全局變量來訪問它們,它們將全部使用同一個變量。爲什麼將實例的數量強制限制爲1會有幫助?

其次,在未來會發生什麼,當你需要臨時增加一些配置選項?不知道怎麼說,你的程序需要將自己作爲一個子程序或者稍微不同的配置信息來運行,然後恢復原來的配置?或者,也許你需要用幾種不同的方式來測試配置,然後將其恢復到原始狀態?有了Singleton和一個全局變量,這變得非常棘手。但是如果你使用了更靈活的東西,那很簡單。我個人認爲,將配置選項以明確的方式傳遞給所有需要它們的東西並不一定是一種不好的方式。但如果你認爲這是無法忍受的,這裏是一個另類:

template <typename T> 
class DynamicallyScoped { 
public: 
    explicit DynamicallyScoped(T &stackinstance) : oldinstance_(0) { 
     oldinstance_ = S_curinstance; 
     S_curinstance = &stackinstance; 
    } 
    ~DynamicallyScoped() { 
     S_curinstance = oldinstance_; 
     oldinstance_ = 0; 
    } 
    static T *curInstance() { return S_curinstance; } 

private: 
    static T *S_curinstance; 
    T *oldinstance_; 

    // Made private and left undefined on purpose. 
    DynamicallyScoped(const DynamicallyScoped &b); 
    const DynamicallyScoped &operator =(const DynamicallyScoped &b); 
}; 

這使您可以替換當前實例的範圍,當範圍消失,系統將自動恢復。它還允許你在你的程序中的任何地方說DynamicallyScoped<Foo>::curInstance()->get_something();,除了靜態或全局對象的構造函數,並期望獲得一些有用的東西。

這是一個塗鴉,可能在這種形式中很有用。但我可以想象它可能更好的方式。例如,通過一些修改,您可以擁有幾個相同類型的動態範圍變量。

用法示例:

#include <iostream> 

template <> 
int *DynamicallyScoped<int>::S_curinstance = 0; 

extern void doSomething(); 
extern void doSomethingElse(); 
extern void printTheInt(); 

int main(int argc, char *argv[]) 
{ 
    int x = 5; 
    DynamicallyScoped<int> theInt(x); 

    printTheInt(); 
    doSomething(); 
    doSomethingElse(); 
} 

void doSomething() 
{ 
    printTheInt(); 
} 

void doSomethingElse() 
{ 
    int newint = 6; 
    DynamicallyScoped<int> subint(newint); 
    doSomething(); 
} 

void printTheInt() 
{ 
    ::std::cout << "_The_ integer's value is: " 
       << *DynamicallyScoped<int>::curInstance() << '\n'; 
} 

至於那可以創造你的「全局配置文件」對象的多個實例的煩惱,不硬編碼的文件名。將main中的對象構造爲堆棧變量,並將其作爲參數賦予文件名。如果代碼的其他部分創建了配置文件對象的實例,除非它們也提供了全局配置文件的名稱,否則沒有問題。如果他們這樣做,他們應該得到他們得到的。