I am trying to understand concept of friendship in nested classes but I am not getting the concept properly. I have written a sample program to understand it but the program is not working
#include<iostream>
using namespace std;
class outerClass
{
private:
int a;
public:
class innerClass;
bool print(innerClass);
};
class innerClass
{
friend class outerClass;
private:
int b;
public:
innerClass() =default;
};
bool outerClass::print(outerClass::innerClass obj)
{
cout<<"Value of b in inner class is:"<<obj.b;
}
int main()
{
outerClass in;
outerClass::innerClass obj;
obj.b=5;
in.print(obj);
}
I am getting below errors:
try.cpp: In member function ‘bool outerClass::print(outerClass::innerClass)’:
try.cpp:26:6: error: ‘obj’ has incomplete type
try.cpp:11:15: error: forward declaration of ‘class outerClass::innerClass’
try.cpp: In function ‘int main()’:
try.cpp:34:28: error: aggregate ‘outerClass::innerClass obj’ has incomplete type and cannot be defined
As I read through articles on internet I learnt following points please comment on them if they are correct or not:
innerClass can access all the members of outerClass by default.
For outerClass to access private members of innnerClass we need to make outerClass as friend class to innerClass.
Please help in pointing out the mistake in code and also if the points I understood are correct.
The line class innerClass; within outerClass is a forward declaration to a class that you never define.
Hence outerClass::innerClass is an incomplete type.
The separate innerClass definition that starts with
class innerClass
{
is a completely different class to the forward declared class.
There's nothing wrong with your friend class outerClass; statement within the defined innerClass.
If you want to define innerClass outside of outerClass, here is how to do it:
class outerClass
{
class innerClass; // forward declaration
};
class outerClass::innerClass // definition
{
};
The rest is OK, except of obj.b=5. The class outerClass is allowed to access innerClass::b, the function main() is not.
innerClass can access all the members of outerClass by default.
Right. From the standard [class.access.nest]:
A nested class is a member and as such has the same access rights as any other member.
For outerClass to access private members of innnerClass we need to make outerClass as friend class to innerClass.
Right. From the standard [class.access.nest]:
The members of an enclosing class have no special access to members of a nested class;
I think you are confusing with nested class and friend class
You can use friend class not using nested class and
you can use nested class not using friend class
Here are some example:
class A {};
class B {};
Here the A class knows the B class, but the B cannot know the A class. So you need to tell the A class that the B class is exist.
This doing thing, is called Forward Declaration
So:
class B; // forward declaration
class A {}; // A knows the B
class B {}; // B knows the A
Related
I have a problem. In the following example, there is a static private member variable called private_b of class A inside namespace a. And then I'm trying to access that variable from class B, which I have declared to be a friend of class A, but it doesn't work, with a compile error from GCC:
error: ‘B* a::A::private_b’ is private within this context
class B;
namespace a {
class A {
private:
static B* private_b;
friend class B;
};
B* A::private_b = nullptr;
}
class B {
public:
void foo() {
B* foo = a::A::private_b; // Error here
}
};
I don't understand why I can't access it, and how to get around this problem. I really want class A to be inside that namespace, and class B doesn't make sense to be inside that namespace. I searched for this on the internet, but couldn't find this exact case, or couldn't find a solution for this case.
friend class B; declared friendship with B in the same namespace a. You may want friend class ::B;.
Note, friend class B; does not refer to the global forward declaration class B, it has own forward declaration class B after the keyword friend.
class B;
class A {
private:
int numA;
public:
A(): numA(12) { }
// friend function declaration
friend int add(A, B);
};
this does not give any error on declaring object of class B in friend
function,,but this gives,,as firstly class B is declared
class Apple;
class B {
private:
int b;
public:
void showA(Apple d)
{
// Since B is friend of A, it can access
// private members of A
cout << "A::a=" ;
}
};
};
this gives an error of incomplete type for object d,,why this is happening though we already declared class apple before,
Why does the first example compile?
In your first example, you have a forward declaration of class B followed by a declaration of a friend function that uses it in its parameter list:
class B;
class A {
...
friend int add(A, B);
};
This is allowed because, although B is incomplete, we are not defining add yet, only declaring an intention to eventually do so.
Why does the second example not compile?
In the second example, we have a forward declaration of class Apple, followed by a definition of showA:
class Apple;
class B {
...
void showA(Apple d)
{
...
}
};
This time, since we are defining the function, the compiler is obligated to generate code for it. But because Apple is incomplete, the compiler cannot know, for example, how much space in memory to reserve to hold the parameter d. Therefore this is an error.
The question When can I use a forward declaration? explains some of what can and cannot be done with an incomplete (forward-declared) type.
The use of 'friend' is irrelevant here
The friend keyword is basically irrelevant here. friend primarily affects access control (in the sense of public and private), but that's not the issue here.
A detail: friend also affects scoping. Because of friend, add is not a member of class A, but rather refers to a member of the global scope without actually introducing one (it's weird). But that does not change whether an incomplete type can be used as a parameter.
First of all, sorry for the lengthy title. I encountered an issue, where the existence of a private base of the same type as a member shadows access to the member in a child class but not outside the child class definition. Look at the following code:
struct PrivateBase {};
struct Base : private PrivateBase {
// Member accessors.
PrivateBase* GetPrivateBase() { return &a; }
template<typename T>
T* GetPrivateBase() { return &a; }
// Free function accessors.
friend PrivateBase* FreeGetPrivateBase(Base* b) { return &(b->a); }
template<typename T>
friend T* FreeGetPrivateBase(Base* b);
private:
// This member has nothing to do with the PrivateBase base class.
PrivateBase a;
};
template<typename T>
T* FreeGetPrivateBase(Base* b) { return &(b->a); }
struct Child : public Base {
void SomeFunc() {
// Works!1!!.
GetPrivateBase();
// Doesn't work.
//GetPrivateBase<PrivateBase>(); // (1)
// Works!1!!.
FreeGetPrivateBase(this);
// Doesn't work.
//FreeGetPrivateBase<PrivateBase>(this);
}
};
int main() {
Child c;
// Works!1!!.
c.GetPrivateBase<PrivateBase>();
// Works!1!!.
FreeGetPrivateBase<PrivateBase>(&c);
return 0;
}
I've tried to compile this both, with g++-4.8.4 and clang++-3.7.1. With clang and (1) uncommented I get:
minimal.cc:30:20: error: 'PrivateBase' is a private member of 'PrivateBase'
GetPrivateBase<PrivateBase>();
^
minimal.cc:3:15: note: constrained by private inheritance here
struct Base : private PrivateBase {
^~~~~~~~~~~~~~~~~~~
minimal.cc:1:8: note: member is declared here
struct PrivateBase {};
^
The fun fact is that access to a works outside of Child and inside Child with the non-templated accessors. It also works inside Child with the templated accessors if I get rid of the private base class.
I would love to blame it on the compiler but unconventionally enough both contenders seem to agree. Could anybody explain the interplay between templated accessors, child scope and private base class? - Thanks.
Name lookup is done before access checking. Unqualified name lookup for PrivateBase within a member function of Child finds the injected class name of the PrivateBase base class, which is then found to be private, hence the error.
Using something like GetPrivateBase<::PrivateBase>(); inside SomeFunc() fixes the problem, because qualified name lookup now finds PrivateBase as a member of the global namespace, where it is accessible.
This is also why the calls in main work: main is not a member function, so unqualified name lookup for PrivateBase finds the namespace member.
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 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.