Reputation: 1766
I'm learning about friend functions, friend classes and friend member functions in C++ classes; Now, the following code compiles fine:
#include <iostream>
class A
{
public:
friend class B;
//friend void B::set(int i);
//friend int B::get();
friend int function(A a);
A(int i);
void set(int i);
int get();
private:
int i;
};
A::A(int i) : i(i)
{
}
void A::set(int i)
{
this->i = i;
}
int A::get()
{
return i;
}
class B
{
public:
B(A a);
void set(int i);
int get();
private:
A a;
};
B::B(A a) : a(a)
{
}
void B::set(int i)
{
a.i = i;
}
int B::get()
{
return a.i;
}
int function(A a);
int main(int argc, char *argv[])
{
A a(0);
std::cout << "in A i=" << a.get() << std::endl;
a.set(10);
std::cout << "in A i=" << a.get() << std::endl;
B b(a);
std::cout << "in B i=" << b.get() << std::endl;
b.set(21);
std::cout << "in B i=" << b.get() << std::endl;
std::cout << "function returns " << function(a) << std::endl;
}
int function(A a)
{
return a.i;
}
I am able to grant friendship to class B and to function "function" in class A without forward declaring class B, or function "function". Now, if I want to grant friendship to the two member functions in class B it doesn't work if I don't define class B before defining class A:
#include <iostream>
class B; // doesn't work, incomplete type (complete type needed)
class A
{
public:
//friend class B;
friend void B::set(int i);
friend int B::get();
friend int function(A a);
A(int i);
void set(int i);
int get();
private:
int i;
};
A::A(int i) : i(i)
{
}
void A::set(int i)
{
this->i = i;
}
int A::get()
{
return i;
}
B::B(A a) : a(a)
{
}
void B::set(int i)
{
a.i = i;
}
int B::get()
{
return a.i;
}
int function(A a);
int main(int argc, char *argv[])
{
A a(0);
std::cout << "in A i=" << a.get() << std::endl;
a.set(10);
std::cout << "in A i=" << a.get() << std::endl;
B b(a);
std::cout << "in B i=" << b.get() << std::endl;
b.set(21);
std::cout << "in B i=" << b.get() << std::endl;
std::cout << "function returns " << function(a) << std::endl;
}
int function(A a)
{
return a.i;
}
but I can't define class B before defining class A so I'm stuck. Forward declaring (not defining) class B doesn't work either.
So my questions are:
1) why I dont need to forward declare a function or an entire class in a friendship declaration but I do need to define a class if I need to specify member functions of that class? I know that friendship declarations are not declarations in the common sense (they just grant access, they don't forward declare anything).
2) how can I make my code compile (besides declaring the A member object in B as A *a)?
Upvotes: 4
Views: 3188
Reputation: 119877
Just make class B
a friend of class A
. There are no adverse effects in doing this.
If you absolutely positively want to exercise more fine-grained control, you can do it with a proxy class like this (using your example stripped to bare bones):
class Proxy;
class A
{
public:
friend class Proxy;
A(int i);
private:
int i;
};
class B
{
public:
B(A a);
void set(int i);
int get();
private:
A a;
};
class Proxy
{
friend void B::set(int);
friend int B::get();
static int& get_i(A& a) { return a.i; }
static const int& get_i(const A& a) { return a.i; }
};
You now can use Proxy::get_i(a)
instead of a.i
in B::set
and B::get
(only).
Upvotes: 0
Reputation: 1416
Here is an example of a friend class and how to use it. This was taken cplusplus.com The reason I am posting this is because your example does not really illustrate the proper use of friendship in c++. I hope this will shed some light as to how/why you should use friendship, and that can lead to you solving your forward declaration problems.
// friend class
#include <iostream>
using namespace std;
class Square;
class Rectangle {
int width, height;
public:
int area ()
{return (width * height);}
void convert (Square a);
};
class Square {
friend class Rectangle;
private:
int side;
public:
Square (int a) : side(a) {}
};
void Rectangle::convert (Square a) {
width = a.side;
height = a.side;
}
int main () {
Rectangle rect;
Square sqr (4);
rect.convert(sqr);
cout << rect.area();
return 0;
}
In this example, class Rectangle is a friend of class Square allowing Rectangle's member functions to access private and protected members of Square. More concretely, Rectangle accesses the member variable Square::side, which describes the side of the square.
There is something else new in this example: at the beginning of the program, there is an empty declaration of class Square. This is necessary because class Rectangle uses Square (as a parameter in member convert), and Square uses Rectangle (declaring it a friend).
Friendships are never corresponded unless specified: In our example, Rectangle is considered a friend class by Square, but Square is not considered a friend by Rectangle. Therefore, the member functions of Rectangle can access the protected and private members of Square but not the other way around. Of course, Square could also be declared friend of Rectangle, if needed, granting such an access.
Another property of friendships is that they are not transitive: The friend of a friend is not considered a friend unless explicitly specified.
Upvotes: 1