7
votes

Est-il autorisé à hériter d'une classe dans l'espace de noms STD (nommément STD :: Wstring)?

La classe STD :: wstring manque certaines opérations pour les chaînes "normales" C (et littéraux).

J'aimerais ajouter ces opérations manquantes dans ma propre classe personnalisée: xxx < / Pre>

Le code ci-dessus compile une amende Ubuntu Karmic avec g ++ v4.4.1.

mais je me demande s'il y a des arguments contre le faisant?

Modifier : Quelques exemples pour clarifier ce que je veux dire avec des "opérations manquantes": xxx

edit: je voudrais avoir cela en quelque sorte " centralisé ". C'est parce que j'ai un projet à porter de M $ -Windows avec des milliers de ces opérations d'échec.

La bonne chose est la suivante: il y a un endroit central où le type de chaîne à utiliser est défini, par exemple: xxx


4 commentaires

Quelles sont les opérations manquantes?


@Gman: conversions vers et depuis char * , je présume.


Si c'est tout, découlant d'une classe de cordes complète semble trop tendre. Quel est le problème avec deux fonctions?


Je recommande vivement de mettre les routines de conversion en dehors de la classe. Ce n'est pas si beaucoup de travail écrit std :: wstring str = encoder ("str"); . En outre, déposez que void dans votre extrait, il est totalement inutile là-bas.


8 Réponses :


2
votes

Le modèle de classe std :: basique_string (de lequel std :: wstring est un typlef avec des arguments de modèle spécifiques) les pas ont un Destructeur virtuel, et en tant que tel, en héritage de celui-ci publiquement est une mauvaise idée .


0 commentaires

15
votes

C'est légal, mais beaucoup de gens le pensent indésirables. La question est que les classes de modèle de bibliothèque standard n'ont pas de destructeurs virtuels. Donc, si vous écrivez un code comme celui-ci:

std::wstring * p = new CustomWString ;
...
delete p;


0 commentaires

1
votes

Vous pouvez le faire. Mais je ne vois pas de point, depuis STD :: basique_string (et ses versions en béton STD :: String et STD :: Wstring) ne définir aucune méthode virtuelle et avoir destructeurs non virtuels. Donc, il n'y a aucun moyen, vous pouvez utiliser votre sous-classe correctement à la place d'E.G. std :: wstring.


1 commentaires

Eh bien, oui, ils pourraient le transmettre in-place-de wstring , mais l'appelant en attente d'un wstring ne pouvait qu'intervoquer le comportement de base, et non rien de l'OP ajouté. Cela soulève la question de savoir pourquoi un couplage aussi puissant (EST) comme héritage est utilisé - s'il n'y a pas de justification tout aussi forte, c'est-à-dire la substituabilité de Liskov. L'héritage est généralement un moyen paresseux d'obtenir toutes les méthodes de la base sans transférer / en les enveloppant au besoin selon la composition. Mais pourquoi pas (a) faire le travail, (b) utiliser composition composition, (c) utiliser des fonctions gratuites? L'héritage a tellement de pièges potentiels que les avantages doivent être importants



3
votes

Je pense que vous savez que basic_string ne définit pas un destructeur virtuel. Il est faux d'utiliser wstring dans un polymorphe de manière. Sinon, vous pouvez utiliser votre classe personnalisée comme d'habitude.

Donc, ce qui suit est dangereux: xxx

Utilisation directe de votre classe personnalisée est correct, par exemple < Pré> xxx


0 commentaires

3
votes

L'argument traditionnel contre hériter d'objets stl est qu'ils n'ont pas de destructeur virtuel. Alors, prenez le vecteur par exemple. Si je devais hériter de celui-ci:

 int main()
 {
     std::vector<int>* vecPtr = new CMyVect();
     delete vecPtr; // invokes vector constructor only, not yours
 }


5 commentaires

L'absence de destructeur virtuel n'est qu'un problème lorsque vous introduisez de nouveaux membres de données. (Ce n'est pas garanti par la norme, mais une mise en œuvre du compilateur devrait se déplacer de sa façon de la casser)


@peterchen: Supposons que la classe dérivée ait un ou plusieurs membres virtuels, et la classe de base ne le fait pas. Ensuite, je suis sûr que la suppression de la classe de base ira mal, car (dans une implémentation typique), il ne pointe pas le début d'une allocation de mémoire, mais le bloc sera libéré comme si elle le faisait. Le compilateur ne sort pas de son chemin. Je pense qu'il est préférable de conseiller simplement d'éviter tout comportement non défini, plutôt que d'essayer de comprendre dans quelles conditions un compilateur «raisonnable» fera en fait quelque chose de prévisible.


