我的问题与 Johannes 在 Is there a way to instantiate objects from a string holding their class name? 中的回答相对应以及 Spencer Rose 最近的评论。由于我不能在那里添加评论,所以我决定开始一个新问题。
Johannes 的建议正是我所需要的。我以完全相同的方式实现了它,但是我使用 VS2008 遇到了一个 Unresolved external symbol 链接器错误,这似乎与 map 有关。几天以来我一直在努力解决它。今天我阅读了 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"
(?map@BaseFactory@@0PAV?$map@V?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@P6APAVBase@@XZU?$less@V?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@@2@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@P6APAVBaser@@XZ@std@@@2@@std@@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" (?map@BaseFactory@@0PAV?$map@V?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@P6APAVBase@@XZU?$less@V?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@@2@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@P6APAVBase@@XZ@std@@@2@@std@@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" (?map@BaseFactory@@0PAV?$map@V?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@P6APAVBase@@XZU?$less@V?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@@2@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@P6APAVBase@@XZ@std@@@2@@std@@A)
1>Project.exe : fatal error LNK1120: 1 unresolved externals)
这意味着我可能定义了两次?? 请 Spencer 或其他人发布改进的 base.hpp 代码。这是一个如此重要的解决方案,它肯定会对更多的 C++ 新手程序员有所帮助。
第二个问题: --> 这个问题解决了!谢谢!
我需要在 base.hpp 中声明一些函数。这些应该在基类中是抽象的并在子类中实现(例如 Derivedb.cpp )。但是
public:
virtual ReadInFile(std::string path, std::string filename) = 0;
在 base.hpp 中给出了一个编译器错误。删除“= 0”解决了编译器错误。但是现在我有另一个 Unresolved external symbol 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> >)"
(?ReadInFile@Base@@UAE_NPAV@@V?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@1@Z).
我在另一个cpp文件中调用它
Base* importer = BaseFactory::createInstance("DerivedB");
importer->ReadInFile(m_path, m_filename);
可能不清楚需要调用哪个函数(基类或子类),因为它在基类中不是抽象的???有什么办法可以解决这个问题吗?谢谢你!
最佳答案
从 LNK2005 错误来看,您的 BaseFactory
类有一个名为 map
的静态字段,对吧?
C++ 中的静态字段必须在类的头文件中“声明”,并在类的源文件中“实现”。
这是一个关于如何设置的简化示例。在这种情况下,在 BaseFactory.h
文件中,您应该声明静态字段:
class BaseFactory
{
private:
static int map;
};
在 BaseFactory.cpp
文件中,实现了静态字段:
int BaseFactory::map = 392;
来自链接器的错误消息表明 BaseFactory::map
静态字段在 Derivedb.cpp
文件和 Switcher.cpp 中都已实现
文件。
即使实现 (... BaseFactory::map = ...
) 不在任何一个文件中,如果将实现放在BaseFactory.h
头文件。 C++ 预处理器只是盲目地包含代码 header ,链接器无法判断实现是在 Switcher.cpp
文件中还是在 Switcher.cpp
包含的某个文件中。
就像方法需要在.h
文件中声明并在.cpp
文件中实现一样,静态字段也是如此。
关于C++ 工厂模式使用模板进行自注册,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7548002/