web-dev-qa-db-fra.com

Vecteur pouvant avoir 3 types de données différents C++

J'essaie de créer un vecteur en C++ pouvant stocker 3 types de données différents. Je ne veux pas utiliser la bibliothèque de boost. Quelque chose comme:

vector<type1, type2, type3> vectorName; 

Dois-je créer un modèle? Et si oui, comment ferais-je cela?

10
Jonny Forney

Le moyen le plus simple de stocker plusieurs types dans le même vecteur consiste à les transformer en sous-types d'une classe parente, en encapsulant vos types souhaités dans des classes si elles ne sont pas déjà.

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();
};

Vous pouvez ensuite créer un vecteur de pointeurs Parent pouvant stocker des pointeurs vers les types enfants:

std::vector<Parent*> vec;

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

Lorsque vous accédez à des éléments directement à partir du vecteur, vous ne pourrez utiliser que les membres appartenant à Parent. Par exemple, vous pouvez écrire:

vec[0]->print();

Mais non:

vec[0]->type1Method();

Comme le type d'élément a été déclaré comme Parent* et que le type Parent n'a pas type1Method.

Si vous devez accéder aux membres spécifiques à un sous-type, vous pouvez convertir les pointeurs Parent en sous-types, comme suit:

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();
}

Bien qu’il soit généralement considéré comme une meilleure idée d’éviter ce type de branchement explicite de types et de faire plutôt appel à des méthodes virtuelles.

Assurez-vous de supprimer les pointeurs avant de les supprimer du vecteur si vous utilisez l'allocation dynamique, comme je l'ai fait dans l'exemple ci-dessus. Vous pouvez également utiliser des pointeurs intelligents (probablement std::unique_ptr) et laisser votre mémoire se débrouiller toute seule:

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

J'essaie de créer un vecteur en C++ pouvant stocker 3 types de données différents.

La réponse ici dépend vraiment du cas d'utilisation particulier:

  1. Si les objets sont en quelque sorte connectés et similaires d'une certaine manière - créez une classe de base et en dérivez toutes les classes, puis créez le magasin de vecteurs unique_ptrs dans la classe parente (voir ApproachingDarknessFish s pour obtenir des détails),

  2. Si les objets sont tous de types fondamentaux (donc intégrés) - utilisez une union qui regroupe les types et définissez un vector<yourUnionType>,

  3. Si les objets sont de type inconnu, mais que vous êtes sûr qu'ils partagent une interface similaire, créez une classe de base et dérivez-y une classe enfant modèle (template <typename T> class container: public parent{};), puis créez un vector<unique_ptr<parent>> comme dans le premier cas,

  4. Si les objets sont de types qui, pour une raison quelconque, ne peuvent pas être connectés (ainsi, par exemple, vector stocke int, std::string et yourType), connectez-les via une union, comme dans 2 . Ou encore mieux ...

... si vous avez le temps et que vous voulez apprendre quelque chose - regardez comment boost::any est implémenté et essayez de le faire vous-même, si vous ne voulez vraiment pas utiliser la bibliothèque elle-même. Ce n'est pas aussi difficile que cela puisse paraître.

7
Paweł Stawarz

vous pouvez utiliser std :: any, stocker vos objets dans le vecteur comme si de rien et quand vous les retirez, utilisez type () == typeid (mytype)

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

Ceci n'est cependant que pour C++ 17.

0
stephane k.

Est-ce que cela doit être un vecteur? Vous pouvez simplement considérer une liste liée de type générique, puis parcourir cette liste, utiliser typeid () pour déterminer le type de données du nœud et extraire les données avec une fonction node.get ().

0
FunkMasterP