9
votes

Maintenir la référence à tout type d'objet en C ++?

J'essaie de m'enseigner moi-même C ++ et l'une des exercices traditionnels «nouvelles langues» que j'ai toujours utilisées est de mettre en œuvre une structure de données, comme un arbre binaire ou une liste liée. En Java, cela a été relativement simple: je pourrais définir un noeud de classe qui a conservé une variable d'instance Data d'objet , de sorte que quelqu'un puisse stocker n'importe quel type d'objet dans chaque nœud de la liste ou de l'arbre. (Plus tard, j'ai travaillé à la modification de cela en utilisant des génériques; ce n'est pas la question de cette question.)

Je ne trouve pas de manière similaire, idiomatique C ++ de stocker "tout type d'objet". En C, j'utiliserais un indicateur annulation ; La même chose fonctionne pour C ++, évidemment, mais je rencontre des problèmes lorsque je construis une instance de std :: string et essayez de le stocker dans la liste / arborescence (quelque chose à propos d'un casting non valide de < Code> std :: string & to vide * ). Y a-t-il une telle manière? C ++ a-t-il équivalent à l'objet de Java (ou NSOBJECT DE CY-C)?

Question de bonus: Si ce n'est pas le cas, et j'ai besoin de continuer à utiliser des pointeurs Void, quel est le moyen "droit" de stocker un std :: string dans un vide * ? Je suis tombé sur static_cast (str.c_str ()) , mais cela semble un type de verbeux pour ce que j'essaie de faire. Y a-t-il une meilleure façon?


4 commentaires

Pourquoi cette question a-t-elle été descendue?


Je suis intéressé à savoir aussi - je n'ai pas pu trouver de dupe ou de rien ...


C'est comme la vieille blague. Patient: Ça fait mal quand je fais ça. Docteur: Ne fais pas ça. En C ++, ne faites pas une collection de "quoi que ce soit".


@ Jerry Coffin- +1, avec la mise en garde qui pour apprendre, alors tout se passe. Il n'y a rien de mal à mettre en œuvre une collection en C ++ pour apprendre les constructions de langue, mais lorsque vous avez terminé l'apprentissage, jetez-la.


6 Réponses :


12
votes

C ++ n'a pas d'objet de base que tous les objets héritent de, contrairement à Java. L'approche habituelle de ce que vous voulez faire serait d'utiliser Modèles . Tous les conteneurs de la bibliothèque C ++ standard utilisent cette approche.

Contrairement à Java, C ++ ne s'appuie pas sur le polymorphisme / l'héritage pour mettre en œuvre des conteneurs génériques. En Java, tous les objets héritent de objet , et une classe peut donc être insérée dans un conteneur qui prend un objet . Les modèles C ++ sont toutefois compilés des constructions de temps qui indiquent au compilateur de générer une classe différente pour chaque type que vous utilisez. Donc, par exemple, si vous avez: xxx

Vous pouvez alors créer un myContainer qui prend std :: string objets, et un autre myContainer qui prend int s. xxx


9 commentaires

Est-il sûr pour moi d'analoguer mentalement des modèles de génériques Java?


Pas vraiment. Ils sont très différents, même si la syntaxe est superficiellement la même.


Pour élaborer, les génériques Java sont un mécanisme d'exécution qui repose sur l'héritage et le polymorphisme. Les modèles C ++ sont des constructions de compilation qui indiquent le compilateur à générer du code pour chaque type paramétré. Voir ma réponse modifiée pour plus d'informations.


En fait, croyez-le ou non, les modèles C ++ ont effectivement plus en commun avec C Macros que Java Generics. Bien sûr, ils sont beaucoup plus sûrs et plus puissants que les macros.


@CHARDLES: C'est comme dire que le Dr X est plus en commun avec le Dr Mangler que le Dr Y. La comparaison n'est pas utile et trompeuse en même temps.


