Question

Y at-il une raison pour laquelle std::type_info est spécifié polymorphes? Le destructor est spécifié comme virtuel (et il y a un commentaire à l'effet de « afin qu'il soit polymorphes » dans la conception et l'évolution de C ++). Je ne vois pas vraiment une raison impérieuse. Je n'ai pas cas d'utilisation spécifique, je me demandais si jamais il y avait une raison ou une histoire derrière elle.


Voici quelques idées que je suis venu avec et rejetais:

  1. Il est un point d'extension - implémentations peuvent définir des sous-classes, et les programmes pourraient alors essayer de dynamic_cast un std::type_info à un autre, type dérivé défini par l'implémentation. Ceci est peut-être la raison, mais il semble que c'est tout aussi facile pour les implémentations d'ajouter un membre défini la mise en œuvre, ce qui pourrait être virtuelle. Les programmes qui souhaitent tester ces extensions seraient nécessairement non-portable de toute façon.
  2. Il est de veiller à ce que les types dérivés sont détruits correctement lorsque deleteing un pointeur de base. Mais il n'y a pas de types dérivés standard, les utilisateurs ne peuvent pas définir des types dérivés utiles, car type_info n'a pas les constructeurs standards publics, et ainsi deleteing un pointeur type_info est jamais légal et portable. Et les types dérivés ne sont pas utiles parce qu'ils ne peuvent pas être construits - l'utilisation que je sais que pour ces types dérivés inconstructible est dans la mise en œuvre des choses comme le trait de type is_polymorphic
  3. .
  4. Il laisse ouverte la possibilité de métaclasses avec des types personnalisés - chaque véritable class A polymorphes obtiendrait une A__type_info « metaclass » dérivé, qui dérive de type_info. Peut-être que ces classes dérivées pourraient exposer les membres qui new A d'appel avec divers arguments du constructeur d'une manière de type sécurisé, et des choses comme ça. Mais faire se rend en fait une telle idée polymorphique type_info pratiquement impossible à mettre en œuvre, parce que vous devriez avoir métaclasses pour vos métaclasses, ad infinitum, ce qui est un problème si tous les objets type_info ont une durée de stockage statique. barrant peut-être c'est la raison pour le rendre polymorphes.
  5. Il y a une certaine utilisation pour appliquer des fonctionnalités RTTI (autres que dynamic_cast) se std::type_info, ou quelqu'un a pensé qu'il était mignon, ou gênant si type_info était pas polymorphes. Mais étant donné qu'il n'y a pas de type dérivé standard, et pas d'autres classes dans la hiérarchie standard que l'on pourrait raisonnablement essayer de contre-CAST pour, la question est: quoi? Y at-il une utilisation pour des expressions telles que typeid(std::type_info) == typeid(typeid(A))?
  6. Il est parce que implémenteurs vont créer leur propre type dérivé privé (comme je crois que GCC fait). Mais, pourquoi prendre la peine de le spécifier? Même si le destructor n'a pas été spécifié comme virtuel et un implémenteur a décidé qu'il devrait être, sans doute que la mise en œuvre pourrait la déclarer virtuelle, parce qu'elle ne change pas l'ensemble des opérations autorisées sur type_info, donc un programme portable ne serait pas en mesure de faire la différence.
  7. Il y a quelque chose à voir avec les compilateurs avec ABIs coexistant partiellement compatible, peut-être en raison de l'enchaînement dynamique. Peut-être pourraient reconnaître leur implémenteurs propre sous-classe de type_info (par opposition à une provenant d'un autre fournisseur) de manière portable si type_info est garanti virtuelle.

Le dernier est le plus plausible pour moi en ce moment, mais il est assez faible.

Était-ce utile?

La solution

Je suppose qu'il est là pour la commodité de mise en œuvre. Il leur permet de définir des classes de type_info étendues, et les supprimer par des pointeurs vers type_info à la sortie du programme, sans avoir à construire dans la magie spéciale du compilateur pour appeler le destructor correct, ou sauter à travers des cerceaux autrement.

  

sûrement que la mise en œuvre pourrait   déclarer virtuelle, parce qu'il ne   modifier l'ensemble des opérations autorisées   sur type_info, donc un programme portable   ne serait pas en mesure de dire   différence.

Je ne pense pas que ce soit vrai. Considérez ce qui suit:

#include <typeinfo>

struct A {
    int x;
};

struct B {
    int x;
};

int main() {
    const A *a1 = dynamic_cast<const A*>(&typeid(int));
    B b;
    const A *a2 = dynamic_cast<const A*>(&b);
}

Que ce soit raisonnable ou non, la première coulée dynamique est autorisée (et Equivaut à un pointeur NULL), tandis que la seconde coulée dynamique n'est pas autorisé. Donc, si type_info a été défini dans la norme pour que le non-destructor virtuelle par défaut, mais une implémentation a ajouté un destructor virtuel, un programme portable pourrait faire la différence [*].

Il semble plus simple de me mettre le destructeur virtuel dans la norme, que ce soit à:

a) mettre une note dans la norme, bien que la définition de la classe implique que type_info n'a pas de fonctions virtuelles, il est permis d'avoir une destructor virtuelle.

