70

複数のクラスのインスタンスをベクトルに格納したいと考えています。すべてのクラスが同じ基本クラスから継承するため、これは可能です。

このプログラムを想像してください:

#include <iostream>
#include <vector>
using namespace std;

class Base
{
    public:
    virtual void identify ()
    {
        cout << "BASE" << endl;
    }
};

class Derived: public Base
{
    public:
    virtual void identify ()
    {
        cout << "DERIVED" << endl;
    }
};

int main ()
{
    Derived derived;

    vector<Base> vect;
    vect.push_back(derived);

    vect[0].identify();
    return 0;
}

「identify」メソッドは仮想であるため、「DERIVED」と出力されると予想していました。代わりに、「vect[0]」は「ベース」インスタンスのようで、出力されます

ベース

これを行うことができる独自のコンテナ(おそらくベクトルから派生)を何らかの方法で作成できると思います(おそらくポインタのみを保持しています...)。これを行うためのよりC ++っぽい方法があるかどうかを尋ねたかっただけです。そして、私は完全にベクトル互換になりたいです (他のユーザーが私のコードを使用する場合の便宜のため)。

4

5 に答える 5

83

あなたが見ているのはObject Slicingです。
基本クラスのオブジェクトを格納することになっているベクトルに派生クラスのオブジェクトを格納しています。これにより、オブジェクトのスライスが発生し、格納されているオブジェクトの派生クラス固有のメンバーがスライスされるため、ベクトルに格納されているオブジェクトは次のように機能します。 Base クラスのオブジェクト。

解決:

Base クラスのオブジェクトへのポインターをベクターに格納する必要があります。

vector<Base*> 

Base クラスへのポインターを格納することにより、スライスがなくなり、目的のポリモーフィック動作も実現できます。
これを行う方法を求めるのでC++ish、適切なアプローチは、ベクトルに生のポインターを格納する代わりに、適切なスマート ポインターを使用することです。これにより、メモリを手動で管理する必要がなくなり、RAIIが自動的にそれを行います。

于 2012-01-08T13:02:55.770 に答える
7

あなたはスライスを経験しています。ベクターはderivedオブジェクトをコピーし、タイプの新しいものBaseが挿入されます。

于 2012-01-08T13:03:45.077 に答える
6

TL;DR: 公的にコピー可能/移動可能なクラスから継承するべきではありません。


実際には、コンパイル時にオブジェクトのスライスを防ぐことができます。このコンテキストでは、ベース オブジェクトをコピー可能にするべきではありません。

ケース 1: 抽象ベース

ベースが抽象的である場合、インスタンス化できないため、スライスを体験できません。

ケース 2: コンクリート基礎

ベースが抽象的でない場合は、(デフォルトで) コピーできます。次の 2 つの選択肢があります。

  • コピーを完全に防止する
  • 子供にのみコピーを許可する

注: C++11 では、移動操作によって同じ問題が発生します。

// C++ 03, prevent copy
class Base {
public:

private:
    Base(Base const&);
    void operator=(Base const&);
};

// C++ 03, allow copy only for children
class Base {
public:

protected:
    Base(Base const& other) { ... }
    Base& operator=(Base const& other) { ...; return *this; }
};

// C++ 11, prevent copy & move
class Base {
public:
    Base(Base&&) = delete;
    Base(Base const&) = delete;
    Base& operator=(Base) = delete;
};

// C++ 11, allow copy & move only for children
class Base {
public:

protected:
    Base(Base&&) = default;
    Base(Base const&) = default;
    Base& operator=(Base) = default;
};
于 2013-08-21T07:40:36.807 に答える
3

私はvector<Base*>それらを保管するために使用します。と言うとvector<Base>、スライスが発生します。

これは、ベクトルからポインターを削除した後、実際のオブジェクトを自分で削除する必要があることを意味しますが、それ以外の場合は問題ありません。

于 2012-01-08T13:03:14.610 に答える