My questions correspond to the answer from Johannes in Is there a way to instantiate objects from a string holding their class name? and the recent comment from Spencer Rose. Since I cannot add a comment there, I decided to start a new question.
Johannes suggestion is what I need. I implemented it in exact the same way but I have an unresolved external symbol linker error using VS2008 which seems to have something to do with the map. I am trying since days to solve it. Today I read the comment from Spencer and added the line he suggests
BaseFactory::map_type BaseFactory::map = new map_type();
to the Base.hpp. Now I get a LNK2005 error
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::alloc开发者_运维知识库ator<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)
instead of the LNK2001 error
(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)
which means that I may have defined it twice?? Please could Spencer or somebody post the improved base.hpp code. It is such an important solution that it surely will be helpful for many more novice C++ programmers.
Second question: --> This problem is solved! Thanks!
I need some function declarations in base.hpp. Those should have been abstract in the base class and implemented in the subclasses (e.g. Derivedb.cpp ). But
public:
virtual ReadInFile(std::string path, std::string filename) = 0;
in base.hpp gave a compiler error. Removing "= 0" resolved the compiler error. But now I have another unresolved external symbol LNK2001 error
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).
I call it in another cpp file
Base* importer = BaseFactory::createInstance("DerivedB");
importer->ReadInFile(m_path, m_filename);
Maybe it is not clear which function (base or subclass) need to be called since it is not abstract in the base class??? Is there any way of solving this problem? Thank you!
From the LNK2005 error, your BaseFactory
class has a static field called map
, right?
Static fields in C++ have to be "declared" inside the class's header file, and "implemented" in the class's source file.
Here is a simplified example of how to set this up. In this case, in the BaseFactory.h
file, you should have the static field declared:
class BaseFactory
{
private:
static int map;
};
And in the BaseFactory.cpp
file, the static field gets implemented:
int BaseFactory::map = 392;
The error message from the linker is saying that the BaseFactory::map
static field got implemented in both the Derivedb.cpp
file and the Switcher.cpp
files.
Even if the implementation (... BaseFactory::map = ...
) isn't in either of those files, you'll get the same error if you put the implementation in the BaseFactory.h
header file. The C++ preprocessor just blindly includes code headers, and the linker can't tell whether the implementation is in the Switcher.cpp
file or some file that Switcher.cpp
included.
Just like methods need to be declared in .h
files and implemented in .cpp
files, the same goes for static fields.
map
is the name of a template class in the STL, and therefore a poor choice for a variable name. This may or may not be related to the duplicate definition error you are getting.
精彩评论