b) déterminer l'ensemble des programmes qui peuvent distinguer si type_info est polymorphe ou non, et à les interdire tout. Ils ne peuvent pas être très programmes utiles ou productifs, je ne sais pas, mais de les interdire, vous devez venir avec une langue standard qui décrit l'exception spécifique que vous faites aux règles normales.

Par conséquent, je pense que la norme doit mandater soit le destructor virtuel, ou l'interdire. Rendant facultatif est trop complexe (ou peut-être devrais-je dire, je pense qu'il serait jugé inutilement complexe. La complexité n'a jamais cessé de le Comité des normes dans les domaines où il a été jugé utile ...)

S'il a été interdit, cependant, alors une mise en œuvre pourrait:

  • ajouter une destructor virtuelle à une classe dérivée de type_info
  • déduire la totalité de ses typeinfo objets de que class
  • l'utilisation qui en interne comme la classe de base polymorphes pour tout

qui résoudrait la situation que je décrivais au sommet du poteau, et type statique d'une expression typeid serait encore const std::type_info, il serait difficile pour les implémentations de définir les extensions où les programmes peuvent dynamic_cast à différentes cibles pour voir quel genre d'objet type_info qu'ils ont dans un cas particulier. Peut-être la norme espérait permettre que, bien qu'une mise en œuvre pourrait toujours offrir une variante de typeid avec un autre type statique ou garantie qu'un static_cast à une certaine classe d'extension fonctionnera, puis laisser le dynamic_cast du programme à partir de là.

En résumé, pour autant que je sais que le virtuel est potentiellement destructor utile aux initiateurs de projets et le retirer ne gagne rien à personne autre que nous ne serions pas passer du temps se demander pourquoi il est là; -)

[*] En fait, je n'ai pas démontré que. Je l'ai démontré qu'un programme illégal serait, ceteris paribus, compilez. Mais une mise en œuvre pourrait peut-être travailler autour de ce en veillant à ce que tout est pas égal, et qu'il ne compile pas. Le is_polymorphic Boost n'est pas portable, si bien qu'il est possible pour un programme de test d'une classe polymorphes, qui devrait être, il peut y avoir aucun moyen pour un programme conforme à l'essai qu'une classe est pas polymorphes, cela ne devrait pas être. Je pense cependant que même s'il est impossible, ce qui prouve que, afin d'éliminer une ligne de la norme, est tout à fait beaucoup d'efforts.

Autres conseils

La norme C ++ indique que les rendements de typeid un objet de type type_info, OU UNE MISE EN OEUVRE définie sous-classe de celle-ci. Alors ... Je suppose que cela est à peu près la réponse. Je ne vois donc pas pourquoi vous rejetez vos points 1 et 2.

Le paragraphe 1 de l'article 5.2.8 de la norme actuelle C ++ lit comme suit:

  

Le résultat d'une expression est une typeid   lvalue de type statique const   std :: type_info (18.5.1) et dynamique   de type const std :: type_info ou const   nom où nom est un   classe d'implémentation défini dérivée   std :: type_info qui conserve   le problème décrit dans 18.5.1.61)   La durée de vie de l'objet désigné   par la lvalue se prolonge jusqu'à la fin de   le programme. Que ce soit ou non   destructor est appelé à la type_info   objet à la fin du programme est   Non spécifié.

qui signifie à son tour que l'on pourrait écrire le code suivant est légal et fin: const type_info& x = typeid(expr); qui peut exiger que type_info être polymorphes

A propos de la plus simple id « global » vous pouvez avoir en C ++ est un nom de classe et typeinfo fournit un moyen de comparer cette id est pour l'égalité. Mais la conception est si maladroit et limité que vous devez ensuite envelopper typeinfo dans une classe d'emballage, par exemple pour être en mesure de mettre des instances dans les collections. Andrei Alexandrescu a fait dans son « Modern C ++ Design » et je pense que cette enveloppe de typeinfo fait partie de la bibliothèque Loki; il y a probablement un aussi Boost; et il est assez facile de rouler vos propres, par exemple voir mon wrapper.

Mais même pour un tel emballage il n'y a pas en général besoin d'un destructor virtuel dans typeinfo.

La question est donc pas tellement « hein, pourquoi est-il un destructeur virtuel », mais plutôt, comme je le vois «hein, pourquoi est la conception si arriérées, maladroit et ne sont pas directement utilisables »? Et je mettrais cela sur le processus de normalisation. Par exemple, iostreams ne sont pas exactement des exemples de conception superbe, que ce soit; pas quelque chose à imiter.

  

3 / Il laisse ouverte la possibilité de métaclasses avec des types personnalisés - chaque véritable class A polymorphes obtiendrait une A__type_info « metaclass » dérivé, qui dérive de type_info. Peut-être que ces classes dérivées pourraient exposer les membres qui new A d'appel avec divers arguments du constructeur d'une manière de type sécurisé, et des choses comme ça. Mais faire se rend en fait une telle idée polymorphique type_info pratiquement impossible à mettre en œuvre, parce que vous devriez avoir métaclasses pour vos métaclasses, ad infinitum, ce qui est un problème si tous les objets type_info ont une durée de stockage statique. barrant peut-être c'est la raison pour le rendre polymorphes.

Clever ...

Quoi qu'il en soit, je suis en désaccord avec ce raisonnement: cette mise en œuvre pourrait facilement exclure une méta classes pour les types dérivés de type_info, y compris lui-même type_info

.
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top