Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does a C++ friend class need a forward declaration only in other namespaces?

Suppose I have a class F that should be friend to the classes G (in the global namespace) and C (in namespace A).

  • to be friend to A::C, F must be forward declared.
  • to be friend to G, no forward declaration of F is necessary.
  • likewise, a class A::BF can be friend to A::C without forward declaration

The following code illustrates this and compiles with GCC 4.5, VC++ 10 and at least with one other compiler.

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; } 

To me this seems inconsistent. Is there a reason for this or is it just a design decision of the standard?

like image 986
pesche Avatar asked Dec 20 '10 17:12

pesche


People also ask

Why does C need forward declaration?

In some object-oriented languages like C++ and Objective-C, it is sometimes necessary to forward-declare classes. This is done in situations when it is necessary to know that the name of the class is a type, but where it is unnecessary to know the structure.

What is forward declaration of a class and why is it often essential when using friend functions?

Forward Declaration refers to the beforehand declaration of the syntax or signature of an identifier, variable, function, class, etc. prior to its usage (done later in the program). In C++, Forward declarations are usually used for Classes.

What is the use of declaring a class as a friend of another?

You can use the friend keyword to any class to declare it as a friend class. This keyword enables any class to access private and protected members of other classes and functions.

What is forward declaration in Objective C?

Forward declarations are mainly to avoid circular imports, where one file imports another file which imports the first file etc. Basically when you import a file, contents of the file are substituted at the point of import when you build your project, which is then fed to the compiler.


2 Answers

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

7.3.1.2 Namespace member definitions

Paragraph 3

Every name first declared in a namespace is a member of that namespace. If a friend declaration in a non-local class first declares a class or function (this implies that the name of the class or function is unqualified) the friend class or function is a member of the innermost enclosing namespace.

// 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 } 

Your friend class BF; is a declaration of A::BF in namespace A rather than global namespace. You need the global prior declaration to avoid this new declaration.

like image 192
Alexey Malistov Avatar answered Oct 24 '22 18:10

Alexey Malistov


Let's take into account these 3 code lines from your sample:

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 in paragraph 7.3.1.2, point 3 ( Namespace member definitions) says:

The friend declaration does not by itself make the name visible to unqualified lookup (3.4.1) or qualified lookup (3.4.3). [ Note: The name of the friend will be visible in its namespace if a matching declaration is provided at namespace scope (either before or after the class definition granting friendship). —end note ]

And line 2 follows exactly what standard requires.

All confusion is because "friend declaration" is weak, you need to provide solid forward declaration for further usage.

like image 24
LookAheadAtYourTypes Avatar answered Oct 24 '22 18:10

LookAheadAtYourTypes