OVH Cloud OVH Cloud

[debutant] operator

30 réponses
Avatar
Bruno CAUSSE
Bonjour,

j'aimerai comprendre (dans le detail) cette declaration :

friend std::ostream& operator<<(std::ostream& stream, const maClass& a);

A) Est declaré dans maClass mais n'est pas une fonction membre de maClass.

B) Est declaré dans maClass avec le modificateur friend pour acceder a
chaques membres de maClass.

C) en ecrivant la declaration de cette facon, j'ai ajouté une nouvelle
declaration "de facon externe" de l'operator<< a la classe std::ostream?

Si cela est exacte comment cela fonctionne t'il?

Merci je patauge un peu.

Par la suite je souhaite declarer deux operateurs << (un pour ecrire
(binaire) dans un fichier, et l'autre pour ecrire (texte) dans la sortie
standard) est ce possible?

10 réponses

1 2 3
Avatar
Gabriel Dos Reis
"kanze" writes:

[...]

| > > Pendant la normalisation, cette injection a été supprimée, et à
| > > la place, on a dit que l'ADL régarde dans les classes
| > > impliquées. Je crois qu'on s'était bien rendu compte que le code
| > > qui appelait foo(), ci-dessus, ne marcherait plus, mais il faut
| > > avouer qu'une amie qui ne prend pas de paramètre apparenté à la
| > > classe n'a généralement pas de sens.
|
| > Je crois que l'intérêt principal de friend name injection, c'était
| > d'utiliser conjointement des classes templates. lorsque la classe
| > template était instanciée, les fonctions friend devenait alors
| > visible. On avait alors un contrôle de la visibilité de la fonction
| > friend, via l'instanciation -- même si celle-ci n'avait pas de
| > paramètres apparentés à la classe.
|
| Tu parles du trick de Barton-Nackman, je crois.

J'avais eu une discussion avec David il y a un certain temps à propos
de cela. Si mes souvenirs sont bons, j'ai compris que la règle
actuelle (que je considère bancale) a été taillée sur mesure pour
préserver le « Barton-Nackman trick » puisque le bouquin avait un
certain succès.
(Cela n'exclut pas que la règle puisse être dans d'autres cas).

[...]

| La solution à base de ADL permet aussi que le trick de
| Barton-Nackman fonctionne. Reste qu'il y a des cas où on a
| maintenant besoin d'une declaration en dehors de la classe, où
| qu'on n'en avait pas besoin avant. Du code (probablement pas
| beaucoup) qu'on a cassé, en somme.

Historiquement, l'ADL est une extension de la règle originelle connue
sous le nom de « Koenig lookup »

http://www.open-std.org/JTC1/SC22/WG21/docs/papers/1995/N0645.pdf

-- règle qui a été proposée indépendamment de template, et dont le but
était de résoudre l'utilisation des opérateurs -- proposée par John
Wilkinson, Jim Dehnert et Matt Austern.

http://www.open-std.org/JTC1/SC22/WG21/docs/papers/1996/N0906.pdf

L'ADL ne visait pas à résoudre le problème de « Barton-Nackman », mais
plutôt à appaiser la tension née et cristalisée par

http://www.open-std.org/JTC1/SC22/WG21/docs/papers/1995/N0640.pdf

et autres débats, après que le comité ait décidé (quelque mois plus
tôt) que le modèle de compilation des templates est le « modèle de
séparation » -- personne ne parlait d'« export » à l'époque, car par
défaut les templates étaient exportés !.

-- Gaby
Avatar
Bruno CAUSSE
dans l'article , kanze
à a écrit le 23/10/06 19:27 :

