4

基本クラスと派生クラスがあり、基本クラスへのポインターの stl ベクトルを受け取る関数があるとします。

class A { public: int x; };

class B : public A { };

void foo(const vector<A*> &va) {
    for (vector<A*>::const_iterator it = va.begin(); it < va.end(); it++)
        cout << (*it)->x << endl;
}

ポインタのリストを派生クラスに渡す方法はありますか? すなわち:

vector<B*> vb;
// ... add pointers to vb ...
foo(vb);

上記により、次のコンパイラ エラーが発生します。

error: could not convert ‘vb’ from ‘std::vector<B*>’ to ‘std::vector<A*>’

B* は A* に変換可能ですが。

最後に、単純なポインターの解決策がある場合、ブースト共有ポインターでも機能しますか?

4

4 に答える 4

5

std::vector<B*> and std::vector<A*>は技術的に無関係です。C++ では、必要なものはそのままでは許可されません。

回避策...オブジェクトstd::vector<Base*>を挿入してはいけませんか?Derivedそれがポリモーフィズム、動的ディスパッチなどのポイントです。

于 2012-10-12T23:20:47.703 に答える
2

派生した基本ポインターのベクトルから基本ポインターの一時的なベクトルを作成できます。

std::vector<B*> bv;
foo(std::vector<A*>(bv.begin(), bv.end())); 

ただし、これには、例のように foo が参照ではなく const 参照を受け入れる必要があり、非常に非効率的であり、メモリの割り当てとコピーが必要です。

その他の推奨される解決策は、foo を関数テンプレートにすることです。

template <class T>
void foo(std::vector<T*>& v);

fooが派生した A にのみ使用されることを確認するには、type_traits と SFINAE 手法を使用しますfoo。最初の引数でのみ呼び出すことに注意してください。

#include <type_traits>

template <class T>
void foo(std::vector<T*>& av,
         // don't use this second param 
         typename std::enable_if<std::is_base_of<A,T>::value>::type* = 0)
于 2012-10-12T23:28:30.243 に答える
2

@Science_Fiction が以前に述べたように、基本型へのポインターを保持するベクターを用意し、基本型と派生型の両方へのポインターを挿入する方が理にかなっていますが、これらの配列の作成を制御しない場合は、テンプレートを使用できます:

template <class T>
inline void foo(const vector<T*>& v)
{
    for (vector<T*>::const_iterator it = v.begin(); it < v.end(); ++it)
    {
        A* a = (A*) *it;
        cout << a->x << endl;
    }
}
于 2012-10-12T23:31:53.630 に答える
1

型に互換性がないため、 avector<B*>を渡すことはできません。暗黙的に に変換できる違いはありません。fooB*A*

できることはvector、正しいタイプの新しいものを作成することです。これは、たとえば次のようにして可能です。

vector<B*> vb;
// ... add pointers to vb ...

vector<A*> va(vb.size());
std::transform(vb.begin(), vb.end(), va.begin(),
               [] (B* p) { return static_cast<A*>(p); });
于 2012-10-12T23:21:02.057 に答える