views:

195

answers:

4

In section 11.5.1 of "The C++ Programming Language", Bjarne Stroustrup writes:

Like a member declaration, a friend declaration does not introduce a name into an enclosing scope.

For example:

class Matrix
{
    friend class Xform;
    friend Matrix invert (const Matrix &);
//..
 };
Xform x; // error: no Xform in scope
Matrix (*p) (const Matrix &) = &invert; // error: no invert() in scope

For large programs and large classes, it is nice that a class doesn’t ‘‘quietly’’ add names to its enclosing scope. For a template class that can be instantiated in many different contexts (Chapter 13), this is very important.

However, the next section then goes on to say that the class must have been previously defined, or defined in the non-class scope immediately enclosing the class that is declaring it a friend.

My question is that because of the fact that the class needs to be previous defined or defined in the nonclass scope immediately enclosing the class that is declaring it a friend, then in the first example Xform could not be out of scope, as presumably the class would have been defined before the definition of the Matrix class. Furthermore, I can't think of a situation which, given the restriction that the friend class needs to be previously defined or defined immediately after the granter's class, that the friend class will not be in scope!

Secondly, is my interpretation of Bjarne in this section correct, in that:

  • For friend CLASSES only, friend class must have been previously defined in an enclosing scope, OR defined immediately after the non-class scope.
  • For a function, must have been previously declared in an enclosing scope, OR it can also be found by having an argument of type == 'the friendship granter's' class?

Thanks

Taras

A: 

I don't know if I understand your question, but I think Bjarne thought you need to define the class (say Xform) outside Matrix if you want to use it (imagine it is some helper class you put in a header file that you don't #include in all .cpp files that #include the file with Matrix). You needn't define it if you never mention it :)

In case of functions, the situation is similar. However, there is a difference, that it can be even defined with the friend declaration (=inside the Matrix class) and, as you say, "be found by having an argument of type == 'the friendship granter's' class" (or have argument type that is a nested class thereof), by Koenig lookup.

jpalecek
A: 

The idea of a friend function is when you have a private class so that normally other classes cannot access what's inside - you're making a black box, BUT you want to specifically name functions that are outside that are exceptions to that rule. I think it should be thought of as not having much to do with scope, or if anything, defining a special kind of scope.

Something defined as a friend would have to be defined elsewhere, otherwise it's not a friend - it's nothing - it doesn't exist.

Was that the question?

George Sisco
+1  A: 

You're right that Xform would need to have been defined before Matrix if the example code was supposed to work. But it wasn't supposed to work. It was an example of bad code — code that tried to have the friend declaration introduce new names into the program, and then use those names to declare a variable and initialize a pointer.

That was the entire standalone example. It wasn't just an excerpt where you were supposed to imagine additional code before or after the given code, such as definitions for Xform and invert.

Your first paraphrase is not quite correct. The definition of the friend class does not need to immediately follow the class who granted it friendship. It needs to be defined in the immediately enclosing scope. Essentially, it should be defined in the same scope as the class it's friends with. The example after the one you cite illustrates it:

class AE { /* ... */ }; // not a friend of Y

namespace N {
  class X { /* ... */ }; // Y's friend

  class Y {
    friend class X;
    friend class Z;
    friend class AE;
  };

  class Z { /* ... */ }; // Y's friend
}

Although Y says that AE is its friend, it's not referring to the AE class declared earlier because namespace N is the immediately enclosing scope of Y and AE isn't declared there. Instead, the friend declaration must refer to some other AE class that's going to be defined in namespace N elsewhere in the program. (However, it doesn't need to be defined anywhere at all; classes can say they are friends with things that don't exist, and the program won't care. The programmers will care, though, because they'll waste time trying to find the right AE class in the source code.)

You're also wrong on your second paraphrase. The function doesn't have to have been previously declared in an enclosing scope. It just has to be declared eventually. Consider the opening example of section 11.5, where operator* is listed as a friend of both Vector and Matrix classes before the operator has been either declared or defined.

Furthermore, for the friend function to be found, it doesn't have to have arguments equal to the class's type. Stroustrup says the function "can be found through its arguments," and then refers you to section 8.2.6 for what he means by that. That's the section on name lookup.

Rob Kennedy
I think I understand the point which Bjarne was trying to make. IF the friend exists, then the above defines which scope it exists in. My confusion was that, assuming that XForm is a friend, I couldn't think of an example where Matrix would be in scope and XForm wouldn't be.I've appended what I think is an example of this occurring to the end of this question.
Taras
If I understand you correctly, you're saying that a friend function has be be declared in an enclosing scope. Bjarne writes: "It follows that a friend function should either be explicitly declared in an enclosing scope or take an argument of its class"So how come in the example immediately preceding 11.5.2, f() is not X's friend? It looks like to be in an immediately enclosing scope (the global scope):void g();class X{ friend void f(); friend void g();};void f() {/* */} // not a friend of X, but isn't this defined (and declared) in the scope immediately enclosing X's declaration?
Taras
A: 

An example of when Matrix is in scope, XForm isn't, yet there is an XForm class defined which is the friend of Matrix:

1.h
------------------------
namespace Foo
{
 class Matrix
 {
  friend class XForm;
 };
}

1.c
------------------------
#include 1.h
// XForm not in scope
// implement Matrix

2.h
------------------------
namespace Foo
{
 class XForm
 {
 };
}

main.c

#include 1.h
#include 2.h
int main()
{
 // both XForm & Matrix in scope here
}

Is this correct?

Taras