2009-06-08 69 views
0

我打算擴展現有的std ::地圖類,並添加了新的功能,把它:憋屈C++模板 - 從STD派生::地圖

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 ::我的新地圖:

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

什麼版本的VC++? – 2009-06-08 20:51:10

回答

16

添加到尼爾的答案。

你不應該從std :: map派生的一個具體原因是它沒有虛擬析構函數。這意味着你不能保證你分配的任何資源,因爲在通過std :: map指針破壞你的實現的過程中,你的映射的一部分將被釋放。

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

std::map不打算通過派生進行擴展。如果您想添加新功能,請使用獨立功能。

+0

我真的只是這樣做,所以我可以調用地圖構建和銷燬時的方法。如果我能做到這一點,我可以通過新的CleanableMap替換std :: map,而不必改變其他任何東西。所以沒有新的數據成員。 即使它不是從派生出來的,如果我是從其他模板類派生出來的並得到了同樣的錯誤呢? :) – DougN 2009-06-08 20:49:24

+0

@DougN,問題是你根本無法保證你的析構函數會在類型被破壞時被調用。爲什麼std :: map沒有虛擬析構函數。查看我的答案,瞭解將會發生的具體情況。 – JaredPar 2009-06-08 20:51:00

2

你正在運行的東西可能是你的環境中std :: map的精確實現的人工產物。由於std :: map從來沒有打算從派生出來,因此實現通常具有奇怪的特化或看起來很奇怪的內部元素,這些元素使它們更快,但是如果嘗試從它們派生出來,會導致很多奇怪的錯誤。

或者,您的其他基類可能存在一些奇怪現象 - 「可清潔」是什麼樣子?如果你刪除'可清除'的基礎(作爲一個測試),一切都編譯?他們的名字可能會有一些奇怪的內部衝突嗎?

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 &類型,但該方法返回std :: map &。

你=運算符的正確的簽名應該是:

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

但是如果你只需要添加一個「乾淨」的功能,爲std ::地圖,你爲什麼不只是使用一個函數來做到工作?

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

如JaredPar所說,應該避免從具有非虛擬析構函數的類派生。

使用包裝或功能。

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