Piges pas :(

il faut que je derive un ostream qui implemente une nouvelle fonction

ostream& operator<<(maClass& a) ?


Non. L'abstraction de std::ostream, c'est un formattage texte,
et tu ne peux pas réelement t'en servir pour écrire dans un
fichier binaire. Il faut plutôt que tu développes un nouveau
type de flux, quelque chose, disons, du genre oxdrstream (avec
éventuellement des dérivées comme ofxdrstream). Et que tu le
dotes des operator<< qu'il faut pour formatter selon le format
voulu.


Un type derivé de ofstream suffit?


Avatar
Lahsen
dans l'article , kanze
à a écrit le 23/10/06 19:27 :

Piges pas :(
il faut que je derive un ostream qui implemente une nouvelle fonction
ostream& operator<<(maClass& a) ?
Non. L'abstraction de std::ostream, c'est un formattage texte,

et tu ne peux pas réelement t'en servir pour écrire dans un
fichier binaire. Il faut plutôt que tu développes un nouveau
type de flux, quelque chose, disons, du genre oxdrstream (avec
éventuellement des dérivées comme ofxdrstream). Et que tu le
dotes des operator<< qu'il faut pour formatter selon le format
voulu.


Un type derivé de ofstream suffit?



Pour utiliser un flux binaire il suffit de spécifier le openmodes
binaire comme suit:

fstream myStream(name, ios_base::binary);

Les openmodes sont définit dans la classe ios_base standard.



Avatar
kanze
Bruno CAUSSE wrote:
dans l'article , kan ze
à a écrit le 23/10/06 19:27 :

Piges pas :(

il faut que je derive un ostream qui implemente une nouvelle fonction

ostream& operator<<(maClass& a) ?


Non. L'abstraction de std::ostream, c'est un formattage texte,
et tu ne peux pas réelement t'en servir pour écrire dans un
fichier binaire. Il faut plutôt que tu développes un nouveau
type de flux, quelque chose, disons, du genre oxdrstream (avec
éventuellement des dérivées comme ofxdrstream). Et que tu le
dotes des operator<< qu'il faut pour formatter selon le format
voulu.


Un type derivé de ofstream suffit?


On pourrait, mais je n'en vois pas l'intérêt. Le problème de
base, c'est qu'on ne peut utiliser aucune des operator<< de
ostream, parce qu'eux, il font tous un formattage text (par
définition). Or, si on utilise un héritage public, il y a une
conversion implicite qui risque de nous faire faire la mauvaise
chose -- si j'oublie de fournir un operator<< pour un type
donné, le code compile, mais les sorties sont en text ; pire,
si j'écris quelque chose du genre « dest << monObj << unInt »,
en ayant oublié la declaration de l'operator<< binaire pour le
type de monObj, l'entier qui lui suit serait aussi formatté en
text, parce que l'operator<<( ostream&, MaClasse const& )
renvoie certainement un std::ostream&, et non une référence à la
classe dérivée.

On pourrait bien utiliser l'héritage privé, en revanche, et sans
risque. Seulement, pourquoi, si je ne veux pas le fonctionnement
de ostream. Moi, j'hériterais bien de std::ios, pour avoir une
gestion des streambuf et des erreurs à peu près standard, mais
c'est tout. De même, j'utiliserais bien des streambuf pour
l'écriture et la lecture des octets finaux (en ayant pris soin
de l'imbuer du locale "C"). Il faudrait évidemment alors que je
réimplémente tous les operator<< du ostream, mais en fait, c'est
ce que je veux. Si j'écris en format XDR, par exemple, aucun
operator<< existant va faire ce que je veux. Et que s'il m'en
manque un pour le format binaire, je préfère le savoir tout de
suite, avec une erreur de compilation, et non m'en apercevoir
seulement parce que le programme avec qui je communique ne
comprend pas les données que je lui envoie.

--
James Kanze (GABI Software) email:
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34



Avatar
kanze
Lahsen wrote:
dans l'article
, kanze
à a écrit le 23/10/06 19:27 :

Piges pas :(
il faut que je derive un ostream qui implemente une nouvelle fonction
ostream& operator<<(maClass& a) ?
Non. L'abstraction de std::ostream, c'est un formattage texte,

et tu ne peux pas réelement t'en servir pour écrire dans un
fichier binaire. Il faut plutôt que tu développes un nouveau
type de flux, quelque chose, disons, du genre oxdrstream (avec
éventuellement des dérivées comme ofxdrstream). Et que tu le
dotes des operator<< qu'il faut pour formatter selon le format
voulu.


Un type derivé de ofstream suffit?


Pour utiliser un flux binaire il suffit de spécifier le openmodes
binaire comme suit:

fstream myStream(name, ios_base::binary);


Pas du tout. Les openmode conditionnent la mode de l'ouverture
du fichier, auprès du système d'exploitation. Dans le cas d'un
système Unix, std::binary n'a aucun effet, parce que Unix ne
distingue pas de modes d'ouverture, et dans le cas de Windows,
il ne joue que sur la représentation des fins de lignes et la
fin du fichier, les conventions des fichiers text sous Windows
n'étant pas compatibles avec celles de C++. Il n'a aucun effet,
en revanche, sur le formattage, ni sur le transcodage, qui
dépend du locale.

--
James Kanze (GABI Software) email:
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34




Avatar
fabien.chene
Gabriel Dos Reis writes:

"kanze" writes:

[...]

| > > Pendant la normalisation, cette injection a été supprimée, et à
| > > la place, on a dit que l'ADL régarde dans les classes
| > > impliquées. Je crois qu'on s'était bien rendu compte que le code
| > > qui appelait foo(), ci-dessus, ne marcherait plus, mais il faut
| > > avouer qu'une amie qui ne prend pas de paramètre apparenté à la
| > > classe n'a généralement pas de sens.
|
| > Je crois que l'intérêt principal de friend name injection, c'était
| > d'utiliser conjointement des classes templates. lorsque la classe
| > template était instanciée, les fonctions friend devenait alors
| > visible. On avait alors un contrôle de la visibilité de la fonction
| > friend, via l'instanciation -- même si celle-ci n'avait pas de
| > paramètres apparentés à la classe.
|
| Tu parles du trick de Barton-Nackman, je crois.

J'avais eu une discussion avec David il y a un certain temps à propos
de cela. Si mes souvenirs sont bons, j'ai compris que la règle
actuelle (que je considère bancale) a été taillée sur mesure pour
préserver le « Barton-Nackman trick » puisque le bouquin avait un
certain succès.


Comme indiqué par Daveed Vandevoorde dans son livre, le problème a été
traité par Bill Gibbons:

http://www.open-std.org/jtc1/sc22/wg21/docs/papers/1996/N0878.pdf
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/1996/N0968.pdf


--
Fab

Avatar
Gabriel Dos Reis
(Fabien Chêne) writes:

| Gabriel Dos Reis writes:
|
| > "kanze" writes:
| >
| > [...]
| >
| > | > > Pendant la normalisation, cette injection a été supprimée, et à
| > | > > la place, on a dit que l'ADL régarde dans les classes
| > | > > impliquées. Je crois qu'on s'était bien rendu compte que le code
| > | > > qui appelait foo(), ci-dessus, ne marcherait plus, mais il faut
| > | > > avouer qu'une amie qui ne prend pas de paramètre apparenté à la
| > | > > classe n'a généralement pas de sens.
| > |
| > | > Je crois que l'intérêt principal de friend name injection, c'était
| > | > d'utiliser conjointement des classes templates. lorsque la classe
| > | > template était instanciée, les fonctions friend devenait alors
| > | > visible. On avait alors un contrôle de la visibilité de la fonction
| > | > friend, via l'instanciation -- même si celle-ci n'avait pas de
| > | > paramètres apparentés à la classe.
| > |
| > | Tu parles du trick de Barton-Nackman, je crois.
| >
| > J'avais eu une discussion avec David il y a un certain temps à propos
| > de cela. Si mes souvenirs sont bons, j'ai compris que la règle
| > actuelle (que je considère bancale) a été taillée sur mesure pour
| > préserver le « Barton-Nackman trick » puisque le bouquin avait un
| > certain succès.
|
| Comme indiqué par Daveed Vandevoorde dans son livre, le problème a été
| traité par Bill Gibbons:
|
| http://www.open-std.org/jtc1/sc22/wg21/docs/papers/1996/N0878.pdf

Note que ce papier motive le changement pour que le
« Barton-Nackman trick » puisse marcher.

BTW, pusique nous sommes sur un groupe francophone, tu peux écrire
« David » (vraie orthographe) sans avoir peur qu'il soit prononcé
incorrectement. Il écrit « Daveed » pour forcer la bonne
prononciation.

-- Gaby
Avatar
fabien.chene
Gabriel Dos Reis writes:

(Fabien Chêne) writes:

| Gabriel Dos Reis writes:
|
| > "kanze" writes:
| >
| > [...]
| >
| > | > > Pendant la normalisation, cette injection a été supprimée, et à
| > | > > la place, on a dit que l'ADL régarde dans les classes
| > | > > impliquées. Je crois qu'on s'était bien rendu compte que le code
| > | > > qui appelait foo(), ci-dessus, ne marcherait plus, mais il faut
| > | > > avouer qu'une amie qui ne prend pas de paramètre apparenté à la
| > | > > classe n'a généralement pas de sens.
| > |
| > | > Je crois que l'intérêt principal de friend name injection, c'était
| > | > d'utiliser conjointement des classes templates. lorsque la classe
| > | > template était instanciée, les fonctions friend devenait alors
| > | > visible. On avait alors un contrôle de la visibilité de la fonction
| > | > friend, via l'instanciation -- même si celle-ci n'avait pas de
| > | > paramètres apparentés à la classe.
| > |
| > | Tu parles du trick de Barton-Nackman, je crois.
| >
| > J'avais eu une discussion avec David il y a un certain temps à propos
| > de cela. Si mes souvenirs sont bons, j'ai compris que la règle
| > actuelle (que je considère bancale) a été taillée sur mesure pour
| > préserver le « Barton-Nackman trick » puisque le bouquin avait un
| > certain succès.
|
| Comme indiqué par Daveed Vandevoorde dans son livre, le problème a été
| traité par Bill Gibbons:
|
| http://www.open-std.org/jtc1/sc22/wg21/docs/papers/1996/N0878.pdf

Note que ce papier motive le changement pour que le
« Barton-Nackman trick » puisse marcher.


Oui exactement.

BTW, pusique nous sommes sur un groupe francophone, tu peux écrire
« David » (vraie orthographe) sans avoir peur qu'il soit prononcé
incorrectement. Il écrit « Daveed » pour forcer la bonne
prononciation.


C'est noté :-)


--
Fab

Avatar
fabien.chene
"kanze" writes:

[...]
Je crois que l'intérêt principal de friend name injection, c'était
d'utiliser conjointement des classes templates. lorsque la classe
template était instanciée, les fonctions friend devenait alors
visible. On avait alors un contrôle de la visibilité de la fonction
friend, via l'instanciation -- même si celle-ci n'avait pas de
paramètres apparentés à la classe.


Tu parles du trick de Barton-Nackman, je crois.


Oui.

L'injection du nom de l'ami a existé bien avant les templates. Elle
n'est en général pas nécessaire, dans le sens qu'on peut toujours
fournir une declaration dans la bonne portée, en plus de la
declaration de friend. Ce n'est qu'une commodité, rien de plus. Sauf
dans le cas d'un template où tu définis la fonction amie directement
dans la classe ; tu as alors une fonction (non template) par
instantiation de la classe (template), chose qu'on ne peut
difficilement faire autrement.


Puisque je fouille dans les archives, j'ai trouvé ce papier
intéressant, qui montre pourquoi l'injection de nom friend est
problématique:
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/1995/N0777.pdf

Et surtout, étant donné l'aspect ouvert de l'ensemble de ces
fonctions, on ne peut pas les définir (ni declarer) ailleurs.


En effet.

--
Fab


Avatar
Gabriel Dos Reis
(Fabien Chêne) writes:

[...]

| Puisque je fouille dans les archives, j'ai trouvé ce papier
| intéressant, qui montre pourquoi l'injection de nom friend est
| problématique:
| http://www.open-std.org/jtc1/sc22/wg21/docs/papers/1995/N0777.pdf


« surprisingly inventive ways » est un euphémisme qui résume à lui
tout seul, le reste du document et l'appréciation de l'auteur :-).

-- Gaby
1 2 3