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メソッドが要素がベクトル内にあるかどうかを判断するだけであるとfind仮定すると、、、binary_searchまたはlower_boundコンテナのコンテンツと検索のニーズに応じて使用します。

時折、begin / endメソッドを提供することで、外の世界からはコンテナのように見えるクラスを実装しましたこの場合、基礎となる標準コンテナが存在することがありますが、クラスが実際にモデル化するものを表すために最小限のパブリックインターフェイスのみを実装します。

于 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 に答える