10
votes

Pourquoi STD :: Sub_Match hériter publiquement de STD :: paire ?

Je lisais la documentation de std :: sub_match std :: paire . Étant donné qu'un sub_match est simplement une paire d'itérateurs dans une séquence de caractères, avec quelques fonctions supplémentaires, je peux comprendre qu'il est implémenté avec une paire , mais pourquoi utiliser l'héritage public ?

Le problème avec héritage publiquement à partir de std :: paire est identique à hériter publiquement de la plupart des autres classes standard: ils ne sont pas destinés à être manipulés polymorphiquement (notamment ils ne le font pas définir un destructeur virtuel). D'autres membres ne manqueront pas de fonctionner correctement, à savoir l'opérateur d'affectation et la fonction de membre d'échange (ils ne copieront pas le membre correspondant de sub_match ).

Pourquoi stimulera-t-on les développeurs, puis le comité a décidé de mettre en œuvre Sub_Match en héritant publiquement à partir de la paire au lieu d'utiliser la composition (ou héritage privé avec l'utilisation de déclarations si elles voulaient conserver Accès membre via premier et second )?


0 commentaires

5 Réponses :


0
votes

Parce qu'ils n'avaient pas besoin de destructeurs virtuels? ; -)


10 commentaires

Les destructeurs ne sont pas les seuls membres qui ne vont pas fonctionner correctement: l'opérateur d'affectation et l'échange ne copieront que les membres et non ceux contenus par sub_match (le correspondant boolean notamment).


Les auteurs ont évidemment estimé qu'ils n'avaient pas besoin d'un destructeur virtuel, ou ils auraient fourni un. Mais pourquoi, puisque dans la plupart des cas, le patrimoine public implique la nécessité d'un destructeur virtuel dans la classe de base.


@LUCTOURAILLE Bon point. Clairement, il n'y a pas d'intention que sub_match ISA paire .


@Jameskanze: Vous avez raison, la relation "is-a" ne s'applique pas à ces deux classes, le principe de substitution de Liskov n'est pas respecté.


@LUC TOURAILLE: Bien que cela soit plus que raisonnable, de s'attendre à ce que la destruction fonctionne correctement pour des objets polymorphes, je dirais que l'attente d'une affectation ou d'un échange pour faire quoi que ce soit sensible dans un contexte polymorphique demande des problèmes.


@Nicolamusatti: C'est un point juste, qui corrobore en fait le fait que l'héritage est probablement une mauvaise idée ici: paire et sub_match sont les deux types avec une sémantique de valeur, qui sont destiné à être copié, assigné, etc. En tant que tel, je ne pense pas que les avoir dans une hiérarchie de classe est un tel design, car il fabrique l'utilisateur de faire preuve de prudence de trancher des problèmes et autres.


Eh bien, la chose est que Sub_Match est une paire et rien d'autre, il n'a donc besoin aucune fonctionnalité supplémentaire. En y hérissant de la paire, vous avez un avantage de l'utiliser où une paire est acceptée.


@ Michaelkrelin-Hacker: C'est le point: c'est est plus qu'une paire. Il dispose notamment d'un membre Boolean correspondant. Et cela ne fonctionne pas partout a est accepté (cf. boost.range).


Oui, tu as raison, c'est plus qu'une paire. Je ne sais pas pourquoi paire ne fonctionnerait-il pas où la paire est acceptée, mais cependant.


@Michael: Dans le cas de Boost.Range, il doit s'agir d'un problème de spécialisation du modèle, ce qui ne fonctionne pas très bien avec la hiérarchie de l'héritage. Je dois admettre que cela n'est pas très pertinent pour le sujet, car il s'agit plus d'une faille de conception de modèles.



0
votes

Si std :: sub_match n'a aucun état, alors il convient de hériter de std :: paire . Ne le faites pas à la maison cependant.


2 commentaires

