enclosing scope - c++

what's wrong with this code?
class matrix{
private:
friend transpose(const matrix&);
friend class invert;
public: //...
};
matrix (*p)(const matrix&)=&transpose; //error: no transpose() in scope.
what does the statement means "a friend declaration does not introduce a name into enclosing scope".This problem does not occur when friend keyword is removed

The difference between the declaration of transpose() as a friend and without the friend declaration is that if you declare "friend transpose()" all you are doing is telling the compiler that a function friend with the signature shown in the friend declaration can have access to the private members of an object of type matrix. It does not declare a function transpose() with this signature - you still have to do this outside the scope of the matrix class.
If you remove the 'friend' keyword, you are declaring a member function transpose() inside the class matrix, so the compiler actually has seen a function it can take the address of.

§7.3.1.2 [namespace.memdef] p3
[...] If a friend declaration in a nonlocal class first declares a class or function the friend class or function is a member of the innermost enclosing namespace. The name of the friend is not found by unqualified lookup or by qualified lookup until a matching declaration is provided in that namespace scope (either before or after the class definition granting friendship). [...]
See also this question of mine.

Friend functions are functions that are not members of a class but
they still have access to the private members of the class.
I should point out that a friend function declaration
may be placed in either the private section or the public section,
but it will be a public function in either case, so it is clearer to
list it in the public section.
class MyClass
{
private:
int data;
public:
MyClass(int value);
friend void myFriend(MyClass *myObject);
};
void myFriend(MyClass *myObject)
{
cout << myObject->data<< endl;
}
MyClass::MyClass(int value)
{
data = value*2;
}
int main()
{
MyClass myObject(3);
myFriend(&myObject);
}
So, you need to define the friend function after you declare it.

Related

How do I access a variable in member function #1 in member function #2?

I'm starting to work with friends of classes.
Here I have two functions called setMaxSickDays and getMaxSickDays.
I made a variable called maxSickDays in setMaxSickDays that I'd like to access from getMaxSickDays.
class timeOff
{
public:
void setMaxSickDays(numDays &friendlyObject) {
int maxSickDays;
friendlyObject.hours = 240;
maxSickDays = friendlyObject.hours;
}
void getMaxSickDays(numDays &friendlyObject) {
cout << maxSickDays;
}
};
The error: 'maxSickDays' was not declared in this scope
This may seem silly but I'm a beginner. Thanks!
You make maxSickDays a data member of your class.
class timeOff
{
public:
void setMaxSickDays(int days);
int getMaxSickDays();
private:
int maxSickDays;
};
You can't access another function's local variable, even as friend. friend is used to granted to access members (i.e. member variables or functions) of the class.
See friend declaration
The friend declaration appears in a class body and grants a function or another class access to private and protected members of the class where the friend declaration appears.

Placement of friend declarations

Does it matter where in a class a friend clause is placed (i.e. within the protected block as opposed to the private block)?
No it does not.
class X
{
public:
friend class A;
private:
friend class B;
protected:
friend class C;
};
All three classes are now friends of X and share the exact same priviliges.
A good convention is to group all friend declarations together for visibility, but that's just style.
11.4 Friends
9) A name nominated by a friend declaration shall be accessible in the
scope of the class containing the friend declaration. The meaning of
the friend declaration is the same whether the friend declaration
appears in the private, protected or public (9.2) portion of the class
member-specification.

Definition of friend inside class

Can i put definition of friend function / class inside another class? I mean something like this:
class Foo
{
friend void foo() {} // 1
friend class Bar {}; // 2
};
gcc compiles friend function, but can't compile friend class.
You can define a friend function in the friend declaration, and it has interesting behavior that cannot be obtained any other way (in the case of the enclosing type being a template).
You cannot define a friend class in the friend declaration, and there is no need for that. If you want to create a new type inline with full access, you can just create a nested type. Being a member it will have full access to the enclosing type. The only difference is that the type will not be found at namespace level, but you can add a typedef if needed (or alternatively, define the class at namespace level and just declare the friendship inside the class).
class Outer {
int x;
class Inner {
static void f( Outer& o ) { o.x = 5; } // fine
};
};
n3337 11.3/2
A class shall not be defined in a friend declaration. [ Example:
class A {
friend class B { }; // error: cannot define class in friend declaration
};
—end example ]
But you can use something like
class Foo
{
friend void foo() {} // 1
class Bar { };
friend class Bar; // 2
};
You can make a nested class which, according to defect report 45, has access to the private members of the class. Is this what you meant?
"A nested class is a member and as such has the same access rights as any other member."
This may not work in all compilers because prior to this C++ standards defect report, nested classes were given no special access.
Change the code to:-
class Foo
{
friend void foo() {} // 1
friend class Bar ; // 2
};

