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.
Related
I'm reading C++11 Standard (N3092).
11-4 Member access control says
Access control is applied uniformly to all names, whether the names are referred to from declarations or expressions. [ Note: access control applies to names nominated by friend declarations (11.4) and using- declarations (7.3.3). — end note ]
11.4-9 Friends says
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.
With my poor English skill, it seems these two excerpts aren't consistent. What if an access control is applied to friends, as indicated in the first excerpt? Could anyone please give me a concrete example code?
The first excerpt also says about using-declarations. That can be confirmed via the code below. So you can say "access control is certainly applied to using-declarations." But I have no idea how to write a code to see the behavior of access-controled friend functions.
#include <iostream>
using std::cout;
class B {
public:
void f() { cout << "B::f()\n"; }
void f(int) { cout << "B::f(int)\n"; }
};
class D : public B {
public:
using B::f; //`using` declaration in `public` context
void f() { cout << "D::f()\n"; }
};
class D2 : public B {
using B::f; //`using` declaration in `private` context
public:
void f() { cout << "D2::f()\n"; }
};
int main() {
D d;
d.f(); //=> "D::f()"
d.f(0); //=> "B::f(int)"
D2 d2;
d2.f(); //=> "D2::f()"
d2.f(0); //=> "error: ‘void B::f(int)’ is inaccessible within this context"
}
As the code above, if I write
public:
friend void some_func() { }
, is access control applied to the name some_func? How?
it seems these two excerpts aren't consistent
They are consistent, but they don't have to be. Anything inside a [note: ] block is non-normative text. It is there to summarize something for human purposes or to provide clarifying examples, but it is not used to define the actual behavior of the language. So the only excerpt that actually matters is the second one.
The bolded text in first excerpt is talking about the content of the friend declaration. If you have two classes, A and B, and you want to make a specific member of B a friend of A, what the bolded text is saying is that the specific member you name must already be accessible by A. That is, this is illegal:
class B
{
private:
void SomeMember();
};
class A
{
private:
friend void B::SomeMember(); //`SomeMember` is not accessible to `A`, so ill-formed.
};
B would have to make itself a friend of A, so that A could name its private members.
The bolded text in the second excerpt merely says that the location where the friend declaration happens in a class doesn't matter. It doesn't matter if the friend declaration is public, private, or whatever. That is, all of the following mean the same thing:
class B;
class A1
{
public:
friend class B;
};
class A2
{
protected:
friend class B;
};
class A3
{
private:
friend class B;
};
So the two bolded excerpts have nothing to do with one another.
Now, the unbolded part of the second except actually says in normative language what the notation in the first excerpt says. Namely, names specified in a friend declaration have to be accessible.
if I write <...> is access control applied to the name some_func? How?
It's fine. friend definitions always define non-member functions. As such, they're not in the scope of a class, so they are de-facto public. And therefore accessible.
I'm having two classes, PlayerCharacter and Ability. The Ability class has an pure virtual function which I declare as a friend to PlayerCharacter. However, I seem to be unable to access the private members within the friend declared function. Is it something I overlook?
I have attemped to declare the child function rather than the virtual one as the friend function, but to no effect.
player_chracter.h :
#include "ability.h"
class PlayerCharacter : public Character {
private:
// Friend function
friend bool Ability::ExecuteAbility(PlayerCharacter& in_player);
// This doesn't work either
//friend bool Dash::ExecuteAbility(PlayerCharacter& in_player);
// Private variable
float top_speed_;
}
ability.h :
//Forward declaration
class PlayerCharacter;
class Ability {
public:
Ability();
~Ability();
virtual bool ExecuteAbility(PlayerCharacter& in_player) = 0;
};
//---------------------------------------------------------
class Dash : public Ability {
public:
Dash();
~Dash();
bool ExecuteAbility(PlayerCharacter& in_player);
};
ability.cpp :
#include "ability.h"
#include "player_character.h" //Follow through on forward declaraction
bool Dash::ExecuteAbility(PlayerCharacter& in_player) {
float example = in_player.top_speed_;
}
In the code above, why cannot I access top_speed_ and put it in the float example variable?
As per [class.friend]/10, friendship is not inherited.
A derived class does not automatically become a friend of a class just because its parent class is a friend of that class.
The reason why the below also does not work either is probably because Dash is not defined before the function ExecuteAbility is defined.
friend bool Dash::ExecuteAbility(PlayerCharacter& in_player);
However, with the proper order of definitions it will work. See DEMO.
From cppreference:
Friendship is not transitive (a friend of your friend is not your friend)
Friendship is not inherited (your friend's children are not your friends)
Even if Dash::ExecuteAbility overrides a friend function from its base class, it does not benefit from it. You'll have to rethink your design.
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 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.
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.