@Martin, je peux voir votre point, mais les modèles sont si souvent comparés aux génériques Java (en raison d'une similitude de syntaxe, et superficiellement, une similitude en fonction), lorsqu'il est en réalité, ils sont drastiquement différents. (Génération de code temporel de compilation par rapport à un polymorphisme de temps d'exécution.) Je pensais que la comparaison avec C macros (qui sont également un mécanisme de génération de code de compilération de la compilation) a aidé à mettre en évidence cela. Mais vous avez raison, les modèles sont également très différents des macros, qui ne sont rien de plus qu'un mécanisme de prétraitement de recherche / remplacement.


@Chals: Ils sont en fait conceptuellement similaires aux macros LISP communes, mais cela ne va pas aider beaucoup de gens à saisir le concept.


Quand venant de Java Generics, je dirais que cela est en fait sûr de penser à des modèles C ++ en tant que génériques initialement, car la plupart des choses que vous attendez du travail de la même manière (à l'exception de les types). Bien sûr, les modèles sont beaucoup plus que cela, mais comme une première itération, cela devrait faire. Un problème plus important s'approche des génériques Java comme si elles sont des modèles C ++ (c'est-à-dire l'autre direction à l'auteur de la question).


Alors, que si je voulais ajouter une chaîne et quelque chose d'autre comme un vecteur à un vecteur. Comme dans je veux avoir une collection d'objets différents. En Java, vous venez de faire une arrayliste , comment faites-vous cela avec la STL?



3
votes

Qu'est-ce que vous recherchez sont des modèles. Ils vous permettent de créer des cours et des fonctions qui vous permettent de prendre n'importe quel type de données.


0 commentaires

1
votes

Vous devriez être capable de lancer un Void * dans une chaîne à l'aide de moulages de style C standard. N'oubliez pas qu'une référence n'est pas traitée comme un pointeur lorsqu'il est utilisé, il est traité comme un objet normal. Donc, si vous passez une valeur par référence à une fonction, vous devez toujours la réfriger pour obtenir son adresse.

Cependant, comme d'autres l'ont dit, une meilleure façon de le faire est avec des modèles


1 commentaires

Les couts de style C doivent être découragés en C ++.



2
votes

modèles sont la manière statique de le faire. Ils se comportent comme des génériques Java et C # mais sont 100% statiques (heure de compilation). Si vous souhaitez stocker différents types d'objetcs dans le même conteneur, utilisez ceci (d'autres réponses décrivent cela très bien).

Toutefois, si vous devez stocker différents types d'objets dans le même conteneur, vous pouvez faire C'est la manière dynamique, en stockant pointeurs sur une classe de base . Bien sûr, vous devez définir votre propre hiérarchie d'objets, car il n'existe pas de ce type de "objet" en C ++: xxx

Un pointeur intelligent est plus facile à utiliser. Exemple avec boost :: smart_ptr : xxx


0 commentaires

9
votes

Vous pouvez regarder Boost :: Toute classe. Il est de type sécurisé, vous pouvez le mettre en collections standard et vous n'avez pas besoin de créer un lien avec une bibliothèque, la classe est implémentée dans le fichier d'en-tête.

Il vous permet d'écrire du code comme celui-ci: P>

#include <list>
#include <boost/any.hpp>

typedef std::list<boost::any> collection_type;

void foo()
{
    collection_type coll;
    coll.push_back(boost::any(10));
    coll.push_back(boost::any("test"));
    coll.push_back(boost::any(1.1));
}


0 commentaires

1
votes
static_cast<char*>(str.c_str())
looks odd to me.  str.c_str() retrieves the C-like string, but with type const char *, and to convert to char * you'd normally use const_cast<char *>(str.c_str()).  Except that that's not good to do, since you'd be meddling with the internals of a string.  Are you sure you didn't get a warning on that?You should be able to use static_cast<void *>(&str).  The error message you got suggests to me that you got something else wrong, so if you could post the code we could look at it.  (The data type std::string& is a reference to a string, not a pointer to one, so the error message is correct.  What I don't know is how you got a reference instead of a pointer.)And, yes, this is verbose.  It's intended to be.  Casting is usually considered a bad smell in a C++ program, and Stroustrup wanted casts to be easy to find.  As has been discussed in other answers, the right way to build a data structure of arbitrary base type is by using templates, not casts and pointers.

0 commentaires