Question:
I created my own map class (called it Mapper) by creating a template class and deriving from STL map container class. I did so because I wanted to have some extra user-defined methods in this class. I don’t have any problems compiling if I only use the methods provided by the STL map class. However, when I try to make a call to one of the new methods in Mapper, I get the following linking error:
--------------------Configuration: mapfunc - Win32 Debug--------------------Compiling...runmapper.cppLinking...runmapper.obj : error LNK2001: unresolved external symbol
"public: int __thiscall Mapper::SmartMatch(class
std::basic_stringshort>,class std::allocator > const &)" (?
SmartMatch@[email protected]@@[email protected][email protected]@std@@[email protected]@2@@std@@@Z)Debug/mapfunc.exe : fatal error LNK1120: 1 unresolved externalsError executing link.exe.mapfunc.exe - 2 error(s), 0 warning(s)
By the way, runmapper.cpp is the driver program and mapfunc is the project name. I have three user-defined methods (one of them is SmartMatch(key)) that when I try to call, from the driver program, give me the same compilation error (linking error).
Answer:
The compiler must see the definition, not just the declaration, of a template in order to instantiate it. It looks like you #included only the declaration (i.e., the prototype) of your added member function:
int Mapper::SmartMatch(std::wstring); // prototype
The compiler needs to see its definitions (implementation), too. If you’re using Visual C++, my advice is to implement template member functions inline, inside the header file that declares the class template.
Note that deriving from STL containers is usually a bad idea because STL containers have no virtual destructors or virtual member functions. This can cause undefined behavior in certain conditions, for example, if you pass a pointer to std::map<> which actually points to a class derived from std::map<> and has its own destructor. In this case, the derived class’s destructor isn’t called:
// mapper is derived from std::mapstd::map < int > * p new mapper < int >; delete p; /*undefined behavior; only map < int >::~map < int > called*/
If you need to extend STL’s functionality, it’s better to use containment rather than public inheritance.