2011-09-25 47 views
1

我的問題與Johannes在Is there a way to instantiate objects from a string holding their class name?的回答以及Spencer Rose最近的評論相對應。由於我無法在那裏添加評論,因此我決定發起一個新問題。使用模板進行自我註冊的C++工廠模式

Johannes的建議是我所需要的。我以完全相同的方式實現它,但使用VS2008時出現無法解析的外部符號鏈接器錯誤,這似乎與地圖有關。我試圖解決這個問題。今天我讀了Spencer的評論,並添加了他建議的行

BaseFactory::map_type BaseFactory::map = new map_type(); 

到Base.hpp。現在,我得到一個錯誤LNK2005

Derivedb.obj : error LNK2005: 
"private: static class std::map<class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> >,class Base * (__cdecl*)(void),struct std::less<class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > >,class std::allocator<struct std::pair<class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > const ,class Base * (__cdecl*)(void)> > > * BaseFactory::map" 
([email protected]@@[email protected][email protected][email protected]@[email protected]@[email protected]@[email protected]@[email protected]@[email protected]@[email protected][email protected][email protected]@[email protected]@[email protected]@[email protected]@[email protected]@@[email protected][email protected][email protected][email protected][email protected]@[email protected]@[email protected]@[email protected]@[email protected]@[email protected]@[email protected]@@@[email protected]@[email protected]@A) 
already defined in Switcher.obj 

Project.exe : fatal error LNK1169: one or more multiply defined symbols found) 

代替LNK2001錯誤

(Switcher.obj : error LNK2001: unresolved external symbol "private: static class std::map<class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> >,class Base * (__cdecl*)(void),struct std::less<class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > >,class std::allocator<struct std::pair<class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > const ,class Base * (__cdecl*)(void)> > > * BaseFactory::map" ([email protected]@@[email protected][email protected][email protected]@[email protected]@[email protected]@[email protected]@[email protected]@[email protected]@[email protected][email protected][email protected]@[email protected]@[email protected]@[email protected]@[email protected]@@[email protected][email protected][email protected][email protected][email protected]@st[email protected]@[email protected]@[email protected]@[email protected]@[email protected]@[email protected]@@@[email protected]@[email protected]@A) 
1>Derivedb.obj : error LNK2001: unresolved external symbol "private: static class std::map<class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> >,class Base * (__cdecl*)(void),struct std::less<class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > >,class std::allocator<struct std::pair<class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > const ,class Base * (__cdecl*)(void)> > > * BaseFactory::map" ([email protected]@@[email protected][email protected][email protected]@[email protected]@[email protected]@[email protected]@[email protected]@[email protected]@[email protected][email protected][email protected]@[email protected]@[email protected]@[email protected]@[email protected]@@[email protected][email protected][email protected][email protected][email protected]@[email protected]@[email protected]@[email protected]@[email protected]@[email protected]@[email protected]@@@[email protected]@[email protected]@A) 
1>Project.exe : fatal error LNK1120: 1 unresolved externals) 

這意味着我可能已經兩次將它定義? 請斯賓塞或其他人發佈改進的base.hpp代碼。這是一個非常重要的解決方案,它肯定會對更多新手C++程序員有所幫助。

第二個問題: - >這個問題解決了!謝謝!

我需要在base.hpp中的一些函數聲明。這些應該在基類中是抽象的並在子類中實現(例如Derivedb.cpp)。但是

public: 
     virtual ReadInFile(std::string path, std::string filename) = 0; 

在base.hpp中給出了編譯器錯誤。刪除「= 0」解決了編譯器錯誤。但現在我有另一種解析外部符號LNK2001錯誤

Derivedb.obj: error LNK2001: unresolved external symbol 
"public: virtual __thiscall Base::ReadInFile(class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> >,class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> >)" 
([email protected]@@[email protected]@[email protected][email protected]@[email protected]@[email protected]@[email protected]@[email protected]@[email protected]). 

