スタックに割り当てられたオブジェクトを使用してベクターに異種オブジェクトを保存する
-
05-07-2019 - |
質問
スタックに割り当てられたオブジェクトを使用して異種ベクトルにオブジェクトを保存する
こんにちは、
CA1、CA2、およびその他に派生した抽象クラスCAがあるとします。
これらの派生型のオブジェクトをベクトルに入れ、クラスCBに埋め込みます。ポリモーフィズムを正しく取得するには、ポインターのベクトルを保存する必要があります:
class CB
{
std::vector <CA*> v;
};
今、次の主な機能があるとします:
int main()
{
CB b;
CA1 a1;
CA2 a2;
b.Store( a1 );
b.Store( a2 );
}
簡単な方法でメソッド void CB :: Store(const CA&amp;)
を書くには、元のオブジェクトが破棄されても保存されたオブジェクトは生き残ります(これは上記の簡単な例)。
私の問題は、ベクター内のアドレスをコピーする前に、最初にヒープ上のオブジェクトをコピーする必要があることですが、派生型のオブジェクトを作成するにはどうすればよいですか?確かに、RTTIを使用して、可能なすべての型を検索し、ポインターを作成して割り当て、ベクターにプッシュする前に割り当てられたスペースにオブジェクトをコピー(適切にキャスト)できます。しかし、これは非常に複雑に思えます、いいえ?
もっと簡単な方法はありますか?
(メインで動的割り当てを使用しない!)
解決
通常、クローン機能を提供します:
struct CA
{
virtual CA *clone(void) const = 0;
virtual ~CA() {} // And so on for base classes.
}
struct CA1 : public CA
{
virtual CA *clone(void) const
{
return new CA1(*this);
}
}
struct CA2 : public CA
{
virtual CA *clone(void) const
{
return new CA2(*this);
}
}
これは仮想コンストラクタと呼ばれます。実行時にオブジェクトのコピーを作成します:
void CB::Store(const CA& pObject)
{
CA *cloned = pObject.clone();
}
Boost.Pointer Containerの使用を検討する必要があります。 ライブラリ。あなたのコードは次のようになります:
boost::ptr_vector<CA> objects;
void CB::Store(const CA& pObject)
{
objects.push_back(pObject->clone());
}
これで、メモリを自分で管理する必要がなくなりました。ライブラリはクローン関数も尊重し、オブジェクトのコピーを作成するときにそれを呼び出します。 チュートリアルはこちら。
他のヒント
派生クラスが実装する抽象クラスにclone()関数が必要なようです。
class CA
{
public:
virtual ~CA() {}
virtual CA* clone() const = 0;
}
class CA1 : public CA
{
public:
virtual CA *clone() const
{
return new CA1(*this);
}
};
可能性としては、引数の型でStoreをテンプレート化することです:
class CB
{
public:
template<class T>
void Store(const T& t)
{
v.push_back(new T(t));
}
private:
std::vector <CA*> v;
};
しかし警告:&quot; clone()&quot;とは異なり他の人が投稿したソリューション、これはスライスする傾向があります。たとえば、これは正常に機能します。
CB b;
CA1 a1;
CA2 a2;
b.Store(a1);
b.Store(a2);
しかし、これはそうではありません:
CA1 a1;
CA* a = &a1;
b.Store(*a); //Ouch! this creates a new CA, not a CA1
保護されたコピーアクターをCAに渡すと、このような誤用を防止できます。ただし、CA1をさらにサブクラス化すると、問題が再発します。