3

私はC++を初めて使います.2つのクラスが継承する抽象クラス(純粋仮想)があります。各派生クラスは同様のデータを保持しますが、異なる STL コンテナー (配列とマップ) でのみ保持されます。たとえば、STL 要素の追加を実行するために、基本クラスの演算子をオーバーロードしています。タイプに関係なく、STL の要素を反復できるようにしたいと考えています。

一般的なイテレータなどを数日間検索しましたが、何も見つかりませんでした。

何もできなかったので、共有するコードはあまりありません。基本クラスに STL コンテナーを表すテンプレート変数を保持させ、オペレーターでそのイテレーターを取得することを考えましたが、方法がわかりません。

protected:
    template<class T>
    T gStlContainer;

そしてアクセスする

gStlContainer::iterator<double> it;

明らかにうまくいきませんでした。

助言がありますか?ありがとう!

編集:例を使用してよりよく説明するために編集しています。基本 (抽象) クラスで + 演算子をオーバーロードしています。STL コンテナーの各要素を反復処理し、それを別の要素に追加します。たとえば、この配列を STL として持っているとします。

arr = [0,1,2,3] // Say it's stored in Derived2 class
arr = [4,5,6,7] // Say it's stored in Derived3 class

これらの配列はそれぞれ、派生クラスの 1 つに格納されます。やってるとき

Derived1 = Derived2 + Derived3;

Derived1 が成り立つ

arr = [4,6,8,10]

もう少し明確になったことを願っています。問題は、常に配列になるとは限らないことです。たとえば、配列とマップを組み合わせることもできます。そのため、一般的な反復子または何らかの解決策が必要です。

ありがとう!

4

4 に答える 4

1

C ++には汎用イテレーターはありませんが、任意のタイプのイテレーターで動作するように記述できるテンプレート関数があります。コンテナ内のすべての要素を追加するために、すでにアルゴリズムがあります。について読むstd::accumulate

于 2012-09-03T17:09:28.767 に答える
1

あなたは間違った視点から問題を見ています。あなたはこれを行うことができますが、なぜあなたはそうしますか?基本クラスは、動作が異なると想定される場合はメソッドを実装しないでください。ただし、派生クラスにロジックを委任する必要があります。

class Base
{
public:
    virtual ~Base() {}
    virtual void iterate() = 0;
};

class Derived : Base
{
public:
    virtual void iterate() { /*iterate through vector or map or whatever*/ }
};
于 2012-09-03T17:09:30.493 に答える
1

動的ポリモーフィズムはオブジェクトには適切に機能しますが、アルゴリズムには非常にうまく機能しません。アルゴリズムの場合、静的ポリモーフィズムを使用する方がはるかに優れています。それらの間をサポートするコンテナーのシステムが必要な場合は、operator+()それらが何らかの形で名前空間を参照していることを確認し、この名前空間で適切なものを定義してくださいoperator+()。たとえば、名前空間内の何かから演算子を継承std::vector<T, A>するアロケータで使用できます。A以下は、このアプローチの例です。

基本的には、名前空間に適切な演算子を実装するという考え方です。たとえば、をaddable実装operator+()してprintable実装しoperator<<()ます。これらの名前空間のどちらも、タイプが何らかの形でそれらを参照しない限り、たとえば、この名前空間のタイプから継承するか、これらのタイプの1つを継承するタイプのテンプレート引数を使用することによって調べられません。このルックメカニズムは、引数依存ルックアップと呼ばれます。したがって、これらの名前空間は両方とも、struct tag {};継承時に費用がかからない空を提供します。

これらの名前空間を何らかの形で参照するコンテナを取得するために、以下のコードは、これらのタイプの両方から派生するアロケータクラステンプレートを作成するだけです。次に、このアロケータをとで使用しstd::vector<T, A>std::list<T, A>タイプエイリアスを作成し、対応するコンテナを簡単に作成します。すべてがうまく機能していることを示すmain()には、演算子の使用法を示します。

以下のコードは、表記を少し短くするために、いくつかの場所でC++2011を利用しています。この原則は、C++2003でも機能します。主に、型エイリアスと初期化子リストの使用は機能しません。

#include <algorithm>
#include <functional>
#include <iostream>
#include <iterator>
#include <list>
#include <vector>

namespace addable
{
    struct tag {};

    template <typename T0, typename T1>
    T0 operator+ (T0 const& c0, T1 const& c1)
    {
        T0 rc;
        std::transform(c0.begin(), c0.end(),
                       c1.begin(),
                       std::back_inserter(rc),
                       std::plus<typename T0::value_type>());
        return rc;
    }
}

namespace printable
{
    struct tag {};
    template <typename T, typename = typename T::value_type>
    std::ostream&
    operator<< (std::ostream& out, T const& value)
    {
        out << "[";
        if (!value.empty()) {
            std::copy(value.begin(), value.end() - 1,
                      std::ostream_iterator<typename T::value_type>(out, ", "));
            out << value.back();
        }
        return out << "]";
    }
}

template <typename T>
struct my_allocator
    : addable::tag
    , printable::tag
    , std::allocator<T>
{
};

template <typename T>
using my_vector = std::vector<T, my_allocator<T>>;
template <typename T>
using my_list   = std::vector<T, my_allocator<T>>;

int main()
{
    my_vector<int> v({ 1, 2, 3, 4 });
    my_list<int>   l({ 2, 3, 4, 5 });
    my_vector<int> rc = v + l;

    std::cout << v << " + " << l << " = " << (v + l) << "\n";
}
于 2012-09-03T20:43:32.580 に答える
0

明白な答えは次のとおりです。少なくともSTLのイテレータではできません。

イテレータは通常、テンプレートとして構築され、コンパイラはテンプレートの特殊化ごとに新しいタイプを作成します。vector :: iteratorはVectorFloatIteratorのようなものであり、map::iteratorはMapFloatIteratorのようなものと考えることができます。

それらは無関係な型であり、継承を通じてさえも、たまたま同様のインターフェースを持っているだけであり、もちろん、C++はダック型ではありません。2つのタイプが完全に無関係である場合、MapFloatIteratorを期待する関数にVectorFloatIteratorを渡すことはできません。

これは、標準アルゴリズムの使用にも当てはまります。たとえば、for_eachアルゴリズムはテンプレート化されているため、コンパイラーは、互いに使用できないfor_each_vector_float_iterator関数とfor_each_map_float_iterator関数のようなものを作成します。

コンパイル時に生成される型について考えると役に立ちます。別の型を関数に渡す操作は、実行時に手遅れになるときに発生します。コンパイル時に使用できるのは、C ++のテンプレートの「一般化」(そう、私はその言葉を作りました)機能だけです。

そうは言っても、@ Luchian Grigoreは、この問題に対する最も認識された答えを持っていoperator+ます。追加ステートメントに表示される可能性のあるさまざまなタイプのいずれかを処理することに特化しています。苦痛ですか?ええ、少し。

そうは言っても、boost :: anyは、ユースケースに求めているものです。これらは、テンプレートを使用せずにさまざまなタイプを処理することで、あらゆるタイプを処理するSTLのようなコンテナーです。

于 2012-09-03T18:24:45.217 に答える