3

所以我读到从 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++ 程序员经常做的事情吗?

谢谢你。

4

3 回答 3

4

是的,包装比继承更好,但前提是您需要向现有数据结构添加状态。否则,添加非成员函数。这在 C++ 编码标准 ( Amazon )的第 35 项中有更详细的解释

要添加状态,更喜欢组合而不是继承。诚然,必须为要保留的成员函数编写传递函数很乏味,但这样的实现比使用公共或非公共继承要好得多,也更安全。

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

要添加行为,最好添加非成员函数而不是成员函数。

但是,请确保您的算法尽可能通用:

// 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);
}
于 2012-08-13T20:25:04.187 回答
3

我只能为自己说话,但我没有这样做,而且我一般不会建议这样做。

几乎在每种情况下,基于迭代器的算法都更易于实现并将算法与容器分开。例如,假设您的include方法只是确定元素是否在向量中,您将使用findbinary_search或 ,lower_bound具体取决于容器的内容和搜索需求。

有时我通过提供开始/结束方法实现了一个在外界看来像容器的类。在这种情况下,它有时确实有一个标准容器底层,但您只实现一个最小的公共接口来表示您的类实际建模的内容。

于 2012-08-13T20:25:38.163 回答
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;
}
于 2012-08-13T21:05:16.150 回答