用于模板基类的C ++ STL容器

时间:2011-02-07 01:21:51

标签: c++ templates base-class

我试图在STL地图中存储从模板化基类派生的对象。但是,尝试插入派生(或实际上是基础)对象会返回:

C2440 'initializing' : cannot convert from 'CBase<T> ' to 'CBase<T>'

我理解使用派生类是使STL容器异构的一种可接受的方式(http://www.parashift.com/c++-faq-lite/containers.html#faq-34.4)。我想知道是否可以在此上下文中使用模板。这将非常方便,因为我可以在基类中单个声明一系列容器,这些容器在编译时为我的各种类型实例化,而不是在非模板化派生类中重复声明。

我的代码如下:

//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)));
}

我尝试对派生类指针执行dynamic_cast以将其强制转换为基类型指针,但这也不起作用:

//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)));  

3 个答案:

答案 0 :(得分:6)

以下一行:

map<string, CBase<class T>* > m_myMap;

几乎可以肯定并不意味着你的想法。这相当于:

map<string, CBase<T>* > m_myMap;

即:'T'是具体类,而不是模板参数。当然,课程之间没有任何关系:

CBase<int> 

CBase<T>

因此错误消息 - 您从未定义(或打算)具体类'T'。使用正确的基数重新获取SCFrench的评论,然后在地图中使用它&lt;&gt;:

map<string, CBase<int>* > m_myIntMap;

将允许您存储具体的CDerivedInt *对象。如果要存储任何对象,请定义完全通用的基础:

 class CBaseAbc 
     { 
        virtual ~CBaseAbc() = 0;
     };
 template<class T>
 class CBase : public CBaseAbc 
    {
     // etc.
    };

map<string, CBaseAbc* > m_myAnthingMap;

答案 1 :(得分:1)

使用Boost's Pointer Containers,它准确地提供了您尝试过的“专门用于指向基类的指针的地图”:

// 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;

由于您在CBase的界面中使用T,因此您希望将CBase保留为模板,但请注意,在这种情况下,从CBase&lt; int&gt;派生的类之间没有共同的基类。和CBase&lt; string&gt;,因为它们是两种不同的类型,并且您不能将从两者派生的类存储在一个容器中。

答案 2 :(得分:0)

您需要有一个基类存储在std::map;它需要是非模板化类或模板的特定实例。除非存在所有实例的公共基类,否则无法存储“CBase的任何实例”。您可能还需要考虑使用boost::shared_ptrstd::shared_ptr来自动管理对象的生命周期。