C++ STL container for template base class
I am attempting to store objects derived from a templated base class in an STL map. However, attempting to insert derived (or indeed base) objects returns:
C2440 'initializing' : cannot convert from 'CBase<T> ' to 'CBase<T>'
I understand using derived classes is one accepted way of making an STL container heterogenous (http://www.parashift.com/c++-faq-lite/containers.html#faq-34.4). I would like to know if it is possible to use a template in this context. It would be very convenient as I could have a single declaration of a range of containers in the base class that are instantiated for my various types at compile time, instead of duplicate declarations in non-templated derived classes.
My code is as follows:
//Header
using namespace std;
template<class T>
class CBase
{
public:
CBase::CBase() {};
virtual CBase::~CBase() {};
vector<pair<int, T> > RetrieveVect() { return vect; };
private:
vector<pair<int, T> > vect;
};
class CDerivedString : public CBase<string>
{
...
};
class CDerivedInt : public CBase<int>
{
...
};
//cpp
int main(void)
{
//Map specialised for pointer to base class
map<string, CBase<class T>* > m_myMap;
string s = "key";
//Create and insert object (base class)
CBase<int> *dataInt = new CBase();
//The following results in error C2440: 'initializing' : cannot convert from 'CBase<T> ' to 'CBase<T>
m_myMap.insert(std::make_pair(s, dataInt));
//Create and insert object (derived class)
CBase<int> *dataBase = new CBase<int>();
//The following results in error C2440: 'initializing' : cannot convert from 'CBase<T> ' to 'CBase<T>
m_myMap.insert(pair<string, CBase<class T>* >(s, static_cast<CBase*>(dataInt)));
}
I've tried doing a dynamic_开发者_StackOverflow中文版cast on the derived class pointer to cast it to a base pointer type but this didn't work either:
//error C2440: 'static_cast' : cannot convert from 'CBase<T> *' to 'CBase<T> *'
m_myMap.insert(pair<string, CBase<class T>* >(s, static_cast<CBase<class T>*>(dataInt)));
The following line:
map<string, CBase<class T>* > m_myMap;
almost certainly does not mean what you think it does. This is equivalent to:
map<string, CBase<T>* > m_myMap;
That is: 'T' is a concrete class, not a template parameter. There is of course no relationship between the classes:
CBase<int>
and
CBase<T>
Hence the error message - you have never defined (or intended to) the concrete class 'T'. Take SCFrench's comment re using the correct base and then use that in the map<>:
map<string, CBase<int>* > m_myIntMap;
will allow you to store the concrete CDerivedInt* objects. If you want to store any object, define a fully generic base:
class CBaseAbc
{
virtual ~CBaseAbc() = 0;
};
template<class T>
class CBase : public CBaseAbc
{
// etc.
};
map<string, CBaseAbc* > m_myAnthingMap;
Use Boost's Pointer Containers, which exactly provide a "map specialised for pointer to base class" that you tried:
// Use whichever is appropriate since you've written CBase as a template:
boost::ptr_map<string, CBase<int> > m_myMap;
boost::ptr_map<string, CBase<string> > m_myMap;
// If CBase were instead not a template base class:
boost::ptr_map<string, CBase> m_myMap;
Since you use T in CBase's interface, it appears you want to keep CBase as a template, but be aware that in that case, there is no common base class between classes derived from CBase<int> and CBase<string>, as these are two different types, and you cannot store classes derived from either in a single container.
You need to have a base class to store in the std::map
; that needs to either be a non-templated class or a specific instance of a template. It is not possible to store "any instance of CBase
" unless there is a common base class for all instances. You might also want to consider using boost::shared_ptr
or std::shared_ptr
to automatically manage the lifetimes of your objects.
精彩评论