10
votes

Malentendu sur la classe et l'opérateur d'Ostream <<

Après avoir regardé le ostream :: opérateur <<< / code> C ++ Référence,

J'ai remarqué les déclarations suivantes: xxx

mais je découvert qu'il existe également les déclarations suivantes: xxx

Pourquoi les opérateurs de sortie de caractère / chaîne ne sont pas des fonctions membres?


5 Réponses :


6
votes

Le premier groupe d'opérateurs sont membres de la classe de flux.

La plupart des surcharges de l'opérateur, comme ceux du second groupe, ne sont pas.


sur le pourquoi , il est probablement juste un accident historique. Les opérateurs pour types intégrés peuvent être ajoutés aux classes de flux et, évidemment, ils étaient (bien avant que C ++ soit normalisé). La norme documente simplement la pratique existante ici.

Les opérateurs pour les types définis par l'utilisateur ne peuvent évidemment pas être ajoutés aux classes de flux. Ils sont donc mis en œuvre comme fonctions libres.

rétrospectivement, il aurait été plus cohérent de rendre tous les fonctions libres des opérateurs, mais cela permettrait de casser de vieux programmes.


14 commentaires

Savez-vous pourquoi ces standards Char Les surcharges n'ont pas été fabriqués des membres de la classe de flux?


@ Drewdormann pourrait être une bonne question à elle seule. Je pense que je pense que je me souvienne d'avoir déjà vu des problèmes (alors des questions) causés indirectement par cette distinction.


@Christianrau des commentaires ici, je soupçonne cette question est cette question .


Oui, c'est le problème principal ici;)


@Trewdormann, j'ai une théorie, n'hésitez pas à commenter ma réponse si vous pensez que cela n'a aucun sens


@ Awrewdormann & Rouki, dans ce cas, la question a besoin d'un peu de nettoyage, clarifiant que l'OP est conscient du fait que l'un est membre et que l'un n'est pas et ne demandant pas la raison plus profonde. Mais les deux questions dans une (et même sans clarification qui la questionner est) est liée à attirer supposément "mal" ou "incomplète" réponses (comme beaucoup d'excitations < I> après cette clarification).


Je n'aurais probablement pas dû demander à la fois sur le même sujet. Quoi qu'il en soit, j'ai édité le poste.


@Bo, je suis en désaccord sur l'accident historique. Je pense qu'ils ne peuvent pas être ajoutés à la classe, car il existe différentes implémentations pour basic_ostream << (char) et basic_ostream << (char) Et vous ne pouvez pas spécialiser un membre unique, ainsi que des surcharges globales.


@Zdeslavvojkovic Vous pouvez très bien spécialiser des membres individuels, tout simplement pas en les spécialisant directement, mais déléguant des parties du travail à d'autres sous-composantes (éventuellement spécialisées), comme les traits de caractère ou les paramètres régionaux (ce qu'ils sont réellement faits pour , résumant la fonctionnalité dépendante du type charret en composants plus petits et spécialisables). Pensez à une méthode classique GOF "Modèle" (modèle dans le sens de la GOF, pas le sens C ++).


@Zdeslavvojkovic - L'accident historique est que basic_ostream :: opérateur << (int) est membre. Ce n'est pas obligé d'être.


@Bopersson, oh, droite - j'ai compris Les opérateurs des types intégrés peuvent être ajoutés aux classes de flux comme référence char .


@Christianrau, bien sûr mais c'est beaucoup plus complexe que de les avoir comme des fonctions globales


@Zdeslavvojkovic "Mais c'est beaucoup plus complexe que de les avoir comme des fonctions globales" pourquoi. Les traits de caractère et les locaux sont conçus pour exactement cet objectif. Pourquoi rendre le flux et les opérateurs les prennent comme des arguments de modèle quand alors ne les utilisez pas et de faire clairement les mêmes opérations qu'ils sont censées faire et peuvent déjà faire en doublonnation de fonction unie. C'est contre tous les principes de la générosité de code et en évitant la duplication de code qui construisent la base de la conception de la bibliothèque standard (et en général une bonne bibliothèque).


@Zdeslavvojkovic, je préférerais une seule méthode de modèle qui possède un code générique (qui ne dépend pas du flux et des types de caractères) une seule fois et délégués du code spécialisé aux traits spécialisés (comme celui-ci est fait dans la bibliothèque standard), qu'un groupe des surcharges effectuant exactement les mêmes pièces de code sur et sur un souci de spéciliation de certaines petites parties du code (et ignorant complètement les traits déjà donnés).



-1
votes

La première série sont les fonctions des membres, que retour * Ceci pour la chaîne d'opérateur de l'opérateur.

