Контейнер C ++ STL для базового класса шаблона - PullRequest
1 голос
/ 07 февраля 2011

Я пытаюсь сохранить объекты, полученные из шаблонного базового класса, в карте 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 ]

6 голосов
/ 07 февраля 2011

Следующая строка:

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

почти наверняка не означает, что вы думаете, что он делает.Это эквивалентно:

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

То есть: 'T' - это конкретный класс, а не параметр шаблона.Конечно, нет никакой связи между классами:

CBase<int> 

и

CBase<T>

Отсюда и сообщение об ошибке - вы никогда не определяли (или не намеревались) конкретный класс 'T'.Возьмите комментарий SCFrench, используя правильную базу, а затем используйте ее на карте <>:

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 голос
/ 07 февраля 2011

Используйте Контейнеры указателей Boost , которые точно предоставляют "карту, специализированную для указателя на базовый класс", которую вы пытались:

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

Поскольку вы используете T в интерфейсе CBase, оно появляетсяВы хотите сохранить CBase в качестве шаблона, но помните, что в этом случае нет общего базового класса между классами, производными от CBase и CBase , так как это два разных типа, и вы не можете хранить производные классыиз любого в одном контейнере.

0 голосов
/ 07 февраля 2011

Вам необходимо иметь базовый класс для хранения в std::map; это должен быть не шаблонный класс или конкретный экземпляр шаблона. Невозможно хранить «любой экземпляр CBase», если не существует общего базового класса для всех экземпляров. Возможно, вы захотите использовать boost::shared_ptr или std::shared_ptr для автоматического управления временем жизни ваших объектов.

...