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?
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:
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_ptr
s dans la classe parente (voir ApproachingDarknessFish s pour obtenir des détails),
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>
,
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,
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.
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.
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 ().