2012-08-13 43 views
2

所以我讀了從STL繼承是一個壞主意。但是如何將STL類包裝到其他類中以擴展它們。這與主要目的是分離抽象層次等等。包裝STL爲了延伸

喜歡的東西:

template<class T> 
class MyVector{ 
public: 
T& last(){ 
    return data[data.size() - 1] 
} 

bool include(T& element); 

//etc. 

private: 
vector<T> data; 
} 

這是一個好主意?這是C++程序員經常做的事嗎?

謝謝。

+6

'std :: vector :: back()'不,這不是首選的方法。首選的方法是將底層容器抽象出來並在迭代器/整個範圍上操作,或者編寫一個超類函數'bool include(std :: vector const&v,T const&elem)''。 – Xeo 2012-08-13 20:20:35

+1

他們不經常這樣做,因爲大部分時間,只要在適當的容器上使用適當的算法就足夠了。 – Griwes 2012-08-13 20:22:02

回答

3

是的,包裝比繼承好,但只有當你需要添加狀態到現有的數據結構。否則,添加非成員函數。這更詳細地在C項35說明++編碼標準(Amazon

要添加狀態,寧可組合物,而不是繼承。無可否認,必須爲要保留的成員函數 編寫直通功能,但這種實現比使用公共或非公共繼承的 更安全,更安全。

template<typename T> 
class MyExtendedVector 
{ 
public: 
    // pass-through functions for std::vector members 
    void some_existing_fun() { return vec_.some_existing_fun(); } 

    // new functionality that uses extra state 
    void some_new_fun() { // your implementation here } 

private: 
    std::vector<T> vec_; 
    // extra state e.g. to do logging, caching, or whatever 
}; 

要添加行爲,寧願加NONMEM-BER函數而不是成員 功能。

但請務必讓你的算法儘可能通用:

// if you CAN: write algorithm that uses iterators only 
// (and delegates to iterator category that container supports) 
template<typename Iterator, typename T> 
bool generic_contains(Iterator first, Iterator last, T const& elem) 
{ 
    // implement using iterators + STL algorithms only 
    return std::find(first, last, elem) != last; 
} 

// if you MUST: write algorithm that uses specific interface of container 
template<typename T> 
void vector_contains(std::vector<T> const& v, T const& elem) 
{ 
    // implement using public interface of Container + STL algorithms 
    return generic_contains(v.begin(), v.end(), elem); 
} 
3

我可以爲我只能說,但我沒有這樣做,我可能就不是一般的建議吧。

在幾乎所有情況下,基於迭代器的算法實現起來都比較簡單將算法從容器中分離出來。例如,假設您的include方法僅僅是確定元素是否在矢量中,則根據容器的內容和搜索需要,您可以使用find,binary_searchlower_bound

偶爾我實現一類通過提供開始/結束方法看起來像對外界的容器。在這種情況下,它有時會有一個標準的容器底層,但是你只實現了一個最小化的公共接口來表示你的類實際建模的內容。

2

我會避免這樣做,因爲最後一個人回答。我明白你要去哪裏你的容器要將一些更復雜的操作包裝成更簡單的方法,並且認爲你可以在某些時候更改底層容器而不必更改接口。然而,話雖如此,你的對象應該模擬你的業務需求,然後這些對象的實現將使用任何數據容器和訪問模式是最好的。我想我所說的是,你最終不會重新使用這個新的向量類,因爲每次你的業務需求的數據訪問都會不同,你會再次使用一些標準的通用容器,比如std :: vector,基於迭代器的算法訪問數據。

現在,如果有一些不存在的算法,您可以爲該特定項目編寫基於迭代器的算法,然後保留可能能夠重用的算法代碼。下面顯示了我寫的一組grep算法,它基於一組交集,但沒有按照我想要的完成。我可以再次使用這個算法。

#include <utility> 
#include <algorithm> 

// this is a set grep meaning any items that are in set one 
// will be pulled out if they match anything in set 2 based on operator pred 
template<typename _InputIterator1, typename _InputIterator2, 
    typename _OutputIterator, typename _Compare> 
    _OutputIterator 
setGrep(_InputIterator1 __first1, _InputIterator1 __last1, 
    _InputIterator2 __first2, _InputIterator2 __last2, 
    _OutputIterator __result, _Compare __comp) 
{ 
    while (__first1 != __last1 && __first2 != __last2) 
    if (__comp(*__first1, *__first2)) 
     ++__first1; 
    else if (__comp(*__first2, *__first1)) 
     ++__first2; 
    else 
    { 
     *__result = *__first1; 
     ++__first1; 
     ++__result; 
    } 
    return __result; 
} 
+0

標準庫實現中使用的命名約定並不意味着要模擬。包含雙下劃線和以下劃線開頭並帶有大寫字母的名稱的名稱爲實現保留,不會在用戶代碼中出現。 – 2012-08-13 21:38:19