(En outre, l'exemple du questionneur a un nouveau membre de données).


@peterchen La norme dit explicitement que l'absence d'un destructeur virtuel entraînera un comportement non défini si un objet dérivé est supprimé via un pointeur de base. Le fait qu'il semble fonctionner ne signifie pas que le comportement n'est pas indéfini.


@Steve: J'envisagerais d'introduire un nouveau membre de données dans ce contexte - car il modifie la représentation en mémoire. .... @Neil: Cela ne signifie pas que chaque classe a besoin d'un DTor virtuel. Je conviens que nous sommes au-delà de ce qui est sanctionné par le compilateur, cependant.



10
votes

Le compilateur vous permet définitivement, car il n'ya aucun moyen de sceller une classe avec un constructeur public en C ++.

Les conteneurs STL ne sont pas conçus pour l'héritage , donc c'est généralement une mauvaise idée. C ++ a à de nombreux angles étranges pour ignorer cela. Votre classe dérivée pourrait casser avec une autre implémentation stl, ou simplement avec une mise à jour de l'environnement de construction.

Cependant, je considérerais comme un panneau d'avertissement Striiong, pas un total total non. C'est un "Tu es vraiment vraiment sûr de ce que tu fais, connaissez-vous toutes les implications et avoir de bons arguments contre toutes les alternatives"?

dans votre cas: fournir des constructeurs supplémentaires est bien (puisque l'interface publique est documentée et que vous pouvez reproduire cela), et tant que vous n'introduisez pas de nouveaux membres de données ni de la VMT, de la tranchée ou Destructeur non virtuel n'est pas un problème. (Gardez à l'esprit que la norme C ++ réclamait un comportement non défini lors de la suppression via un pointeur de classe de base sans DTTor virtuel)

Cependant, Je ne suis pas sûr de savoir comment vous souhaitez implémenter chartons * c_str () sans fournir de stockage pour la chaîne. Et dès que vous introduisez de nouveaux membres de données, vous entrez dans un domaine de mines antipersonnel.


2 commentaires

Vous avez raison concernant «Comment implémenter C_STR () sans fournir de stockage local».


Il n'y a aucun moyen de sceller une classe avec un constructeur public en C ++ - pour la postérité, il existe dans> = C ++ 11, qui a ajouté le mot-clé final pour les deux classes et méthodes virtuelles. Je suppose qu'aucune implémentation de STDLIB n'augmente a réellement effectué des classes STDLIB finale , car (a) la norme ne le stipule probablement pas et / parce que (b) il briserait toutes sortes de code (Peut-être inutilement ou même dangereusement ou même dangereusement) héritant des classes STDLIB.



3
votes

C'est possible et légal. Mais c'est une mauvaise idée. Les classes ne sont pas conçues pour l'héritage et l'extension est la mieux effectuée sans héritage. Si vous ne faites pas attention lorsque en utilisant les classes, vous obtiendrez un comportement indéfini. (Les classes n'ont pas de destructeurs virtuels)

En outre, il semble une mauvaise idée d'ajouter ces fonctions spécifiques, car elles dépendent de la locale et de l'encodage. Vous donnez la classe plus qu'une responsabilité. La fonctionnalité de la conversion entre char et wchar_t appartient ailleurs.


0 commentaires

0
votes

La possibilité de "hériter" d'une classe d'une autre est une caractéristique linguistique. Il s'agit simplement d'une fonctionnalité de langue formelle, plaine et sèche qui n'est pas liée à une application spécifique ou à un modèle d'utilisation spécifique. C'est un outil de bas niveau que vous pouvez utiliser à des fins différentes. Et pour répondre à votre question, il est parfaitement légal d'hériter de std :: wstring classe.

Cependant, la question suivante serait la question de "pourquoi". Pourquoi voulez-vous hériter de std :: wstring ?

Si vous concevez votre code dans le paradigme OOP, alors héritage publiquement de std :: wstring pourrait ne pas être une bonne idée "pourrait" être un mot clé ici. L'héritage public dans OOP implique généralement une relation est une relation dans une hiérarchie de la classe polymorphe. Classe std :: wstring n'est pas conçu pour être polymorphe, ce qui est la raison pour laquelle on peut en hériter publiquement de celui-ci comme une chose plutôt étrange à faire.

Si vous concevez votre code dans un autre paradigme, comme par exemple, la méta-programmation de modèle (TMP), alors l'héritage public peut être une chose parfaitement valide à faire. Vous voyez, dans l'héritage public de TMP, sert un objectif complètement différent, pas même à distance lié à distance au polymorphisme et aux relations.

En d'autres termes, il n'ya aucun moyen de produire une réponse concrète à votre question sans prendre en compte la plus grande image. Dans tous les cas, méfiez-vous de "mécanique" réponses, comme "car std :: wstring n'a pas de destructeur virtuel, vous ne pouvez pas hériter de celui-ci car il va casser ". Un tel raisonnement est complètement faux, même dans l'approche de l'OOP.


0 commentaires