28

これらのクラスを検討してください。

class Base
{
   ...
};

class Derived : public Base
{
   ...
};

この機能

void BaseFoo( std::vector<Base*>vec )
{
    ...
}

そして最後に私のベクトル

std::vector<Derived*>derived;

derivedfunctionに渡したいのですBaseFooが、コンパイラが許可しません。ベクトル全体を a にコピーせずに、これを解決するにはどうすればよいstd::vector<Base*>ですか?

4

9 に答える 9

44

vector<Base*>vector<Derived*>は無関係なタイプなので、これを行うことはできません。これについては、こちらのC++FAQで説明されています。

変数をaからaに変更し、それにオブジェクトを挿入する必要がvector<Derived*>ありますvector<Base*>Derived

また、vector不必要にコピーしないように、値ではなくconst-referenceで渡す必要があります。

void BaseFoo( const std::vector<Base*>& vec )
{
    ...
}

最後に、メモリリークを回避し、コードを例外安全にするために、ヒープに割り当てられたオブジェクトを処理するように設計されたコンテナの使用を検討してください。

#include <boost/ptr_container/ptr_vector.hpp>
boost::ptr_vector<Base> vec;

または、生のポインターを使用する代わりに、スマートポインターを保持するようにベクトルを変更します。

#include <memory>
std::vector< std::shared_ptr<Base*> > vec;

また

#include <boost/shared_ptr.hpp>
std::vector< boost::shared_ptr<Base*> > vec;

いずれの場合も、BaseFooそれに応じて関数を変更する必要があります。

于 2008-09-22T13:31:38.607 に答える
27

コンテナー オブジェクト ( vector<>) を渡す代わりに、残りの STL アルゴリズムのようにbeginとイテレーターを渡します。endそれらを受け取る関数はテンプレート化され、Derived* または Base* を渡すかどうかは問題になりません。

于 2008-09-22T14:10:54.767 に答える
14

この問題は、変更可能なコンテナーを持つプログラミング言語で発生します。変更可能なリンゴの袋を果物の袋として渡すことはできません。なぜなら、他の誰かがその果物の袋にレモンを入れていないことを確認できないためです。その後、リンゴの袋としての資格がなくなります。りんごの袋が可変でない場合は、果物の袋として渡しても問題ありません。共分散/反分散を検索します。

于 2008-09-22T17:06:28.793 に答える
8

1 つのオプションは、テンプレートを使用することです

template<typename T>
void BaseFoo( const std::vector<T*>& vec)
{
 ...
}

欠点は、実装をヘッダーに含める必要があり、コードが少し肥大化することです。タイプごとに異なる関数がインスタンス化されることになりますが、コードは同じままです。ユースケースによっては、迅速で汚いソリューションです。

編集、ここでテンプレートが必要な理由は、他のいくつかのポスターで指摘されているように、関連のない型に対して同じコードを記述しようとしているためです。テンプレートを使用すると、これらの問題を正確に解決できます。また、const 参照を使用するように更新しました。また、基本的に常にコピーが必要ない場合は、ベクトルのような「重い」オブジェクトを const 参照で渡す必要があります。

于 2008-09-22T13:23:07.923 に答える
2

上記のMattPrice答えを参考にすると、関数で使用するタイプが事前にわかっている場合は、ヘッダーファイルで関数テンプレートを宣言し、それらのタイプの明示的なインスタンス化を追加できます。

// BaseFoo.h
template<typename T>
void BaseFoo( const std::vector<T*>& vec);

// BaseFoo.cpp
template<typename T>
void BaseFoo( const std::vector<T*>& vec);
{
 ...
}

// Explicit instantiation means no need for definition in the header file.
template void BaseFoo<Base> ( const std::vector<Base*>& vec );
template void BaseFoo<Derived> ( const std::vector<Derived*>& vec );
于 2008-09-22T15:06:48.283 に答える
2

サードパーティのライブラリを扱っていて、これが唯一の希望である場合は、次のことができます。

BaseFoo (*reinterpret_cast<std::vector<Base *> *>(&derived));

それ以外の場合は、他の提案の1つでコードを修正してください。

于 2008-09-22T13:39:43.813 に答える
2

通常、ベース ポインターのコンテナーから開始しますが、その逆ではありません。

于 2008-09-22T13:27:17.430 に答える
1

std::vectorあなたが求めているものがサポートされていれば、キャストを使用せずに C++ 型システムを打ち負かすことができます (編集: C++ FAQ Lite への ChrisN のリンクは同じ問題について語っています) :

class Base {};
class Derived1 : public Base {};
class Derived2 : public Base {};

void pushStuff(std::vector<Base*>& vec) {
    vec.push_back(new Derived2);
    vec.push_back(new Base);
}

...
std::vector<Derived1*> vec;
pushStuff(vec); // Not legal
// Now vec contains a Derived2 and a Base!

関数はベクトルを値で受け取るためBaseFoo()、渡した元のベクトルを変更できないため、私が書いたことは不可能です。ただし、非 const 参照を使用reinterpret_cast<std::vector<Base*>&>()して を渡すとstd::vector<Derived*>、必要な結果が得られず、プログラムがクラッシュする可能性があります。

Java 配列は共変サブタイプをサポートします。これには、配列に値を格納するたびにJava が実行時の型チェックを行う必要があります。これも望ましくない。

于 2008-09-22T15:00:02.810 に答える
0

それらは無関係なタイプです-できません。

于 2008-09-22T13:23:09.780 に答える