L'état n'a rien à voir avec ça. Si vous supprimez un SUB_MATCH Objet via un paire <> pointeur, c'est un comportement indéfini.


De plus, il a en effet un état propre (un booléen indiquant si le match a été réussi).



5
votes

C'est une question intéressante. Vraisemblablement, ils considéraient cela en sécurité Parce que personne ne l'allouerait jamais de façon dynamique une de toute façon. À propos de Seule façon que vous allez obtenir sub_match est comme une valeur de retour de certaines des fonctions de basic_regex ou en copies d'autres sub_match , et tous ces éléments seront temporaires ou locaux variables.

Notez qu'il n'est pas sûr de garder sub_match Objets autour de toute façon, car ils contiennent des itérateurs dont la vie ... ne semble pas être spécifiée dans le standard. Jusqu'à ce que l'objet match_results est réutilisé? Jusqu'à ce que le chaîne opérande à la fonction rempli dans le match_results l'objet est désttructif? Ou?

J'aurais toujours évité l'héritage public. Mais dans ce cas, c'est pas aussi dangereux que cela semble, car il n'y a vraiment aucune raison. jamais envie d'allouer de manière dynamique un sub_match .


1 commentaires

Je suis d'accord sur l'allocation dynamique qui ne devrait probablement jamais arriver. Cependant, des problèmes pourraient toujours apparaître avec = et échange . Je pensais à Boost.Range par exemple, mais cela ne nécessite pas que des gammes soient assignées ou rapides. Cependant, il est intéressant de noter que Boost.Range algorithmes n'accepte pas Sub_Match ES comme des arguments, mais le font si elles sont manipulées via une référence à une paire (catégories de trait> problèmes).



3
votes

Voici ce que Regex S doit en dire à ce sujet: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2003/n1429.htm#matches_discussions

rien de très spécifique à votre question, j'ai peur.

Je devinerais que cette décision était un compromis entre réinventer la roue et introduire un peu de risque d'utilisation abusive. Notez que, en général, il n'est pas nécessaire de construire un sub_match , ils sont renvoyés à partir de la fonction regex . De plus, les paires d'itérateurs sont un moyen très pratique de mettre en œuvre des gammes.


0 commentaires

3
votes

Parce que c ++ n'a aucun moyen d'hériter d'une interface sans héritage public. Vous pouvez hériter d'une mise en œuvre avec héritage privé, mais tout est privé. Si vous voulez la même interface qu'un std :: paire , vous devez être a std :: paire .

aussi, envisagez cette. Ceci est évidemment un comportement non défini: xxx

mais est-ce tel: xxx

Pourquoi est-ce le premier à beaucoup plus de une préoccupation que la seconde?

sub_match et paire sont des objets de poids léger (en fonction de leur contenu bien sûr). Ils sont destinés à être copiés ou passés par référence, tout ce qui est sûr à 100%. Il y a peu de raisons de les affecter sur le tas et de les utiliser à travers des pointeurs. Donc, alors que je comprends votre préoccupation, je pense qu'il est peu probable qu'il se produise dans n'importe quel code réel.


3 commentaires

En effet, votre deuxième exemple est (presque) aussi défectueux que le premier, mais c'est parce que vous avez considéré que le membre serait public: pourquoi supposeriez-vous qu'une telle encapsulation aussi mauvaise serait utilisée? Et pendant que je conviens que la suppression ne serait probablement jamais une question, je suis en désaccord que le passage par référence est 100% sûr, en raison des autres fonctions de membre non virtuel.


Vous peut hériter (pièces) d'une interface publique à l'aide d'une héritage privé: classe SUB_MATCH: paire {Utilisation de paire.First; en utilisant la paire.seconde; bool correspondant; }


Si vous souhaitez la même interface qu'un std :: paire sans être un, vous pouvez utiliser un héritage privé avec l'utilisation de déclarations et / ou de délégation. Bien sûr, cela reste beaucoup plus de travail pour le développeur de la sous-classe.