坚持使用C ++模板 - 从std :: map派生

时间:2009-06-08 20:41:17

标签: c++ visual-c++ templates stl

我将扩展现有的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 个答案:

答案 0 :(得分:16)

加入Neil的答案。

您不应该从std :: map派生的一个具体原因是它没有虚拟析构函数。这意味着您无法保证在通过std :: map指针破坏实现期间释放您作为地图一部分分配的任何资源。

std::map<int,int>* pMap = GetCleanableMap();
...
delete pMap; // does not call your destructor

答案 1 :(得分:12)

std::map无意通过派生进行扩展。如果要添加新功能,请使用独立功能。

答案 2 :(得分:4)

很多人都在摒弃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;
}

答案 3 :(得分:2)

您遇到的可能是您环境中std :: map的确切实现的工件。由于std :: map从未打算派生自,因此实现通常具有奇怪的特化或奇怪的内部结构,可以使它们更快,但如果你试图从它们派生,会导致许多奇怪的错误。

或者,你的另一个基类可能有些奇怪 - '可清洁'是什么样的?如果删除'可清除'基础(作为测试),其他所有内容都会编译吗?他们的名字可能会发生一些奇怪的内部冲突吗?

答案 4 :(得分:1)

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&amp;但该方法返回std :: map&amp;。

你的=运算符的正确签名应该是:

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所说,应该避免从具有非虚拟析构函数的类派生。

使用包装器或函数。