from C++ primer 5th edition:
have a look at these classes:
class Base {
friend class Pal;
public:
void pub_mem();
protected:
int prot_mem;
private:
int priv_mem;
};
class Sneaky : public Base {
private:
int j;
};
class Pal {
public:
int f1(Base b){
return b.prot_mem; //OK, Pal is friend class
}
int f2(Sneaky s){
return s.j; //error: Pal not friend, j is private
}
int f3(Sneaky s){
return s.prot_mem; //ok Pal is friend
}
}
Here Pal is a friend class of Base, while Sneaky inherits from Base and is used in Pal.
Now the very last line where s.prot_mem is invoked, author gives the reason it works because Pal is a friend class of Base. But what i read so far, my understanding tells me that it should work anywawy, because s derives from Base and prot_mem is protected member of Base Class, which should have already access to Sneaky, can you explain why i am wrong or some more elaboration please?
my understanding tells me that it should work anyway, because s
derives from Base and prot_mem is protected member of Base Class,
which should have already access to Sneaky
No, protected variable prot_mem can only be accessed by derived class member, but not by third party class member, like class Pal, if Pal is not a friend of Base.
Without friendship, Pal only sees Sneaky or Base's public members. The fact that one member of Base is protected does not benefit Pal in any way - it only benefits Sneaky.
The thing is that while Sneaky can access prot_mem, the code you're showing is not in Sneaky, it's in Pal. If Pal was an unrelated class, it couldn't access prot_mem, which is also protected in Sneaky. However, Pal is a friend of Base, which gives it the access necessary.
Related
Consider the following
class Base;
class A {
int x;
friend class Base;
};
class Base {
protected:
A a_obj;
public:
Base(){
a_obj.x; // works
}
};
class Derived : public Base {
public:
Derived(){
a_obj.x; // not accessible
}
};
I could make public getters and setters for x, or make the object public, but that is not preferrable. Assuming there is a bunch of derived classes, adding friend class Derived in class A would make the code too verbose. Is there a way to say "A is friends with class Base and all it's children"
Is there a way to say "A is friends with class Base and all it's children"
No.
What you can do is make the base a friend (as you did), and write a protected accessor in the base that the children can use to access the private member.
In short, c++ rule is that friendship is not inheritable.
To achieve what you need, you can add static protected method as accessor in a Base class.
But, if you really need to make it w/o accessors or getters
you can make it with reinterpret_cast, but it would be hack and its not recommended.
Is there a way to say "A is friends with class Base and all it's children"
No
You need to fix your design. Classes should not be granted access to members of all types derived from a base class. As per your code, I think you need to modify the private member of a class in the constructor of other class.
One possible solution is using parameterized constructor. You can call constructor of class A from classes Base and Derived.
class Base;
class A {
int x;
public:
A(int in): x(in)
{
}
};
class Base {
protected:
A a_obj;
public:
Base(int in): A(in)
{
}
};
class Derived : public Base {
public:
Derived(): Base(5)
{
}
};
class baseClass {
public:
friend int friendFuncReturn(baseClass &obj) { return obj.baseInt; }
baseClass(int x) : baseInt(x) {}
private:
int baseInt;
};
class derivedClass : public baseClass {
public:
derivedClass(int x, int y) : baseClass(x), derivedInt(y) {}
private:
int derivedInt;
};
in the function friend int friendFuncReturn(baseClass &obj) { return obj.baseInt; }
I don't understand why would the friend function of the base class work for the derived class?
should not passing derived class obj. instead of a base class obj. tconsidered as error?
my question is why it works when i pass a derived class object to it?
Are friend functions inherited?
No, friend functions are not inherited.
Why would a base class function work on a derived class object?
Because friend function is using the data members available in base class only. Not the data members of derived class. Since derived class is a type of base class So, friend function is working fine. But note that here derived class instance is sliced and having information available only for base class.
friend function will report an error if you will try to access restricted members of derived class. e.g.
int friendFuncReturn(baseClass &obj) { return ((derivedClass)obj).derivedInt; }
No. You cannot inherited friend function in C++. It is strictly one-one relationship between two classes.
C++ Standard, section 11.4/8
Friendship is neither inherited nor transitive.
I would like to know if there's a way to make a method from a derived class a friend of its base class. Something like:
class Derived;
class Base
{
int i, j;
friend void Derived::f();
protected:
Base();
};
class Derived : public Base
{
public:
void f();
};
The errors I got were:
error: C2027: use of undefined type 'Derived'
see declaration of 'Derived'
error: C2248: 'Base::i' : cannot access private member declared in class 'Base'
see declaration of 'Base::i'
see declaration of 'Base'
error: C2248: 'Base::j' : cannot access private member declared in class 'Base'
see declaration of 'Base::j'
see declaration of 'Base'
error: C2027: use of undefined type 'Derived'
see declaration of 'Derived'
I struggled with it during all the day. Everything I found about friendship use only separated classes, not inheritance.
No there is no direct way : Base needs the definition of Derived::f while Derived also needs the definition of it's Base class.
But it does not matter, you should not do that, you can, in order of preference :
Provide protected accessors in the Base class
Make the entire Derived class a friend (not necessary in general)
You can use an intermediate helper class which only forward the call of this specific method, and give it friendship :
Example here:
class Base;
class Derived;
class Helper final
{
friend class Derived;
public:
void f(Base* base);
private:
Helper() {}
};
class Base
{
int i, j;
friend class Helper;
protected:
Base() {}
};
class Derived : public Base
{
public:
void f();
private:
Helper helper;
};
void Helper::f(Base* base)
{
base->i = 10; base->j = 5;
std::cout << "Help !" ;
}
void Derived::f()
{
helper.f(this);
}
One approach for this kind of problem is to apply the rule "if it's a thing, then it's a class."
#quantdev solution is on those lines.
Based on the comment:
assuming that I have two classes both derived from base class and
having an identical private member. Why not saving some codes by
putting that member in the base class and providing a friend access to
both derived classes that need the member. Assuming that other derived
classes won't be able to access that member at all. That's what I'm
trying to achieve
[I know that this does not answer the specified question, but may be what you need.]
I'd solve that by factoring the common element into an intermediate class:
class Base
{
public:
Base();
virtual ~Base() = 0;
};
class Derived : public Base
{
public:
void f()
{
i = 1;
}
private:
int i, j;
};
class Foo : public Derived
{};
class Bar : public Derived
{};
class Fred : public Base
{};
I don't know if it is possible to do exactly what you want (although it seems to me like it should be) -- and I'd be interested to see other answers that show how if it is -- but there are a few other ways to achieve what you want. I assume you are asking about this situation in general -- that is, you are also interested in the case where there can be many different derived classes, not all of which need, no should have access to the private fields of Base (otherwise you should make these fields protected of course).
First, the easiest thing to do would be to make Derived a friend class to Base, although this feels like a hack (in part because it doesn't allow for any encapsulation of Base with respect to Derived) and is definitely sub-optimal here.
In my opinion, a somewhat better approach in terms of encapsulation would be to make an external "free" (non-member) function that is a friend to Base (and potentially Derived if you need that too). This gets around the circular compiler error, but unfortunately still loses the conceptual semantics of being an "operation on Derived".
Does a subclass inherit, the main class' friend associations (both the main class' own and other classes friended with the main class)?
Or to put it differently, how does inheritance apply to the friend keyword?
To expand:
And if not, is there any way to inherit friendship?
I have followed Jon's suggestion to post up the design problem:
C++ class design questions
Friendship is not inherited in C++.
The standard says (ISO/IEC 14882:2003, section 11.4.8):
Friendship is neither inherited nor transitive.
You can create (static) protected methods in the parent that will allow you to do things like that.
#include <stdio.h>
class MyFriend
{
private:
int m_member = 2;
friend class Father;
};
class Father
{
protected:
static int& getMyFriendMember(MyFriend& io_freind) { return io_freind.m_member; }
};
class Son : public Father
{
public:
int doSomething(MyFriend& io_freind)
{
int friendMember = getMyFriendMember(io_freind);
return friendMember;
}
};
int main(){
MyFriend AFriendOfFathers;
Son aSonOfFathers;
printf("%d\r\n", aSonOfFathers.doSomething(AFriendOfFathers));
return 0;
}
This however bypasses encapsulation so you probably should take a second look at your design.
friend only applies to the class you explicitly make it friend and no other class.
http://www.parashift.com/c++-faq-lite/friends.html#faq-14.4
The answer is very simple: no, subclasses do not inherit friend associations. A friend can only access the private members of the class the association is declared in, not those of parents and/or children of that class. Although you might be access protected member of a superclass, but I'm not sure about that.
I have three classes:
A data holder class CDataHolder, which uses a Pimpl pattern
class CDataHolder
{
public:
// ...
private:
friend class CBase;
struct PImpl;
PImpl* iPimpl;
};
A base class CBase, which need to access the iPImpl member in CDataHolder, so it is a friend class of CDataHolder
class CBase:
{
protected:
CDataHolder::Pimpl* getDataHolderPimpl();
};
A derived class CDerived from CBase, which need to access the same iPimpl member also. Here occurs a problem.
The derived class cannot use the iPimpl member although its parent class is a friend class. like this:
class CDerived : public CBase
{
public:
void doSth() {
CDataHolder::Pimpl *pImpl = getDataHolderPimpl(); // this line raises an error:
// "illegal access from CDataHolder to protected/private member CDataHolder::PImpl"
}
};
There are plenty of derived classes, so it's not a good way for each derived class to put a "friend class CDerivedXXX" line in CDataHolder class.
How to overcome this issue? Is there a better way to do this? Thanks in advance.
Since you have declared struct PImpl in the private part of CDataHolder class, only friends of CDataHolder can access the same. Why don't you put a forward declaration struct PImpl in the public section or even better before the CDataHolder class?
Friend is (rightfully) very limited and can't be inherited. I hate to beg the question, but maybe either A) you need public access to PImpl or some aspect of it, or B) you need the DataHolder class to do something with PImpl for you.