我把它在另一個CPP文件

Base* importer = BaseFactory::createInstance("DerivedB"); 
importer->ReadInFile(m_path, m_filename); 

也許並不清楚其功能(基地或子類)需要被調用,因爲它是不在基類中抽象?有沒有解決這個問題的方法?謝謝!

+2

錯誤並不意味着「某些東西」是錯誤的。錯誤通常具有特定的消息,並且在編譯器錯誤的情況下,一行指示問題的位置。你收到什麼錯誤信息?你說你有一個純虛函數時會出現編譯錯誤。那個編譯器錯誤是關於嘗試實例化一個具有純虛函數的類嗎?總之:你得到了什麼_messages_? –

+0

感謝您的評論!現在我試着再次通過添加「= 0」來得到錯誤,並且編譯器錯誤沒有出現,此外LNK2001錯誤消失了。我嘗試了很多東西,現在我不知道原因是什麼。它確實告訴我,抽象方法是不允許的。無論如何,我很高興你的評論,因爲現在至少這個錯誤已經解決:-)。我仍然有LNK2005錯誤。 – Natalie

+0

現在你已經過去了第一個錯誤,你可以[編輯]你的問題。另外,編譯器錯誤通常很具體,但重要的細節有時可能會丟失。如果在編輯問題時包含* exact *編譯器錯誤,您會得到更好的幫助。 –

回答

1

從LNK2005錯誤中,您的BaseFactory類有一個靜態字段,名爲map,對吧?

C++中的靜態字段必須在類的頭文件中「聲明」,並在類的源文件中「實現」。

這裏是一個簡化的如何設置它的例子。在這種情況下,在BaseFactory.h文件,你應該有靜態字段聲明:

class BaseFactory 
{ 
private: 
    static int map; 
}; 

而在BaseFactory.cpp文件,靜態領域得到實施:

int BaseFactory::map = 392; 

從鏈接器的錯誤信息表示在Derivedb.cpp文件和Switcher.cpp文件中都實現了BaseFactory::map靜態字段。

即使實現(... BaseFactory::map = ...)不在這兩個文件中,如果將實現放入BaseFactory.h頭文件中,也會得到相同的錯誤。 C++預處理器只是盲目地包含代碼頭文件,鏈接程序無法分辨該實現是在Switcher.cpp文件中還是在Switcher.cpp中包含的某個文件中。

就像方法需要在.h文件中聲明並在.cpp文件中實現一樣,靜態字段也是如此。

+0

非常感謝Dan!這是我的問題的完美答案。程序現在運行,但在「importer-> ReadInFile(m_path,m_filename)」行中「我有一個調試斷言失敗的錯誤,與表達式: 地圖/設置迭代器不可取消。導致它的行是「在baseFactory :: createInstance方法中重新運行 - > second()」。我正在尋找這個解決方案....... – Natalie

+0

沒問題。祝你下一次的挑戰順利! –

0

map是STL中模板類的名稱,因此對變量名來說是一個糟糕的選擇。這可能與您獲得的重複定義錯誤相關,也可能不相關。

+1

你是對的!我只是在這裏命名它,就像它在約翰內斯的示例代碼中命名的一樣,不要混淆任何人。但在我的代碼中有另一個名字。所以不幸的是這不是錯誤的原因。謝謝你的評論! – Natalie

+0

'map'就是這樣一個普遍的名稱,把它作爲一個標識符被禁止是不合理的:map是一個編程的核心概念,有幾個不同的但相關的含義。我在我的代碼中自由使用它。當然,必須注意避免衝突,但是如果你沒有打開整個'std'命名空間並小心謹慎,這是沒有問題的。畢竟,這就是命名空間。 –

+1

我會考慮這個詞的普遍性另一個缺點。使用'map'作爲變量名不會告訴你任何有關該變量包含的內容。這個問題的一個更好的選擇是'class_map'或'class_name_map'或者沿着這些線的東西。 – CurtisB