开发者

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.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