Friends letting me down

I've got a problem with friend functions in classes. Code:

1
2
3
4
5
6
7
8
9
10
11
12
13
class c2;
class c1 {
     int i;
public:
     void func();
     friend c2::func();
}
class c2 {
     int i;
public:
     void func();
     friend c1::func();
}

etc.

All I want is functions in each class having access to the private int from the other class. That doesn't seem to work, cause function in class c2 hasn't been declared, but I can't declare it before c1, cause member function cannot be declared outside the class and I can't define c2 before c1, cause there would be no way to define function from c1 as a friend of c2 class. That whole thing is some kind of paradox, I have no idea how to solve this.

I know that the problem can be solved using global functions or by defining the whole class as a friend, but I don't want to use that. I'm just wondering if there's a way to do it my way.
1
2
3
4
5
6
7
8
9
10
11
12
13
class C2;

class C1
{
    friend class C2;
    // ...
};

class C2
{
    friend class C1;
    // ...
};
...or by defining the whole class as a friend, but I don't want to use that.

Why wouldn't you want to do that? I'm pretty sure it doesn't add much to any overhead. This is the right way to do this in C++.
There are very few times where friends are a good choice. If you find that you tend to use them, you're headed down the wrong path.
Strangely, I use friends almost exclusively to overload the output stream operator so I can print the class data members values out easily for easy debugging. I have not used it for other purposes though.
That's how it seems to be implemented in books, but there's no reason why stream operators can't be implemented using public methods.
That's how it seems to be implemented in books, but there's no reason why stream operators can't be implemented using public methods.


Of cuz it can be like public methods but then the calling code will not be so intuitive.

E.g
class Abc {
friend ostream& operator<<(ostream&, Abc&);
void printOut(ostream&);
};

Abc a;

cout << a << "\n"; // statement 1

versus

a.printOut(cout); // statement 2

Now I personally would find statement 1 to be rather intuitive over statement 2.

Just turn the member function c1::func() into a non-member function func(c1&). If you need access to private or protected elements of c1 make that function a friend of c1. Same with c2::func(). Hence this would look like
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class c2; 

class c1
{
public:
	friend void func( c2 & );
	friend void func( c1 & );
protected:
	int i;
};

class c2
{
public:
	friend void func( c2 & );
	friend void func( c1 & );
private:
	int i;
};
Last edited on
There's another, rather complicated way, so that you only use member functions. I renamed c1 as X and c2 as Y. Here's how it can be done:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
// forward declaration
class X;

// Is a friend of X and provides access to YFuncBase::func(), where func() is implemented.
class YFuncInterface
{
protected:
	static int &getI( X & x );
	// maybe other functions to retrieve private or protected data from X.
};

class X
{
	int i;
public:
	void func();

	friend class YFuncInterface;
};

// Implements func() using functions from YFuncInterface 
// to access protected and private members of X.
class YFuncBase : private YFuncInterface
{
public:
	void func(); // can access X::i through YFuncInterface::getI().
};

// inherits func() from YFuncBase, bot not the access to protected 
// and private members of X. 
class Y : public YFuncBase
{
	int i;
public:
	friend void X::func();
};


// IMPLEMENTATION

int &YFuncInterface::getI( X & x )
{
	return x.i;
}

void YFuncBase::func()
{
	X x;
	getI(x) = 0;
}

void X::func()
{
	Y y;
	y.i = 1;
}

A plus for this way of doing it, is that you have full control over the functions YFuncBase::func() can access. A minus is, that you have to explicitely specify them in the YFuncInterface.
Last edited on
thanks guys, that's helpful

I was hoping there's some easy way to forward declare member functions, but it seems life is not that easy.
Topic archived. No new replies allowed.