La deuxième série sont des fonctions autonomes (telles que vous dites que vous pouvez ajouter pour n'importe quelle classe afin que vous puissiez les diffuser à un std :: ostream ), qui n'ont pas ceci Pour revenir et Retour OS au lieu de rendre le travail de chaînage de l'opérateur.

Notez que les deux fonctionnent de la même manière sur un site d'appel.


4 commentaires

ma compréhension de la question est que le fait est que c'est pourquoi sont-ils séparés, pas quelle est la différence


Demandé à la fois d'être honnête;)


@Zdeslavvojkovic La réponse est la même chose, car les questions posent la même chose: les premiers font partie de la classe, alors savent déjà ce que std :: ostream et pour revenir, ce dernier a besoin d'un argument supplémentaire.


Peut-être que je n'étais pas clair: la partie déroutante est pourquoi ne pas les avoir tous en tant que membres ou tous comme non membres.




2
votes

Les autres ont décrit les différences, voici mon tir de la raison pour laquelle ils sont divisés.

Les versions non membres, qui prennent des variantes Char car les paramètres sont spécialisés en fonction du type du flux cible. Type de caractère de base et manipulé en fonction de la locale, car la norme définit un comportement spécifique ( o << '1' a un comportement différent de celui de oo << 33 , il doit être manipulé correctement Si o est basic_ostream , etc).

par exemple Char ECRITEN À BASIC_OSTREAM est élargi, tandis que si écrit sur basic_ostream Ce n'est pas (27.6.2.5.4). Donc en fait, il existe de multiples surcharges d'opérateur <<< / code>, par exemple: xxx

s'ils ont été définis comme des fonctions membres, vous ne seriez pas en mesure de Spécialisez-les comme ça, comme vous l'avez besoin de spécialiser partiellement toute la classe, pas seulement un seul membre, car la norme n'autorise pas la spécialisation partielle des fonctions des membres.


2 commentaires

Mais encore une fois, vous ne pouvez pas spécialiser des modèles de fonction autonomes (ou du moins que vous ne pouviez pas au moment de ces opérateurs ont été ajoutés à la norme, mais peut-être en C ++ 98, ils n'étaient pas autonomes du tout? ). En fin de compte, vous pouvez les personnaliser aussi facilement (ou peut-être encore plus facilement) s'ils étaient des fonctions membres. Et par exemple L'élargissement et ce genre de choses sont les traits de caractère et les locaux spécialisés, pas besoin de spécialiser les opérateurs de flux, je pense.


En fait, ce n'est pas une spécialisation partielle, mais une surcharge, non? J'ai édité la réponse. Le problème similaire est discuté ici: gotw.ca/gotw/049.htm



0
votes

La raison de l'opérateur << Prise de charcuterie n'est pas une fonction de membre est qu'il existe déjà des fonctions définies dans OStream qui écrivent des caractères au flux.

 XXX  

Par conséquent, ces opérateurs sont fabriqués non Fonctions membres qui utilisent à l'interne ces deux fonctions.


0 commentaires

1
votes

Il y a en fait deux familles de surcharger opérateur <<< / code> s, comme vous l'avez découvert.

Une famille est l'élément surchargé ostream :: opérateur <<< / code> (qui obtient la référence ostream implicitement en tant que Ceci Pointeur) et le Une autre famille est la fonction gratuite surchargée <<< / code> qui obtient la référence ostream explicitement comme un argument.

Lorsque vous souhaitez ajouter une capacité de diffusion en continu à une classe de votre choix, vous ajoutez une fonction gratuite.


5 commentaires

D'accord, et y a-t-il une bonne raison pour laquelle les opérateurs de sortie de caractère, non signé, ..., Const non signé Char * sont déclarés à différents endroits?


@Rouki: une raison: suppose que vous avez une instance s d'une classe qui n'est pas un ostream , mais a un opérateur de conversion sur ostream . Si opérateur <<< / code> n'étaient qu'un membre de ostream puis s << 1 ne compilerait bien sûr pas. Cependant, avec la fonction libre, le compilateur peut voir qu'il existe une fonction pouvant correspondre si s était un ostream - et que savez-vous? Il y a un opérateur de conversion qu'il peut utiliser pour le faire! Vous trouverez de nombreux opérateurs définis comme des fonctions libres (par exemple, voir ici ) pour cette raison.


Les fonctions libres ne transmettent pas les fonctions des membres - notez qu'ils ont des types d'entrée différents. Le sous-classement n'est pas une raison pour cette différence, car une référence à dérivée peut être convertie en une référence à la base de toute façon. Je ne connais pas la raison même.


@Aschepler: True, j'avais à l'esprit le cas où il pourrait y avoir un comportement polymorphique. Corrigée. En ce qui concerne le sous-classement, je n'obtiens pas bien ce que vous parlez de? L'exemple ci-dessus n'a pas à faire avec le sous-classement.


@aschepler, je pense qu'il est lié à la spécialisation en fonction de la largeur de caractère cible - j'ai plus d'informations dans ma réponse