What's the scope of inline friend functions?

After searching aroung SO, one question taught me that the lexical scope of an inline friend function is the class it's defined in, meaning it can access e.g. the typedefs in the class without qualifying them. But then I wondered what is the actual scope of such a function? GCC at least rejects all my attempts to call it. Can a function such as in the example ever be called through means other than ADL, which is not possible here thanks to no arguments?
Standard quotations are appreciated, as I currently can't access my copy of it.
The following code
namespace foo{
struct bar{
friend void baz(){}
void call_friend();
};
}
int main(){
foo::baz(); // can't access through enclosing scope of the class
foo::bar::baz(); // can't access through class scope
}
namespace foo{
void bar::call_friend(){
baz(); // can't access through member function
}
}
results in these errors:
prog.cpp: In function ‘int main()’:
prog.cpp:9: error: ‘baz’ is not a member of ‘foo’
prog.cpp:10: error: ‘baz’ is not a member of ‘foo::bar’
prog.cpp: In member function ‘void foo::bar::call_friend()’:
prog.cpp:15: error: ‘baz’ was not declared in this scope
When you declare a friend function with an unqualified id in a class it names a function in the nearest enclosing namespace scope.
If that function hasn't previously been declared then the friend declaration doesn't make that function visible in that scope for normal lookup. It does make the declared function visible to argument-dependent lookup.
This is emphasised in many notes, but the definitive statement is in 7.3.1.2/3 (of ISO/IEC 14882:2011):
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 the friend class or function is a member of the innermost enclosing namespace. The name of the friend is not found by unqualified lookup (3.4.1) or by qualified lookup (3.4.3) until a matching declaration is provided in that namespace scope (either before or after the class definition granting friendship). If a friend function is called, its name may be found by the name lookup that considers functions from namespaces and classes associated with the types of the function arguments (3.4.2). If the name in a friend declaration is neither qualified nor a template-id and the declaration is a function or an elaborated-type-specifier, the lookup to determine whether the entity has been previously declared shall not consider any scopes outside the innermost enclosing namespace.
"The C++ Programming Language 3rd Edition (Stroustrap)" : p279:
I. "Like a member declaration, a friend declaration does not introduce a name into an enclosing scope"
II. "A friend class must be previously declared in an enclosing scope or defined in the nonclass
scope immediately enclosing the class that is declaring it a friend"
III. "A friend function can be explicitly declared just like friend classes, or it can be found through its argument types (§8.2.6) as if it was declared in the nonclass
scope immediately enclosing its class."
IV. "It follows that a friend function should either be explicitly declared in an enclosing scope or take an argument of its class. If not, the friend cannot be called. For example:"
//no f() here
void g();
class X{
friend void f(); //useless
friend void g(); //can be found because it is declared outside of class scope
friend void h(const X&); //can be found because the arguments access class members
};
void f() { } //enemy of X :)
But in your case there is more to it that has to do with the namespace, because if you put the proper declaration in foo e.g.:
namespace foo{
struct bar{
friend void baz(const &bar){};
void call_friend();
}
}
does not compile. However, if you declare it outside foo is works like a charm. Now consider that in fact, global, local, struct, and classes are in fact namespaces. Now this leads to the conclusion that the baz(const &) is implicitly defined in the global scope.
This compiles:
namespace foo{
struct bar{
friend void baz(const bar&){};
void call_friend();
};
}
int main(){
foo::bar k;
baz(k);
return 0;
}
Therefore, there are two issues:
The friend declaration does not introduce a name in an enclosing scope, unless IV. Thus the original program cannot find baz() because it has not been properly declared.
If IV , i.e. ADL, then the function is found in foo, but cannot be accessed as foo::baz(k), due to ADL. You will have to explicitely define baz(const bar&) in foo to access it by qualified name.
Thanks, hope it helps, but certainly, I liked the challenge :) .
Interesting!
It seems that the compiler does not know what scope it belongs to (and to be honest there are no clues) and thus puts in in no scope. Some standard digging coming up I suppose.
Note: If you explicitly add a declaration to a particular scope then it starts to work as expected.
namespace foo
{
void baz(); // declare it here and now it works in foo namespace etc.
struct bar
{
friend void baz(){}
void call_friend();
};
}
Digging the standard I find:
11.3 Friends [class.friend]
Paragraph 6
A function can be defined in a friend declaration of a class if and only if the class is a non-local class (9.8), the function name is unqualified, and the function has namespace scope.
[ Example:
class M { friend void f() { } // definition of global f, a friend of M,
// not the definition of a member function
};
— end example ]
Paragraph 7
Such a function is implicitly inline. A friend function defined in a class is in the (lexical) scope of the class in which it is defined. A friend function defined outside the class is not (3.4.1).
Note:
A free standing function that does not take a parameter is not much use as a friend. As it will have no object on which to take advantage of its friendship (I suppose file scope static storage duration objects).
A friend function defined within an enclosing class, will only be found by argument dependent lookup (ADL). Calling it will succeed when one or more of the arguments is either of the enclosing class type; or of a type declared within the class. Here is an example, displaying "Hello World!", which (for variety) doesn't use an object of the enclosing class type to provide such an argument:
#include <iostream>
struct foo
{
struct local_class{};
friend void greet(local_class o, int) { std::cout << "Hello World!\n"; }
};
int main(int argc, char *argv[])
{
foo::local_class o;
greet(o,1);
return 0;
}
In this Example,
namespace foo{
struct bar{
friend void baz(){}
void call_friend();
};
}
int main(){
foo::baz(); // can't access through enclosing scope of the class
foo::bar::baz(); // can't access through class scope
}
namespace foo{
void bar::call_friend(){
baz(); // can't access through member function
}
}
foo::baz() is inaccessible because the name baz is not visible in scope of namespace foo. If I remember correctly (§ 3.4/2) applies here.
foo::bar::baz() is inaccessible because friends aren't members of class and the scope of inline friend function is namespace or class in which their definition exists therefore, you can't access them outside of that scope.
If you put the declaration of baz() in foo the name of function baz will be visible in foo and the definition will be looked up in the nested scope of bar.
namespace foo{
void baz(); // declaration at namespace scope
struct bar{
friend void baz(){}
};
void call_friend() {
baz(); // ok
}
}
int main()
{
foo::baz(); // ok, bar will be looked up in the nested scope of foo::bar.
}
I think you are confusing friend and private. By declaring function a friend you are granting it access to your private members, and not grating other functions access to it. Anyway, any member function of a struct is accessible by any object because struct members are public by default.
However, in your case baz isn't accessible because by doing friend void baz(){} you didn't really declare the function baz, you just said that it is a friend function. You can just remove the friend keyword, and it will solve all the issues.

