2

クラスまたはクラスNSArrayのいずれかのインスタンスのObjective-Cがあるとします。これらのクラスには両方ともメソッドがあります。ShoeComputerage

Objective-C を使用すると、次のような 1 つの簡単なステートメントで、すべての靴とコンピューターの年齢を取得できます。

NSArray *agesOfShoesAndComputers = [ourArray valueForKey:@"age"];

C++には、たとえばベクトルに適用できる同様の方法論がありますか?または、このようなものは、C++では常にやや面倒ですか?

4

3 に答える 3

6

まず、静的にstd::vector<T>型付けされます。つまり、コンパイル時に、靴が含まれているか、コンピューターが含まれているかを知る必要があります。

つまり、簡単な答えは、C ++では常に面倒になるということです(静的型付けは実際には最適化であるため、これがパフォーマンスに支払う代償です)。


従来のランタイムポリモーフィズムを使用する場合は、共通の基本クラスが必要です。

class MyBase
{
public:
    virtual ~MyBase();
    virtual int age() = 0;
};

class Shoe: public MyBase
{
public:
    virtual int age();
};
// same for Computer

今私は持つことができます

std::vector<std::unique_ptr<MyBase>> ourArray;

std::vector<int> ages(std::vector<std::unique_ptr<MyBase>> const &ourArray)
{
    std::vector<int> ages;
    std::transform(ourArray.begin(), ourArray.end(),
                   std::back_inserter<int>(ages),
                   [](std::unique_ptr<MyBase> const& elem) { return elem->age(); }
                  );
    return ages;
}

ここへの呼び出しelem->age()は、で定義された共通インターフェースに依存しますMyBaseが、派生クラスの実装(Shoe::age()およびComputer::age()それぞれ)にディスパッチします。

共通のインターフェース、継承などはすべて静的に定義されているため、ObjectiveCバージョンよりも柔軟性が低くなります。

これが単純なプロパティである場合は仮想メソッド呼び出しを完全にスキップして、MyBase代わりに配置できることに注意してください。靴とコンピューターは引き続きこのクラスから継承する必要がありますが、基本クラスでプロパティ値を設定するだけです。


代わりに、コンパイル時のポリモーフィズム、つまりテンプレートを使用できる場合があります。これは、継承関係に関係なく、期待されるメソッドをサポートするすべてのタイプで機能するため、ObjectiveCのアプローチにいくつかの点で似ています。

template <typename T> // T could be Shoe, Computer or anything else
std::vector<int> ages(std::vector<T> const &ourArray)
{
    std::vector<int> ages;
    std::transform(ourArray.begin(), ourArray.end(),
                   std::back_inserter<int>(ages),
                   [](T const& elem) { return elem.age(); }
                  );
    return ages;
}

ただし、メカニズムは完全に異なります。静的に区別された呼び出しサイトがあり、どちら vector<Shoe> vector<Computer>または何でもあり、2つが出会うことはありません。

于 2012-08-16T16:14:36.313 に答える
2

コンパイラがサポートしていないlambdas場合は、使用できます<functional>(ただし、いずれにしても c++ 11)。

std::vector<std::shared_ptr<Base>> v;

std::vector<int> ages;
std::transform(v.begin(),
               v.end(),
               std::back_inserter(ages),
               std::bind(&Base::getAge, std::placeholders::_1));

Baseの基本クラスはどこですかShoeComputer

テンプレートを使用して、関数をサポートする任意の型から年齢を取得することもできgetAge()ます。

template <typename InputIterator>
static std::vector<int> getAges(InputIterator start, InputIterator finish)
{
    typedef typename InputIterator::value_type T;

    std::vector<int> ages;
    std::transform(start,
                   finish,
                   std::back_inserter(ages),
                   std::bind(&T::getAge, std::placeholders::_1));
    return ages;
}

int main()
{
    std::vector<Base> v;
    std::vector<int> ages = getAges(v.begin(), v.end());
}
于 2012-08-16T16:09:12.597 に答える
2

C++ はやや動的ではありませんが、一般的に探しているのは次のtransformとおりです。

vector<unique_ptr<BaseClassForShoeAndComputer>> ourArray;
vector<int> agesOfShoesAndComputers;

transform(ourArray.begin(), ourArray.end(),
          back_inserter(agesOfShoesAndComputers),
          [](unique_ptr<BaseClassForShoeAndComputer>& s) { return s->age(); });

ただし、無関係なオブジェクトを 1 つのコンテナー内に配置することはできません (可能ですが、それらを使用するかどうかは別問題です)。ただし、テンプレートを使用して (残念ながら、ラムダでは使用できません)、静的なダック タイピングを実現できます ("age" メソッドを使用する任意の型で使用できます)。

于 2012-08-16T16:07:03.937 に答える