Застрял на шаблоне C ++ - происходит от std :: map - PullRequest
0 голосов
/ 09 июня 2009

Я собираюсь расширить существующий класс std :: map и добавить в него новую функцию:

template<typename key_type, typename value_type>
class CleanableMap : public Cleanable, public std::map<key_type, value_type> 
{
    CleanableMap(const CleanableMap& in); //not implemented
    CleanableMap& operator=(const CleanableMap& in); //not implemented
public:
    CleanableMap() {}
    CleanableMap(const std::map<key_type, value_type>& in) { *this = in; }
    virtual ~CleanableMap() {}
    std::map<key_type, value_type>& operator=(const std::map<key_type, value_type>& in)
    {
        *((std::map<key_type, value_type>*)this) = in;
        return *this;
    }
};

У меня есть конструктор копирования и оператор присваивания, так что я могу просто присвоить существующую std :: map того же типа моей новой карте:

CleanableMap<DWORD, DWORD> cm;
std::map<DWORD, DWORD> stdm;
cm = stdm;

Проблема в том, что компилятор жалуется с ошибкой, которая не имеет смысла - я явно написал то, на что он жалуется:

1>c:\dev\proj\commonfunc.cpp(399) : error C2679: binary '=' : no operator found which takes a right-hand operand of type 'std::map<_Kty,_Ty>' (or there is no acceptable conversion)
1>        with
1>        [
1>            _Kty=DWORD,
1>            _Ty=DWORD
1>        ]
1>        c:\dev\proj\templates.h(245): could be 'CleanableMap<key_type,value_type> &CleanableMap<key_type,value_type>::operator =(const CleanableMap<key_type,value_type> &)'
1>        with
1>        [
1>            key_type=DWORD,
1>            value_type=DWORD
1>        ]
1>        c:\dev\proj\templates.h(250): or       'std::map<_Kty,_Ty> &CleanableMap<key_type,value_type>::operator =(const std::map<_Kty,_Ty> &)'
1>        with
1>        [
1>            _Kty=unsigned long,    <--- where did it come up with that?
1>            _Ty=std::pair<const DWORD,DWORD>,  <--- where did it come up with that?
1>            key_type=DWORD,
1>            value_type=DWORD
1>        ]
1>        while trying to match the argument list '(CleanableMap<key_type,value_type>, std::map<_Kty,_Ty>)'
1>        with
1>        [
1>            key_type=DWORD,
1>            value_type=DWORD
1>        ]
1>        and
1>        [
1>            _Kty=DWORD,
1>            _Ty=DWORD
1>        ]

Там «может быть», о котором упоминается, что в строке 245 нет смысла - такого оператора присваивания нет (ну, он частный. Полное его удаление ничего не меняет).

В строке 250, которую он упоминает, это «оператор присваивания», который я определил, но он каким-то образом вывел некоторые другие несоответствующие типы шаблонов. Откуда он взял эти ??

Помощь !!! :)

Ответы [ 5 ]

16 голосов
/ 09 июня 2009

Добавление на ответ Нейла.

Одна конкретная причина, по которой вы не должны наследовать от std :: map, заключается в том, что в ней нет виртуального деструктора. Это означает, что вы просто не можете гарантировать, что любые ресурсы, выделенные вами как часть вашей карты, будут освобождены во время уничтожения вашей реализации через указатель std :: map.

std::map<int,int>* pMap = GetCleanableMap();
...
delete pMap; // does not call your destructor
12 голосов
/ 09 июня 2009

std::map не предназначен для расширения путем деривации. Если вы хотите добавить новую функциональность, сделайте это с автономными функциями.

4 голосов
/ 05 января 2010

Многие люди отказываются от наследования от объектов STL. Вы можете сделать процесс более безопасным, используя защиту доступа, однако: используйте map как частную базу. Вот демонстрация.

#include <iostream>
#include <map>

using namespace std;

struct cmap : private map<int, int> {
        cmap() : map<int, int>() { };

        using map<int, int>::operator[]; // repeat for other methods you'd like
};

int main( int argc, char **argv ) {
        cmap my_map;

        my_map[1] = 2; // behaves like a map

        cerr << my_map[1] << " " << my_map[2] << endl;

        // map<int, int> *bad_map = &my_map; this does not compile

        return 0;
}
2 голосов
/ 09 июня 2009

То, с чем вы сталкиваетесь, вероятно, является артефактом точной реализации std :: map в вашей среде. Поскольку std :: map никогда не предназначался для получения из него, реализации часто имеют либо странные специализации, либо странные на вид внутренние компоненты, которые служат для их ускорения, но приводят к множеству странных ошибок, если вы пытаетесь получить их. *

С другой стороны, могут быть некоторые странности с вашим другим базовым классом - как выглядит «Cleanable»? Если удалить «очищаемую» базу (в качестве теста), все остальное компилируется? Может ли быть какой-то странный внутренний конфликт с их именами?

1 голос
/ 09 июня 2009
std::map<key_type, value_type>& operator=(const std::map<key_type, value_type>& in)
{
    *((std::map<key_type, value_type>*)this) = in;
    return *this;
}

Этот исходный код пытается преобразовать ваш CleanableMap в std :: map. * это тип CleanableMap &, но метод возвращает std :: map &.

Правильная подпись вашего оператора = должна быть:

CleanableMap &operator=(const std::map<key_type, value_type> &in);

Но если вы хотите добавить «чистую» функцию в std :: map, почему бы вам просто не использовать функцию для выполнения работы?

template<typename K, typename V> void clean(std::map<K, V> &map);

Следует избегать наследования от класса с не виртуальным деструктором, как сказал JaredPar.

Использовать оболочку или функцию.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...