Why can't I change a private member of a class from a friend class in a different namespace?

I am finding trouble accessing a private member of a class from a friend class.
The class that holds the private member I want to change and the class where the change is made are in different namespaces.
The friend class is defined after the class holding the data, so I've tried to forward declare the friend class outside the namespace.
g++ says that I can't modify the member because it's private, visual studio seems to think it's fine.
Am I doing some weird non-standard thing here? Why can't I change the member? Here is a simplified snippet that represents my problem:
struct S;
namespace N
{
class A
{
int m;
public:
A():m(5){};
friend struct S;
};
}
using namespace N;
struct S
{
A& a;
S(A& a):a(a) {}
void changeA(){ a.m = 9; }
};
int main()
{
A a;
S s(a);
s.changeA();
}
friend struct ::S;
what you are really doing with
friend struct S;
is declaring as friend the class N::S (which is defined nowhere).
Edit: To back up my idea that gcc behavior is correct and VC++ has a bug.
7.3.1.2/3
If a friend declaration in a non-local class first declares a class or
function the friend class or function is a member of the innermost
enclosing namespace. [...] When looking for a prior declaration of a
class or function introduced by a friend declaration, scopes outside the
innermost enclosing namespace scope are not considered.
Because friend struct S; declares N::S class but you need ::S class.
Try writing out friend struct ::S;.
At the moment, the non-existent N::S is assumed. This fix specifies the global namespace, a bit like how the leading / on a Linux path specifies the filesystem root.