47 votes

Pourquoi une classe d'amis C ++ a-t-elle besoin d'une déclaration forward uniquement dans d'autres espaces de noms?

Supposons que j'ai une classe F qui devrait être un ami pour les classes G (dans l'espace de noms global) et C (dans l'espace de noms A).

  • pour être ami de A::C, F doit être déclaré avant.
  • pour être ami de G, pas de déclaration anticipée d' F est nécessaire.
  • de même, une classe A::BF peut être l'ami d' A::C sans déclaration anticipée

Le code suivant illustre et compile avec GCC 4.5, VC++ 10 et au moins avec un autre compilateur.

class G {
    friend class F;
    int g;
};

// without this forward declaration, F can't be friend to A::C
class F;

namespace A {

class C {
    friend class ::F;
    friend class BF;
    int c;
};

class BF {
public:
    BF() { c.c = 2; }
private:
    C c;
};

} // namespace A

class F {
public:
    F() { g.g = 3; c.c = 2; }
private:
    G g;
    A::C c;
};

int main()
{
    F f;
}

Cela me semble incohérent. Est-il une raison à cela ou est-ce juste une décision de conception de la norme?

45voto

Alexey Malistov Points 13526

C++ Standard ISO/IEC 14882:2003(E)

7.3.1.2 de l'espace de Noms des définitions de membre

Le paragraphe 3 de l'

Tout d'abord le nom déclaré dans un espace de noms est un membre de cette espace de noms. Si un ami dans la déclaration de un non-local de classe déclare d'abord un classe ou d'une fonction (ce qui implique que le nom de la classe ou d'une fonction est non qualifiés) l'ami de classe ou de la fonction est un membre de la enfermer les plus secrets de l'espace de noms.

// Assume f and g have not yet been defined.
void h(int);
template <class T> void f2(T);
namespace A {
   class X {
   friend void f(X);  //  A::f(X) is a friend
      class Y {
         friend void g();  //  A::g is a friend
         friend void h(int);  //  A::h is a friend
         //  ::h not considered
         friend void f2<>(int);  //  ::f2<>(int) is a friend
      };
   };
   //  A::f, A::g and A::h are not visible here
   X x;
   void g() { f(x); }  // definition of A::g
   void f(X) { /* ... */}  // definition of A::f
   void h(int) { /* ... */ }  // definition of A::h
   //  A::f, A::g and A::h are visible here and known to be friends
}

Votre friend class BF; est une déclaration d' A::BF en l'espace de noms plutôt que l'espace de noms global. Vous avez besoin de la mondial de déclaration préalable pour éviter cette nouvelle déclaration.

6voto

tomekpe Points 31

Prenons en compte ces 3 lignes de code à partir de votre échantillon:

1. friend class F; // it creates "friend declaration", (that's not the same as ordinary forward declaration

2. class F; // without this forward declaration, F can't be friend to A::C <-- this is ordinary forward declaration

3. friend class ::F; // this is qualified lookup (because of ::), so it needs previous declaration, which you provide in line 2.

C++ standard dans le paragraphe 7.3.1.2, point 3 ( espace de Noms des définitions de membre) dit:

L'ami de la déclaration n'est pas par lui-même au nom visible non qualifiés de recherche (3.4.1) ou un professionnel de la recherche (3.4.3). [ Note: L' nom de l'ami sera visible dans son espace de noms si un correspondant la déclaration est prévue à l'espace de noms de champ d'application (que ce soit avant ou après la définition de la classe de l'octroi de l'amitié). -la note de fin ]

Et la ligne 2 suit exactement ce que la norme ne l'exige.

De toute confusion est parce que "l'ami de la déclaration" est faible, vous devez fournir une déclaration anticipée pour une autre utilisation.

2voto

Billy ONeal Points 50631

Parce que cela n'aurait aucun sens de pouvoir déclarer quelque chose dans l'espace de noms global si vous êtes dans un bloc namespace {} . La raison pour laquelle friend class BF; fonctionne est que cela se comporte comme une déclaration aval implicite.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X