Y a-t-il un moyen de surcharger l'opérateur <<, en tant que membre de la classe, à imprimer des valeurs sous forme de flux de texte. Tels que: Le seul moyen de penser était de surcharger l'opérateur en dehors de la classe: p> mais alors le seul moyen d'accéder aux parties privées de l'objet seraient à l'ami de la fonction de l'opérateur et je préfère éviter les amis si possible et vous vous demandez donc des solutions alternatives. P> Toute commentaires ou recommandations sur la procédure à suivre être utile :) p> p>
6 Réponses :
Vous pouvez le rendre membre de la classe, à gauche de Ce que vous pouvez faire, cependant, a une classe de base avec <<< / code>, qui est
ostream code> dans votre cas. p>
void do_stream (ostream & o); code> membre de tous vos streamables et non membre
opérateur <<< / code> que l'appellerait. p>
Je ne. Je déclare simplement le fait que si on veut qu'il s'agisse d'un membre de classe, la classe devrait être std :: Ostream code>. Ce qui signifie fondamentalement non, vous ne voulez pas que ce soit un membre de classe.
Vous avez trébuché sur le moyen canonique de mettre en œuvre cette fonctionnalité. Ce que vous avez est correct. P>
Ce n'est pas correct car il ne compilera pas. Dans la configuration de la question, il faudrait écrire quelque chose laide comme obj << cout; code>.
Vous avez raison, c'est le seul moyen de mettre en œuvre l'opérateur du flux - en dehors de la classe. P>
Vous devez déclarer la méthode comme C'est comme ça que c'est fait. P> ami code>. p>
Il n'est généralement pas nécessaire de déclarer la fonction sous forme de ami code>; Tout ce que vous sortiez fait partie de l'interface publique de la classe. (Il est souvent approprié de le déclarer comme ami dans un modèle, afin d'utiliser le tour de Barton et de Nackman, mais c'est un problème différent.)
C'est sérieusement pas i> le seul moyen de la mettre en œuvre. J'ai vu et mis en œuvre la plupart des opérateurs de flux sans les lier comme ami code>. Seulement été nécessaire,
ami code> devrait être utilisé.
@phresnel j'ai tendance à utiliser beaucoup la méthode code> imprimer code> avec des modèles de classe. Ne pas avoir accès, mais pour pouvoir définir la fonction dans la classe.
Dans son cas, le député est privé, alors l'amitié est requise. C'est beaucoup plus simple que d'ajouter des getters juste pour être utilisés par le flux.
Il doit être un non-membre, car la classe forme le deuxième argument de l'opérateur, pas le premier. Si la sortie peut être effectuée en utilisant uniquement l'interface publique, vous avez terminé. Si cela a besoin d'accès aux membres non publics, vous devrez alors vous le déclarer un ami; C'est ce que font les amis.
class TestClass { public: friend ostream& operator<<(ostream& os, TestClass const & tc) { return os << "I'm a friend of the class, msg=" << tc.msg << endl; } private: string msg; };
Merci, cette solution fonctionne également pour la production d'autres opérateurs surchargés. Pour par exemple, cout << (S1 + S2) code> n'a pas fonctionné lors de l'utilisation d'autres méthodes. Une raison pour laquelle cela pourrait se produire?
Pour une réponse plus exhaustive autour de cette question, voir Réponse acceptée dans
Je crois qu'une façon populaire de faire ceci est un opérateur non membre et sans ami qui appelle une méthode d'impression
imprimée code> non virtuelle dans votre classe . Cette méthode d'impression peut soit faire le travail, soit déléguer à une implémentation virtuelle protégée.
class TestClass {
public:
ostream& print(ostream& os) const {
return os << "I'm in the class, msg=" << msg << endl;
}
private:
string msg;
};
ostream& operator<<(ostream& os, TestClass& obj) {
return obj.print(os);
}
int main(int argc, char** argv) {
TestClass obj;
cout << obj;
return 0;
}
Je soutiens cette solution ci-dessus en utilisant une déclaration d'ami. Il maintient l'encapsulation et obtient le travail.
@broc je ne vois aucune différence réelle dans l'encapsulation. Dans un cas, l'auteur de la classe donne explicitement des droits d'accès à une seule instance d'opérateur << () code>; Dans cette méthode, il donne explicitement des droits d'accès à une fonction nommée
impression () code>. Où est la différence? (Il peut y avoir d'autres raisons d'utiliser la méthode
impression () code>, mais plus ou moins encapsulation n'est pas l'une d'entre elles.)
@Jameskanze, vous pourriez faire valoir que déclarer un public membre n'est que l'auteur donnant des droits d'accès à tout le monde explicitement et qu'il ne casse pas l'encapsulation. Que vous achetiez cela ou non dépend de l'endroit où vous dessinez la ligne. Personnellement, je pense que la ligne doit être tirée autant que possible dans la direction opposée; Avoir la méthode d'impression vous permet de distribuer la classe dans une .dll, distribue-la sans source et permet toujours à l'utilisateur de la bibliothèque d'écrire leur opérateur surchargé << pour leur commodité. Pouvez-vous obtenir plus encapsulé? De la perspective ...
@Jameskanze de juste la langue que je ne peux pas être en désaccord avec vous, cependant, la langue est utilisée pour créer une exécutable ou une bibliothèque et je pense que, dans le but de développer professionnellement, le concept d'encapsulation doit atteindre plus loin que de penser à des conditions de la langue.
@broc déclarant une encapsulation de déposition du public membre, car elle fait partie de l'interface publique de l'interface publique. Déclarer une fonction ami code> fait partie de cette fonction de l'interface publique de la classe "; En faisant une partie de la fonction de l'interface, plutôt que des données, vous augmentez en réalité l'encapsulation. Trop de fonctions (ou des fonctions mal conçues, telles que les getters et les setters) affaiblir l'encapsulation également, mais à cet égard, que la fonction soit un ami ou un membre est hors de propos.
Vous devez en faire un non membre (comme le premier paramètre n'est pas votre classe).
Mais vous pouvez l'écrire dans votre définition de classe (en tant qu'ami): P>
class TestClass { public: // Have a nice friend. // This tightly binds this operator to the class. // But that is not a problem as in reality it is already tightly bound. friend ostream& operator<<(ostream& os, TestClass const& data) { return os << "I'm in the class, msg=" << data.msg << endl; } private: string msg; };
Les amis ne sont-ils pas censés résoudre ce problème même? Pourquoi voudriez-vous les éviter?
Le
<<< / code> doit être non membre, mais cela peut être un ami.
Les amis sont de répondre aux questions et ne résolvent pas de problèmes!
ami code> s sont vos amis. Pourquoi voulez-vous les éviter?
Je recommande de lire drdobbs.com/184401197 et Parasht.com/c ++ - FAQ-Lite / Friends.html # FAQ-14.2 .
ami code> s fait partie de l'encapsulation de la classe; Ils sont juste appelés à utiliser une syntaxe différente. Il n'y a rien de mal avec
ami code> S, et aucune raison réelle de les éviter.
@Jameskanze: Si vous peut I> éviter les informations sans perdre de performances pertinentes, vous devriez alors le faire, afin de réduire le couplage. C'est-à-dire que si vous pouvez mettre en œuvre des parties de l'interface sans accès privé / protégé et sans sacrifier trop, vous devriez. D'autre part, si ce n'est pas un
ami code> signifie que vous devez modifier l'interface, alors c'est un sacrifice assez gros et le
code> est le moindre mal.
Il n'y a rien de mal à déclarer des amis: programmeurs.stackexchange.com/a/99595/12917
@phresnel: une fonction qui sérialise une classe est intrinsèquement étroitement couplée à ce cours de classe informatique. Étant donné que le streaming est intrinsèquement déjà étroitement couplé, la fabrication d'un ami n'augmente pas le couplage, mais plutôt documente le couplage b>. L'alternative consiste à rendre l'opérateur << appeler une méthode d'impression (cela peut sembler diminuer le couplage, mais lie plutôt le couplage à une méthode différente afin que vous n'ayez pas diminué de couplage, il suffit de le déplacer).
@phresnel je pense que c'est un bon résumé. L'idée clé est que
ami code> est bon quand il augmente l'encapsulation, mauvaise quand elle diminue.
@Lokiastari Jamais moins, il y a souvent de bonnes raisons d'aller avec la méthode
impression code>. (Le plus évident est que cela peut être polymorphe.)
@Jameskanze: Pas de désaccord là-bas. Mais quand j'utilise l'impression, je suis souvent (pas toujours) imprimer privé. Dans ce cas, l'opérateur de flux est toujours un ami (cette façon de documenter que l'interface étendue).
@Lokiastari: Je ne dirais pas que le streaming est intrinsèquement couplé à la classe. Prenons par exemple des conteneurs: ils peuvent être diffusés simplement en itérant sur eux et en diffusant chaque élément successivement. Pas besoin de connaître les internes.
@LucTouraille: Grand contre-exemple. Mais je considérerais des conteneurs une classe distincte (surtout car ils n'ont pas leurs propres opérateurs de flux).
@James Kanze: bon résumé là-bas, exactement mon point. Ma conversation-fu est faible aujourd'hui. Je ne suis pas sûr de la série de sérialisation, cependant. L'intention d'Ostream est-elle vraiment la sérialisation complète ou la production conviviale? Types flottants E.G. ne sont pas triviaux pour sérialiser en utilisant des nombres décimaux, de même que la valeur par défaut avec OStream. Je penserais donc intuitivement que Onetream est plus pour l'interaction de l'utilisateur chic, que pour la persistance.
@phresnel: vous pouvez sérialiser un float exactement comme chaîne de format hexagonal utilisant: (C ++ 03 Stream << STD :: Fixe << STD :: Scientifique << Floatvalue (cassé G ++)) (C ++ 11 Stream <
@phresnel Le
iOSTream code> L'abstraction est une entrée et une sortie textuelles, pas la sérialisation binaire. Pour d'autres formats, vous devez généralement rouler votre propre (ou peut-être trouver quelque chose existant sur le net).
@Lokiastari Quelque chose ne semble pas mal là-bas: dans
Stream << std :: fixe << std :: scientifique code>, le manipulateur
std :: scientifique code> annule tout effet du
std :: fixe code>; Vous produisez toutes les valeurs de points flottants en tant que scientifique. En ce qui concerne la sérialisation, vous pouvez utiliser le format de texte, à condition que vous utilisiez suffisamment de chiffres (qui dépend du format de point flottant --- 17 suffisent pour l'IEEE Double).
@James KANZE: C'était mon point de vue, que les opérateurs de streaming n'ont généralement besoin que de la vue extérieure, pour une interface utilisateur, mais pas les informations intérieures nécessaires à la persistance.
@Lokiastari: Ouais, mais le comportement par défaut est de fournir une interface utilisateur, pas la sérialisation / la persistance.
@phresnel: Dites-vous que
{std :: destream s ("plop"); Plop << MyObject; } {std :: ifstream s ("plop"); s >> mysecondObject;} code> ne sauvegardera pas et restaurera votre objet. Ensuite, je dirais que votre objet n'est pas bien conçu. Je m'attendrais à ce que vos opérateurs d'entrée et de sortie soient symétriques pour toute classe que vous définissez.
@Jameskanze: voir tableau X: conversions de point flottant:
iOS_Base :: fixe | iOS_Base :: Conversion scientifique% A code> (numéro de table varie selon la norme, mais il devrait être sous [facet.num.uput.virtuals])
@Lokiastari qui n'est pas présent dans C ++ 03, vous auriez donc besoin d'un compilateur très récent pour que cela fonctionne. Plus au point, votre code n'a pas défini
floatfield code> sur
ios_base :: fixe | ios_base :: scientifique code>; Il définit
floatfield code> sur
ios_base :: scientifique code>.
std :: scientifique code> utilise le formulaire de deux arguments de
iOS_base :: SETF code> (et qui n'a pas changé en C ++ 11).
@Lokiastari: pas faux ce que vous dites. Cependant, compte tenu de la manière dont les iOSTreams ne sont pas sérialisés correctement par défaut et de la difficulté à définir la désérialisation performante pour des types complexes (pensez à Pixar et à Disney ici), ainsi que de la production lisible à la lecture humaine (Seuls non redondants), combinés dans Un opérateur
<< / >> code> combinaison, je voudrais personnellement i> ne pas envisager iOSTreams pour une sérialisation à plus grande échelle. Les utilisateurs de ma classe 3D-QUADTREE peuvent être intéressés par des paramètres de la profondeur, mais issus de la fonction
f (x, z) -> y code>. Je pense que les iostreams manquent vraiment d'une définition précise de leur utilisation.
@phresnel: Je laisserai les gars à booster l'équipe de sérialisation.
@Lokiastari: Je pense que nous parlions des iostreams?
@phresnel: Où pensez-vous stimuler sérialiser des données sérialisées en réalité?
@Lokiastari: Cela dépend. La valeur par défaut est les opérateurs de diffusion en streaming, mais pour des types plus complexes, vous écrivez votre propre fonction de sérialisation / s qui utilisez-la à son tour ceux-ci. Boost :: Sériatalisation (ainsi qu'un cadre de sérialisation que j'ai développé) utilise iostreams, mais ce n'est pas une spécialisation de celle-ci. J'ai jeté un coup d'œil dans la norme et je n'ai pas pu trouver une référence non plus, sauf entrée / sortie, qui est un terme très multiple.
@phresnel: il utilise un flux B>. Et la bibliothèque B>> la bibliothèque de flux B>>
@Lokiastari: a) Nous n'avons pas eu de définition claire de flux i>, b) si elle découvre par exemple par ex. Une fonction de membre code> Serialize code>, appelée, puis il est votre i> Tourner pour dire boost :: Serialization Les fragments de données soient sérialisées. Ce processus est récursif. Quant à A) et B): Je ne suis pas sûr de ce que vous voulez me dire. J'utilise mon clavier et nous devons faire les uns avec les autres, mais je ne suis pas mon clavier et mon clavier n'est pas moi.
@phresnel: J'aime votre tentative futile d'obscurcissement. Mais j'envisage de la conversation comme vous n'avez rien dit d'aucune utilité.
@Loki Astari: Je commence à perdre une trace de votre structure de discussion. Standard dit: E / S. Amende. Mais les E / S peuvent être des E / S pour des raisons d'interaction utilisateur, ou des E / S pour des raisons de persistance. Pas bien: manque de définition précise que les E / S sont préférées en C ++. Se résume à: pas clair si les opérateurs de streaming ont besoin d'une perspicacité complète ou non. Contre-exemple: Opérateur
Non-ami <<< / Code> Peut fonctionner correctement pour les conteneurs pour l'utilisateur introspection-par-utilisateur. Maintenant: expliquez pourquoi Boost-Serialization prend en charge votre définition de la sérialisation iOSTREAMS. ... J'aime ta tentative futile de cacher la discussion originale ... et que l'obfuscation?