Does friendship indeed not inherit?

Hi, all
I am learning C++ with the book C++ Primer, 4th edition. In section 15.2.6, it talks about friend and inheritance, the basic conclusion is that friendship does not inherit. Making something a friend of the base class does not automatically turn it into a friend of any derived class, even w.r.t. the inherited base part in the derived class. The following sample code is given in the book as an example:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class Base {
         friend class Frnd;
     protected:
         int i;
     };
     // Frnd has no access to members in D1
     class D1 : public Base {
     protected:
         int j;
     };
     class Frnd {
     public:
        int mem(Base b) { return b.i; }  // ok: Frnd is friend to Base
        int mem(D1 d) { return d.i; }    // error: friendship doesn't inherit
     };


However, though the last line is labeled as an error by the book, I found it actually works well on my machine. So seems that a friend of the base class can access the "base part" of a derived class.

Can anyone confirm this? Is it a bug in the text book? Or some modification to C++ has been made since the 4th edition of the book is published?

Thank you so much for help.
Last edited on
just to pop it up, anyone helping me?
What compiler?
Hi, I am using gcc under ubuntu. I use g++ to compile.
It shouldn't inherit; but I guess it's dependent on compiler implementation. Specifying it at the lowest possible level to limit scope is going to be a better coding practice.
It might not help, but you could try using `g++ -ansi' rather than just `g++'. That will turn off your GNU C++ compiler extensions. It might just be an implementation bug, though. =/
Last edited on
Hi, I tried g++ -ansi but it still complies. I wrote the following complete code for testing.

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
#include <iostream>
using namespace std;

class Base {
	public:
	Base(): i(0) {}   // i is initialized to 0
	friend class Frnd;   // Frnd is declared a friend of Base
	protected:
	int i;
};

// Frnd has no access to members in D1
class D1 : public Base {  // D1 inherits i from Base as the only member, which is protected.
};

class Frnd {
	public:
		int mem(D1 d) { return d.i; }    // should be an error: friendship doesn't inherit and i is protected in D1
};


int main() 
{
	Base b;
	D1 d1;
	Frnd f;
	cout << f.mem(d1) << endl;  // however it works and give the output 0, what's wrong? 
	return 0;
}


Such code should not even compile, but it did and at run time gives the out put 0. Can anyone help me compile the code on his own system and tell me whether an error is reported or not?
Compiles on VS2008.
It compiles on my machine as well, using OSX and xCode. I'm very new to programming so I don't really understand the problem fully. Does protected really restrict access from friend classes? If I change line 5 to protected: it'll give en error though.
I'm pretty sure the book is wrong and/or it was a typo (or you're reading it wrong?)

When you do this:

int mem(D1 d) { return d.i; }

You're accessing Base::i, not D1::i. Since Frnd is a friend of Base, it's ok.

Or perhaps it was a typo in the book. Maybe he meant to say this:

int mem(D1 d) { return d.j; } // error: friendship doesn't inheri

This would definitely be an error because here you're trying to access D1::j, which is protected. Even though Frnd is a friend of Base, it is not a friend of D1, so this gets you an error. This is what "friendship doesn't inherit" means; just because you're a friend of the parent, doesn't mean you're a friend of the children.


Another tricky bit is this:

1
2
3
4
5
6
7
8
9
10
     class D1 : public Base {
     using Base::i;  // throw this in here....
     protected:
         int j;
     };

     class Frnd {
     public:
        int mem(D1 d) { return d.i; }    // now this will error..
     };


The idea here is that the using statement makes Base::i "become" D1::i. So now mem is trying to access D1::i, which is an error.

However this is dumb because it's easily side-stepped:

1
2
3
4
5
int mem(D1 d)
{
  Base& b = d;
  return b.i;    // we just got around it
}
Last edited on
closed account (z05DSL3A)
The Standard says that "Friendship is neither inherited nor transitive."
From the small example given, I would take that to mean that (in the OP example) you can not inherit freindship from Frnd
i.e.:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
class Base {
    friend class Frnd;
protected:
    int i;
};

// Frnd has no access to members in D1
class D1 : public Base {
protected:
    int j;
};

class Frnd {  
public:
    int mem(Base b) { return b.i; }  // ok: Frnd is friend to Base
    int mem(D1 d) { return d.i; }     
};

class Frnd2 : public Frnd {
public:
    int mem(Base b) { return b.i; } // error: friendship doesn't inherit
};

Hi, Disch:
I tried the code you gave however it still compiles on my machine.
Well some of it does compile, and some of it shouldn't.

Which did you try?
This part:

1
2
3
4
5
6
7
8
9
10
class D1 : public Base {
     using Base::i;  // throw this in here....
     protected:
         int j;
     };

     class Frnd {
     public:
        int mem(D1 d) { return d.i; }    // now this will error..
     };
Weird. Maybe I'm wrong on that one?

*shrugs*

It errored for me on VS though. But perhaps I'm mistaken on what the correct behavior is.
Topic archived. No new replies allowed.