web-dev-qa-db-ja.com

3つの異なるデータ型を持つことができるベクトルC ++

3つの異なるデータ型を格納できるベクトルをC++で作成しようとしています。 boostライブラリを使いたくありません。何かのようなもの:

vector<type1, type2, type3> vectorName; 

テンプレートを作成する必要がありますか?そして、もしそうなら、私はそれをどのように行いますか?

15
Jonny Forney

複数の型を同じベクターに格納する最も簡単な方法は、それらを親クラスのサブタイプにして、目的の型がクラスでない場合はクラスにラップすることです。

class Parent
{
  //anything common to the types should be declared here, for instance:
  void print() //make this virtual if you want subclasses to override it
  {
     std::cout << "Printing!";
  }

  virtual ~Parent(); //virtual destructor to ensure our subclasses are correctly deallocated
};

class Type1 : public Parent
{
    void type1method();
};

class Type2 : public Parent
{
    void type2Method();
};


class Type3 : public Parent
{
    void type3Method();
};

次に、子タイプへのポインターを格納できるParentポインターのベクトルを作成できます。

std::vector<Parent*> vec;

vec.Push_back(new Type1);
vec.Push_back(new Type2);
vec.Push_back(new Type3);

ベクトルから要素に直接アクセスする場合、Parentに属するメンバーのみを使用できます。たとえば、次のように記述できます。

vec[0]->print();

だがしかし:

vec[0]->type1Method();

エレメントタイプはParent*として宣言されており、Parentタイプにはtype1Methodがありません。

サブタイプ固有のメンバーにアクセスする必要がある場合、次のようにParentポインターをサブタイプポインターに変換できます。

Parent *p = vec[0];

Type1 *t1 = nullptr;
Type2 *t2 = nullptr;
Type3 *t3 = nullptr;

if (t1 = dynamic_cast<Type1*>(p))
{
    t1->type1Method();
}
else if (t2 = dynamic_cast<Type2*>(p))
{
    t2->type2Method();
}
else if (t3 = dynamic_cast<Type3*>(p))
{
    t3->type3Method();
}

この種の明示的な型分岐を避け、代わりに仮想メソッドに依存することは、一般的にはより良い考えと考えられていますが。

上記の例で行ったように、動的割り当てを使用する場合は、ポインターをベクターから削除する前に必ず削除してください。または、スマートポインタ(おそらくstd::unique_ptr)を使用して、メモリが自動的に処理するようにします。

std::vector<std::unique_ptr<Parent>> vec;

3つの異なるデータ型を格納できるベクトルをC++で作成しようとしています。

ここでの答えは、実際には特定のユースケースによって異なります。

  1. オブジェクトが何らかの方法で接続され、類似している場合-基本クラスを作成し、そこからすべてのクラスを派生させて、ベクトルストアunique_ptrsを親クラスに作成します(ApproachingDarknessFishの回答を参照)詳細については)、

  2. オブジェクトがすべて基本的な(組み込み)タイプである場合-タイプをグループ化し、vector<yourUnionType>を定義するunionを使用します。

  3. オブジェクトのタイプが不明であるが、それらが同様のインターフェースを共有し、基本クラスを作成して、テンプレート化された子クラスを派生させる場合(template <typename T> class container: public parent{};)、次のようにvector<unique_ptr<parent>>を作成する場合最初のケース、

  4. オブジェクトが何らかの理由で接続できないタイプである場合(たとえば、vectorintstd::string、およびyourTypeを格納します)、それらを経由して接続します2のようなunionまたは-さらに良い...

...時間があり、何かを学びたい場合は、boost::anyの実装方法を確認し、ライブラリ自体を使用したくない場合は、自分で実装してみてください。見た目ほど難しくはありません。

7
Paweł Stawarz

std :: anyを使用し、オブジェクトをベクトルとしてanyとして保存し、それらを取り出すときにtype()== typeid(mytype)を使用することができます

https://en.cppreference.com/w/cpp/utility/any

ただし、これはC++ 17以降のみです。

3
stephane k.

ベクトルである必要がありますか?ジェネリック型のリンクリストを検討し、そのリストを反復処理し、typeid()を使用してノードのデータ型を把握し、node.get()関数でデータをプルすることができます。

0
FunkMasterP