c++工厂模式使用模板进行自注册

C++ Factory pattern using templates for self registering

本文关键字:注册 工厂 模式 c++      更新时间:2023-10-16

我的问题对应于约翰内斯的回答是否有一种方法从持有其类名的字符串实例化对象?以及斯宾塞·罗斯最近的评论因为我不能在这里添加评论,所以我决定开始一个新问题。

约翰的建议正是我所需要的。我以完全相同的方式实现了它,但我使用VS2008有一个未解决的外部符号链接器错误,这似乎与地图有关。这几天我一直在努力解决这个问题。今天我读了斯宾塞的评论,加上了他建议的那行
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)

意味着我可能已经定义了它两次??请斯宾塞或有人张贴改进的基础。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> >)"
(?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++预处理器只是盲目地包含代码头,链接器无法判断实现是在Switcher.cpp文件中还是Switcher.cpp包含的某个文件中。

就像方法需要在.h文件中声明并在.cpp文件中实现一样,静态字段也是如此。

map是STL中模板类的名称,因此不适合作为变量名。这可能与您得到的重复定义错误有关,也可能与之无关。