我将扩展现有的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行提到的'可能'是我定义的赋值运算符,但它以某种方式推导出其他一些非匹配的模板类型。它从哪里得到的?
帮助!!! :)
答案 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所说,应该避免从具有非虚拟析构函数的类派生。
使用包装器或函数。