The following code compiles on MSVC:
#include <iostream>
class Bob
{
int a;
friend class Outer;
};
class Outer
{
class Inner
{
void f(Bob obj)
{
std::cout << obj.a; //OK
}
};
};
So it seems that if Outer is a friend of Bob, so is Inner, automatically. I am reading the Friends chapter of the standard and am unable to find a clause that would confirm or refute this.
Is this legal, and if so, what's the chapter and verse?
[class.access.nest]/1 states that
A nested class is a member and as such has the same access rights as any other member
So I believe yes, this is standard behavior.
Let's say that Outer has a member function foo(). That function, of course, will have access to Bob's members. To my understanding, the part that I quoted implies that any nested class inside Outer would have the same access rights as foo(), thus having the ability to access Bob's members.
It is also worth noting that the standard contains the following example ([class.friend]/2), note the usage of A::B in Y:
class A {
class B { };
friend class X;
};
struct X : A::B {
// OK: A::B accessible to friend
A::B mx; // OK: A::B accessible to member of friend
class Y {
A::B my; // OK: A::B accessible to nested member of friend
};
};
Related
I have a code where class A and B are defined in global namespace. Same thing is repeated in a nested namespace. However in nested namespace when it sees friend declaration of Class B in Class A, it considers it to be global class B with msvc cl compiler whereas with nested::B in gcc.
class A{
friend class B;
protected:
int i;
A(){
i=0;
}
}; //end of class A
class B{
A* create(){
return new A();
}
}; //end of class B
int main() {
B object;
return 0;
}
namespace nested{
// This forward declaration fixed the error.
//class B;
class A{
friend class B;
protected:
int i;
A(){
i=0;
}
}; //end of class A
class B{
A* create(){
return new A();
}
}; //end of class B
int main() {
B object;
return 0;
}
} //end of nested
It compiles fine with gcc-7.2 but gives below errors with Visual-Studio 17.
[ on line - return new A;] error C2248: 'nested::A::A' cannot access protected member declared in class 'nested::A'
[ on line - A() in nested namespace]note: see declaration of 'nested::A::A'
[ on class A in nested namespace]note: see declaration of 'nested::A'
I found the above commented forward declaration fixes the error.
Reference
My understanding is in nested namespace in class A, it is considering it to be friend with global class B, as it has not seen nested::B yet. But, when we declare a class as friend, shouldn't it first lookup in local namespace (over another pass of compiler or something).
My question is - is there a c++ standard defined and which is the buggy compiler here (if any). I would like it to work with Visual Studio without or with minimal code changes.
Edit 1:
I found some free version of C++ standard on github. Sorry, I got tex files only.
Link
\indextext{local class!friend}%
\indextext{friend!local class and}%
If a friend declaration appears in a local class\iref{class.local} and the
name specified is an unqualified name, a prior declaration is looked
up without considering scopes that are outside the innermost enclosing
non-class scope.
For a friend function declaration, if there is no
prior declaration, the program is ill-formed.
For a friend class
declaration, if there is no prior declaration, the class that is
specified belongs to the innermost enclosing non-class scope, but if it is
subsequently referenced, its name is not found by name lookup
until a matching declaration is provided in the innermost enclosing
non-class scope.
\begin{example}
\begin{codeblock}
class X;
void a();
void f() {
class Y;
extern void b();
class A {
friend class X; // OK, but \tcode{X} is a local class, not \tcode{::X}
friend class Y; // OK
friend class Z; // OK, introduces local class \tcode{Z}
friend void a(); // error, \tcode{::a} is not considered
friend void b(); // OK
friend void c(); // error
};
X* px; // OK, but \tcode{::X} is found
Z* pz; // error: no \tcode{Z} is found
}
\end{codeblock}
\end{example}
I am trying to understand the language
a prior declaration is looked up without considering scopes that are outside the innermost enclosing non-class scope.
This feels like msvc cl is doing right thing and my understanding is "look for last declaration" without worrying about scope.
But, in code example
friend class X; // OK, but \tcode{X} is a local class, not \tcode{::X}
Doesn't this suggest it refers to a local class and not global class, but since there was no local definition of X, on name lookup it referred to global X. Since in my case, there is a local definition of friend class, that should be referred?
Any help would be appreciated.
Hello I am wondering why C++ standard allows us in nested classes to access outer class's private fields, while it forbids to access inner class's private fields from the outer class. I understand, that this example:
class OuterClass{
public:
class InnerClass{
public:
void printOuterClass(OuterClass& outer) {cout << outer.m_dataToDisplay;};
};
private:
int m_dataToDisplay;
};
is fine, because thing, that Inner class sometimes can be complicated. But I think following scenario is also fine:
class Algorithm{
public:
class AlgorithmResults{
public:
void readAlgorithmResult();
private:
void writeAlgorithmResult();
};
void calculate(AlgorithmResults& results, Arguments...){
//calculate stuff
results.writeAlgorithmResult(results);
}
};
For me this structure makes perfect sense, although it is not allowed in C++. I also noticed, that for some time both were allowed in Java, but now second example is also forbidden.
What is the reason, that first example is allowed and another is denied?
Essentially, within a scope names declared earlier in that scope are valid and can be used directly (unless they're shadowed). Code outside a scope can't directly use names declared inside the scope. E.g. code after a curly braces block, can't directly use variables declared inside that block (an example of indirect use is when the outside code has access to a pointer to a static variable inside the curly braces block).
For the second example, just make Algorithm a friend of AlgorithmResults:
class AlgorithmResults
{
friend class Algorithm;
The nested classes could access outer class's private fields, because it's a member of the outer class, just same as the other members.
[class.access.nest]/1
A nested class is a member and as such has the same access rights as any other member.
On the other hand, the outer class doesn't have special access rights on the nested class, they're just normal relationship.
The members of an enclosing class have no special access to members of a nested class; the usual access rules ([class.access]) shall be obeyed. [ Example:
class E {
int x;
class B { };
class I {
B b; // OK: E::I can access E::B
int y;
void f(E* p, int i) {
p->x = i; // OK: E::I can access E::x
}
};
int g(I* p) {
return p->y; // error: I::y is private
}
};
— end example ]
Counter question: Why would you want to allow it?
If you need an outer class have access to an inner class' private internals, you can befriend:
class Foo {
public:
class Frob {
friend class Foo;
int privateDataMember;
};
Foo () {
Frob frob;
frob.privateDataMember = 3735928559;
}
};
C++ has no device to unfriend, so allowing default private access to an outer class would steal you a class design tool and yield reduced default encapsulation.
So i have problem trying to access a friend class properties, i need a pointer to the first item in the map.
class.h
class A{
private:
map<int,float> database;
public:
......
class B{
private:
map<int,float>::iterator it;
public:
friend class A;
B begin();
}
}
and implem.hxx
A::B A::B::begin(){
A::B it;
ite.it = database.begin();
return ite;
}
But it shows a problem when compiling:
error: invalid use of non-static data member A::database
How can i resolve the problem?
Besides some syntax issues, I see the A::database variable is attempted to be accessed in A::B::begin(). But this variable is not static to access it in that way, and class B is not derived from A as well. So, that the question imho has nothing to do with the friendship.
First thing to note is that it is completely redundant to make A a friend of B. Inner classes in C++ have access to private members of outer classes. However, when you're creating an instance of B, in there is no instance of class A, for which you are trying to access the map. You need an instance.
A::B doesn't have an enclosing creating instance of A like in Java for example - begin needs an object of type A to access its database:
A::B A::B::begin(A& a) {
A::B b;
b.it = a.database.begin();
return b;
}
Note that A::B doesn't need to declare A as friend to access private members of A (friend works the other way around) B already has access to the private members since it is nested.
It seems to me you wanted to wrap iterators of A::database in B, so hopefully this points you in the right direction:
class A {
std::map<int,float> database;
public:
class B {
friend class A;
std::map<int,float>::iterator it;
explicit B(std::map<int,float>::iterator it) : it(it) { }
...
};
B begin();
};
A::B A::begin() {
return B(database.begin());
}
Now begin is a member function of A and creates a B using a private constructor only A may access. Here's the usage code:
A a;
A::B b = a.begin();
...
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
};
I have the following situation:
class Test
{
private:
class SubType
{
//...
};
static std::vector<SubType> v;
};
Because v is static, I initialize it in the cpp file with
std::vector<Test::SubType> Test::v;
But this does not work, the compiler tells me that "Test::SubType" is private.
What can I do about this?
Thanks!
This works for me:
#include <vector>
using namespace std;
class A {
class B {
};
static B b;
static vector <B> vb;
};
A::B A::b;
vector <A::B> A::vb;
I guess you forgot to #include <vector>. Because the following compiles on comeau
#include <vector>
class Test {
class SubType
{
//...
};
static std::vector<SubType> v;
};
std::vector<Test::SubType> Test::v;
Others reported the code compiles fine. I want to supply the Standard wording for backing it up. At 11/5
All access controls in clause 11 affect the ability to access a class member name from a particular scope. The access control for names used in the definition of a class member that appears outside of the member’s class definition is done as if the entire member definition appeared in the scope of the member’s class. [...]
[Example:
class A {
typedef int I; // private member
I f();
friend I g(I);
static I x;
};
A::I A::f() { return 0; }
A::I g(A::I p = A::x);
A::I g(A::I p) { return 0; }
A::I A::x = 0;
Here, all the uses of A::I are well-formed because A::f and A::x are members of class A and g is a friend of class A. This implies, for example, that access checking on the first use of A::I must be deferred until it is determined that this use of A::I is as the return type of a member of class A. ]