8
votes

C ++ et son système de type: comment traiter les données avec plusieurs types?

"Introduction" forte>

Je suis relativement nouveau à C ++. J'ai traversé toutes les choses de base et réussi à construire 2-3 interprètes simples pour mes langages de programmation. P>

La première chose qui m'a donné et me donne toujours mal à la tête: Mise en œuvre du système de type de ma langue en C ++ forte> p>

Pensez à cela: Ruby, Python, PHP et Co. ont beaucoup de types intégrés qui sont évidemment mis en œuvre dans C. Alors, ce que j'ai essayé d'abord était de permettre de donner une valeur dans ma langue trois types possibles: int, string et nil. P>

Je suis venu avec ceci: p>

enum ValueType
{
     Int, String, Nil
};

extern string stringTable[255];
class Value
{
 public:
  ValueType type;
  int index;
};


3 commentaires

"Int, string, nil", qu'en est-il du flotteur?


Je supporte pleinement l'idée d'un langage de programmation sans float ! Sinon, la première question sub_language sur ce que vous serez "hé, pourquoi 0,1 + 0,2 0,2 ​​== 0.3 dans sub_language? C'est cassé!".


@SUB: Si c'est vous, vous descendez certaines des réponses, vous devez le reconsidérer. Il existe des réponses valides qui ont été évitées sans raison, dont certaines pourraient être que vous n'avez pas compris la réponse dans toute leur mesure. Si cela n'a pas été vous, à qui l'a fait: s'il vous plaît, expliquez ce que vous considérez comme mal des réponses. C'est le seul moyen d'améliorer réellement le système.


5 Réponses :


1
votes

En ce qui concerne la vitesse, vous dites:

C'était extrêmement lent de passer cette classe autour de l'allocateur de chaîne devait être appelé tout le temps.

Vous savez que vous devriez passer des objets en référence à la grande majorité du temps? Votre solution a l'air viable pour un interprète simple.


2 commentaires

Ce n'était pas si facile la plupart du temps. J'ai dû faire plusieurs copies autant de fonctions modifier temporairement les valeurs.


@sub bien cela semble douteux. Je ne vois pas pourquoi vous changeriez jamais une valeur, une fois qu'il a été créé, à moins que l'utilisateur ne l'assigne.



4
votes

Une solution évidente consiste à définir une hiérarchie de type: xxx

et ainsi de suite. À titre d'exemple complet, écrivez-nous un interprète pour une langue minuscule. La langue permet de déclarer des variables comme ceci: xxx

qui créera un objet int , attribuez-lui la valeur 10 et Stockez-le dans la table d'une variable sous le nom A . Les opérations peuvent être invoquées sur des variables. Par exemple, l'opération d'addition sur deux valeurs INT ressemble à: xxx

Voici le code complet de l'interpréteur: xxx

Un échantillon d'interaction avec l'interprète: xxx


4 commentaires

Puis-je les stocker tous dans un seul tableau? Ou sont-ils des types complètement différents comme chaîne vs int? Je suis relativement nouveau à cela.


@Vijay: Pourriez-vous s'il vous plaît expliquer comment et où stocker les instances des classes?


Ceci est une solution commune dans de nombreux systèmes. Il doit être combiné à une allocation dynamique C'est l'évolution directe de la solution C que j'ai fournie, où vous ajoutez la hiérarchie et remplacez le style C avec une distribution dynamique. Les informations de type réelles sont généralement stockées dans la classe de base (sous forme d'énorme) ou obtenues avec l'opérateur typeid ()


@sub Le moyen le plus C ++ est d'utiliser std :: Carte en tant que table de symboles. Je modifierai ma réponse avec un exemple plus complet.



1
votes

C ++ est une langue fortement dactylographiée. Je peux voir que vous venez d'une langue non typée et que vous pensez toujours dans ces termes.

Si vous vraiment besoin de stocker plusieurs types dans une variable, jetez un coup d'œil à boost :: n'importe quel .

Toutefois, si vous mettez en œuvre un interprète, vous devez utiliser l'héritage et les classes qui représentent un type spécifique.


3 commentaires

Ce n'est pas mon problème. Vous ne m'avez pas dit comment et stocker les instances de ces classes.


J'ai évoqué, car la réponse est bonne: utiliser Boost :: Tout. Je ne vois pas comment ce n'est pas votre problème.


+1, d'accord. Boost :: Tout est une solution à la question écrite, même si ce n'est pas une réponse (complète) à la question de la tête de Sub.



4
votes

Il y a quelques choses différentes que vous pouvez faire ici. Différentes solutions ont augmenté dans le temps et la plupart d'entre elles ont besoin d'une allocation dynamique de la donnée réelle (Boost :: Variant peut éviter d'utiliser une mémoire allouée dynamiquement pour les petits objets --Thanks @msalters).

APPROCHE PURE C:

Informations sur le type de magasin et un pointeur vide sur la mémoire qui doit être interprété en fonction des informations de type (généralement une énumération): xxx

in c ++, vous pouvez améliorer cela Approche en utilisant des classes pour simplifier l'utilisation, mais plus important encore, vous pouvez utiliser des solutions plus complexes et utiliser des bibliothèques existantes telles que Boost :: Tout boost :: Variante offrant différentes solutions au même problème.

Boost :: Tout boost :: Variante Stockez les valeurs de la mémoire allouée dynamiquement, généralement via un pointeur à une classe virtuelle dans une hiérarchie et avec des opérateurs qui réinterpréter (Down Count) sur les types de béton. >


2 commentaires

Je ne pense pas que ça boost :: variante (ou même boost :: n'importe quel) nécessite une allocation dynamique . Ils ont des astuces spéciales pour éviter que possible. À peu près parler, même s'ils ont un Void * pour les gros objets sur le tas, ce pointeur peut faire partie d'une union dont les autres membres sont utilisés pour contenir de petits types de données.


@Msalters: Droite. Je n'avais pas examiné la mise en œuvre de la variante et utilise un tampon qui est réinterprété en fonction du type particulier utilisé, comme vous l'avez expliqué. Boostez-vous, d'autre part, est beaucoup plus simple et utilise une mémoire allouée de manière dynamique inconditionnellement.



0
votes

Selon la solution de Vijay, la mise en œuvre sera la suivante: xxx

Le bit manquant de son code est de savoir comment extraire ces valeurs ... Voici ma version (en fait j'ai appris cela de l'ogre et modifié C'est à mon goût).

Utilisation est quelque chose comme: xxx

OK, maintenant pour voir si un élément particulier est une chaîne: xxx

Le code de la catégorie de n'importe quelle classe est indiqué ci-dessous. N'hésitez pas à l'utiliser mais vous aimez :). J'espère que cela vous aide!

dans le fichier d'en-tête ... Dites an.h xxx

maintenant dans le fichier CPP ... tout.cpp xxx


1 commentaires

Oublié de mentionner. Speed-sage, c'est effectivement un pointeur à l'instance CLAS d'espace réservé, qui stocke le pointeur sur la valeur transmise. Pas trop de surcharge je suppose. Et c'est le type de type et n'a pas besoin de bibliothèques complexes comme Boost.