Twitter iPhone pliant OnePlus 11 PS5 Disney+ Orange Livebox Windows 11

friend, operateur et namespace

5 réponses
Avatar
Nico R
bonjour à tous
je me suis bien pris la tête sur un truc l'autre jour, alors pour que
les choses soient plus claires dans ma tête je vous l'expose dans
l'espoir que l'un d'entre vous m'éclaire

j'ai une classe définie dans un namespace
et je veux surcharger l'operateur >> de istream
la classe comportant des membres prives je suis obligé de déclarer
operator>> comme fonction amie.
voici le code correspondant

namespace Espace{
class Foo{

friend istream& operator>>(istream&, Foo&);

public:
int getA();
private:
int a;

};
}

et dans le cpp correspondant:

int Espace::Foo::getA()
{
return a;
}


istream& operator>>(istream& is, Espace::Foo& f)//compile pas
//istream& Espace::operator>>(istream& is, Espace::Foo& f)//compile
{
is>> f.a;
return is;
}


et là ça ne compile pas avec la premiere ligne, pour un acces à un
membre privé de Foo
si je met la deuxieme ligne pas de souci

donc ma question c'est pourquoi?
je présume que la déclaration friend revient plus ou moins à un extern,
mais pourquoi l'ajoute t'il dans le namespace Espace?
Y a t'il un moyen de l'éviter?
(c'est compilé avec MSVC7 si ça a une importance)

Nicolas

5 réponses

Avatar
Falk Tannhäuser
Nico R wrote:

namespace Espace{
class Foo{

friend istream& operator>>(istream&, Foo&);

public:
int getA();
private:
int a;

};
}

et dans le cpp correspondant:


J'aurais écrit
namespace Espace
{
int Foo::getA() { return a; }
std::istream& operator>>(std::istream& is, Foo& f) { return is >> f.a; }
}
mais ça revient au même - l'opérateur>> en question se retrouve dans le
namespace Espace. Cela ne pose AMA aucun problème - si tu fais

int main()
{
Espace::Foo f;
std::cin >> f;
...

une règle dans la Norme ("Argument-dependent name lookup" ou "Koenig lookup",
cf. § 3.4.2) oblige le compilateur à chercher l'opérateur>> dans les namespaces
std et Espace, donc il sera trouvé dans ce dernier.


je présume que la déclaration friend revient plus ou moins à un extern,
mais pourquoi l'ajoute t'il dans le namespace Espace?
Y a t'il un moyen de l'éviter?


Je ne vois pas trop pourquoi l'éviter, mais c'est possible :

namespace Espace { class Foo; } // Déclaration sans définition de Foo
std::istream& operator>>(std::istream&, Espace::Foo&);
// Déclaration de l'opérateur>> dans le namespace global

namespace Espace
{
class Foo
{
friend std::istream& ::operator>>(std::istream&, Foo&);
// Noter le :: ^^ !
...

puis on définit cet opérateur dans le .C au niveau du namespace global...

Falk

Avatar
Nico R

J'aurais écrit
namespace Espace
{
int Foo::getA() { return a; }
std::istream& operator>>(std::istream& is, Foo& f) { return is >>
f.a; }
}
mais ça revient au même


merci pour ta reponse
l'assesseur n'était pas inline parce que j'en ai juste mis un dans mon
exemple pour qu'il y ait une fonction membre. par contre l'operateur
inline comme ça ça marche? parce que là en fait tu le déclares comme
une fonction membre du coup ce n'est pas vraiment une surcharge de
std::operator>>, i.e. je ne suis pas sur que je puisse l'appeler comme ça:

Espace::Foo f;
cin>>f;

par contre avec un friend devant ça marche, mais je trouve ça super
crade. enfin c'est mes automatismes de développeurs Java, je suis pas
super habitué à la surcharge d'operateurs...

une règle dans la Norme ("Argument-dependent name lookup" ou "Koenig
lookup",
cf. § 3.4.2) oblige le compilateur à chercher l'opérateur>> dans les
namespaces
std et Espace, donc il sera trouvé dans ce dernier.

faudrait que je lise cette norme. C'est abordable?

C'est dans le Stroustrup ou c'est autre chose?
merci pour ta réponse

Avatar
Falk Tannhäuser
Nico R wrote:


J'aurais écrit



Le code qui suit était censé se trouver dans le fichier Foo.cpp .
Bien sûr, au début il manquait un
#include "Foo.H"
où le fichier Foo.H contient la définition de la classe Foo dans
le namespace Espace, avec les déclarations (sans définition) de
la fonction membre getA() et de la fonction "friend" operator>>() .

namespace Espace
{
int Foo::getA() { return a; }
std::istream& operator>>(std::istream& is, Foo& f) { return is >>
f.a; }
}
mais ça revient au même



merci pour ta reponse
l'assesseur n'était pas inline parce que j'en ai juste mis un dans mon
exemple pour qu'il y ait une fonction membre. par contre l'operateur
inline comme ça ça marche? parce que là en fait tu le déclares comme
une fonction membre du coup ce n'est pas vraiment une surcharge de
std::operator>>, i.e. je ne suis pas sur que je puisse l'appeler comme ça:

Espace::Foo f;
cin>>f;


Non, ces 2 fonctions ne sont pas inline - elles sont définies
en dehors de la classe Foo (et l'opérateur>> n'est même pas membre
de la classe Foo), mais à l'intérieur du namespace Espace, au niveau
du fichier Foo.cpp . Mon but était illustrer qu'on peut simplement
rouvrir le namespace dans le fichier .cpp d'implémentation, ce qui
simplifie légèrement l'écriture car on n'est pas obligé de mettre
Espace:: partout devant les noms.

faudrait que je lise cette norme. C'est abordable?
C'est dans le Stroustrup ou c'est autre chose?
merci pour ta réponse


Le "Koenig lookup" devrait être expliqué un peu partout où on
introduit les namespaces - regarde sur Google... En gros, cela
veut dire que le nom d'une fonction (y compris un opérateur)
n'est pas seulement recherché dans le(s) namespaces "actives"
à l'endroit où se trouve l'appel (non qualifié par "NomDUnNamespace::")
de cette fonction (opérateur) mais aussi dans le(s) namespace(s)
de l'/des argument(s) de cet appel.

Falk


Avatar
Nico R

Non, ces 2 fonctions ne sont pas inline - elles sont définies
en dehors de la classe Foo (et l'opérateur>> n'est même pas membre
de la classe Foo), mais à l'intérieur du namespace Espace, au niveau
du fichier Foo.cpp . Mon but était illustrer qu'on peut simplement
rouvrir le namespace dans le fichier .cpp d'implémentation, ce qui
simplifie légèrement l'écriture car on n'est pas obligé de mettre
Espace:: partout devant les noms.


autant pour moi, j'ai répondu vite et même pas pris le temps de bien
lire. merci pour la réponse en tout cas, j'y vois plus clair

amicalement

Nicolas

Avatar
Loïc Joly
Nico R wrote:


une règle dans la Norme ("Argument-dependent name lookup" ou "Koenig
lookup",
cf. § 3.4.2) oblige le compilateur à chercher l'opérateur>> dans les
namespaces
std et Espace, donc il sera trouvé dans ce dernier.

faudrait que je lise cette norme. C'est abordable?



Abordable au sens monétaire, oui (une vingtaine de $)
Abordable au sens intellectuel, pourquoi pas pour un esprit tordu, mais
on a fait plus palpitant comme récit...

C'est dans le Stroustrup ou c'est autre chose?
merci pour ta réponse


Le Stroustrup n'est pas la norme. Mais il en reprend un certain nobre de
points.

--
Loïc