Unexpected behavior with reference and friend class - c++

I have an unexpected behavior using the friend keyword and a reference. Here is the code :
#include <iostream>
class Modifier;
class A{
private:
int _a;
friend Modifier;
};
class B : public A {};
class Modifier
{
public:
void f(A& i) { i._a = 10; std::cout << i._a << std::endl; }
};
int main()
{
Modifier m;
B b;
m.f(b);
}
// Output
// 10
B shouldn't be able to modify the variable _a. Can someone explain me how it is possible ?

B shouldn't be able to modify the variable _a
_a and the object that contains it are non-const, so _a can be modified. Declaring a member private doesn't prevent a variable from being modified. Access specifier only affects the scopes where the name of the variable is accessible.
The class B doesn't modify the variable _a. It is Modifier::f that modifies _a variable (which is member of A base sub object of variable b). Modifier is a friend of class A, so members functions of Modifier have access to privately declared names of A. Having access means that it can use the name A::_a.

B is already unable to modify _a, as it's declared private in B. It's only accessible in A. If you need to read _a from B, use protected getter:
class A {
protected:
auto get_a() const { return _a; }
private:
int _a;
friend Modifier;
};

A friend class can access private and protected members of other class in which it is declared as friend. So, _a can be modified by any method of class Modifer. However, B can not modify _a because it is defined as private in class A. For example, if you would implement the method f in class B, then you would get compiler error which says 'int A::_a' is private
class B : public A {
void f(A& i) { i._a = 10; std::cout << i._a << std::endl; }
};

Related

Accessing private members of surrounding class

I have two classes like this:
#include <iostream>
class A {
public:
class B {
public:
void printX(void) const { std::cout << A::x << std::endl; }
};
private:
int x;
};
Obviously this piece of code doesn't work because B can't access x, but is there a way to make it work?
I've tried using friend class keyword in both classes like this:
class A {
public:
class B {
public:
friend class A;
void printX(void) const { std::cout << A::x << std::endl; }
};
friend class B;
private:
int x;
};
But it didn't work either, and I can't figure out if it's even possible.
According to the C++ 17 Standard (14.7 Nested classes)
1 A nested class is a member and as such has the same access rights as
any other member. The members of an enclosing class have no special
access to members of a nested class; the usual access rules (Clause
14) shall be obeyed.
The problem with the provided code is that x is not a static data member of the class A. You need to provide an object of the class A the data member x of which will be accessed within an object of the nested class.
For example
class A {
public:
class B {
public:
void printX( const A &a ) const { std::cout << a.x << std::endl; }
};
private:
int x;
};
A::B().printX( A() );
As the error message should tell you, A::x isn’t a static member so you need an object instance to access it. If you add a reference to instance of A to B::A, you can use that to access A::x.
For example, the following works:
class A {
public:
class B {
public:
B(A const& a) : a(a) {}
void printX(void) const { std::cout << a.x << std::endl; }
private:
A const& a;
};
private:
int x;
};
Note that using a reference member has several implications. Notably, you can now no longer reassign instances of type A::B, nor are its instances movable. As a consequence, it’s often convenient to hold a pointer rather than a reference to A inside A::B. Either way, you’ll need to ensure that instances of A::B do not outlive the A instance they refer to, otherwise you end up with a dangling reference.

Why Friend Function cannot access private members of a class

class A{
public:
void printer(){
B obj;
obj.private_data = 10; // <- fails, says member inaccessible
}
}
class B{
friend void A::printer();
private:
int private_data;
}
is it possible for printer function to access private members of class B? i tried to pass an obj of B as arg to printer but it still failed
Class A doesn't know about B to use it. Hence, postpone the definition of the function printer() until you define B, and if you need an instance of B to be a member var in A then make a forward declaration for B to declare a B* in A.
Hence, use something like what follows:
class A {
public:
void printer();
};
class B {
friend void A::printer();
private:
int private_data;
};
void A::printer() {
B obj;
obj.private_data = 10; // <- No longer fails
std::cout << obj.private_data;
}
int main() {
A a;
a.printer();
}
Demo
Why Friend Function cannot access private members of a class?
They can, but you may need to split the definition of the class up a bit.
Imaginary files added:
Define A (file a.hpp):
class A {
public:
void printer();
};
Define B (file b.hpp):
#include "a.hpp" // B must see the definition of A to befriend a member function
class B {
friend void A::printer();
private:
int private_data;
};
Define A's member function (file a.cpp):
void A::printer() {
B obj;
obj.private_data = 10;
}
To access B, you first need to define it. Thus, you can just declare the method printer and define it after you have defined the class B.
class A {
public:
void printer();
};
class B {
private:
friend class A;
int private_data;
};
void A::printer() {
B obj;
obj.private_data = 10;
}
Note, you probably want to move your methods out of your class definition anyways and into a separate .cpp file. Methods defined inside the class are implicitly marked as inline which might not be what you expect.

Multiple level friendship

In code below:
class B {
int x;
int y;
};
class A {
friend class Other;
friend class A;
int a;
B* b;
public:
A(){ b = new B();}
};
struct Other {
A a;
void foo() {
std::cout << a.b->x; // error
}
};
int main() {
Other oth;
oth.foo();
}
The indicated line fails with:
t.cpp:22:19: error: 'x' is a private member of 'B'
std::cout << a.b->x;
^
t.cpp:7:5: note: implicitly declared private here
int x;
Why friendship is not working when referring from class member to other class member?
This line:
std::cout << a.b->x;
involves accessing a private member of A (b) and a private member of B (x) within class Other. While A gave access privileges to Other, B did not, hence the error. If you want this to work, you'll need to add:
class B {
friend class Other;
};
Side-note, this declaration is meaningless:
class A {
friend class A;
};
A class already has access to its own private members. So calling it its own friend is redundant.
Although this is a weird use of friends, I assume it is for learning purposes. That said, you should fix your friends definition like this:
class B{
friend class Other; // Because you access private member x from Other::foo()
int x;
int y;
};
class A{
friend class Other; // Because you access private member b from Other::foo()
int a;
B* b;
public:
A(){ b = new B();}
};
struct Other{
A a;
void foo(){
// Access A's private member b
// Access B's private member x
std::cout << a.b->x;
}
};
Try this:
class B{
friend class Other;
int x;
int y;
};

Protected member function address in derived class is not accessible

#include <iostream>
class A {
protected:
void foo()
{}
};
class B : public A {
public:
void bar()
{
std::cout << (&A::foo) << std::endl;
}
};
int main()
{
B b;
b.bar();
}
Here I am trying to get address of protected member function of base class. I am getting this error.
main.cpp: In member function ‘void B::bar()’:
main.cpp:5: error: ‘void A::foo()’ is protected
main.cpp:13: error: within this context
make: *** [all] Error 1
Changing foo to public works. Also printing &B::foo works. Can you please explain why we can't get address of protected member function of base class?
B is allowed to access protected members of A as long as the access is performed through an object of type B. In your example you're trying to access foo through A, and in that context it is irrelevant whether B derives from A or not.
From N3337, §11.4/1 [class.protected]
An additional access check beyond those described earlier in Clause 11 is applied when a non-static data member or non-static member function is a protected member of its naming class (11.2) As described
earlier, access to a protected member is granted because the reference occurs in a friend or member of some class C. If the access is to form a pointer to member (5.3.1), the nested-name-specifier shall denote C or a
class derived from C. All other accesses involve a (possibly implicit) object expression (5.2.5). In this case, the class of the object expression shall be C or a class derived from C. [Example:
class B {
protected:
int i;
static int j;
};
class D1 : public B {
};
class D2 : public B {
friend void fr(B*,D1*,D2*);
void mem(B*,D1*);
};
// ...
void D2::mem(B* pb, D1* p1) {
// ...
int B::* pmi_B = &B::i; // ill-formed
int B::* pmi_B2 = &D2::i; // OK
// ...
}
// ...
—end example]
Your example is very similar to the code in D2::mem, which shows that trying to form a pointer to a protected member through B instead of D2 is ill-formed.
I was curious and tried the following example:
#include <iostream>
using namespace std;
class A {
public:
void foo()
{
}
};
class B : public A {
public:
void bar()
{
printf("%p\n", (&A::foo));
printf("%p\n", (&B::foo));
}
};
int main()
{
B b;
b.bar();
}
Actually, I see that &A::foo == &B::foo, so for protected member of base class you can use derived class member to take address. I suppose in case of virtual functions this will not work
Seems I found the answer. If we could get pointer of member function we can call it for other objects of type A (not this) which is not allowed.
It is not allowed to call protected member function in derived classes for objects other than this. Getting pointer would violent that.
We can do something like this:
#include <iostream>
class A {
protected:
void foo()
{}
};
class B : public A {
public:
void bar()
{
void (A::*fptr)() = &A::foo;
A obj;
(obj.*fptr)();
// obj.foo(); //this is not compiled too.
}
};
int main()
{
B b;
b.bar();
}

subtle C++ inheritance error with protected fields

Below is a subtle example of accessing an instance's protected field x.
B is a subclass of A so any variable of type B is also of type A.
Why can B::foo() access b's x field, but not a's x field?
class A {
protected:
int x;
};
class B : public A {
protected:
A *a;
B *b;
public:
void foo() {
int u = x; // OK : accessing inherited protected field x
int v = b->x; // OK : accessing b's protected field x
int w = a->x; // ERROR : accessing a's protected field x
}
};
Here is the error I get with g++
$ g++ -c A.cpp
A.cpp: In member function ‘void B::foo()’:
A.cpp:3: error: ‘int A::x’ is protected
A.cpp:14: error: within this context
Since B is publicly inherited from A, A's protected member(s) become B's protected member(s), so B can access its protected members as usual from its member function(s). That is, the objects of B can access the protected members of B from its member functions.
But A's protected members cannot be accessed outside the class, using object of type A.
Here is the relevant text from the Standard (2003)
11.5 Protected member access [class.protected]
When a friend or a member function of a derived class references a protected nonstatic member function or protected nonstatic data member of a base class, an access check applies in addition to those described earlier in clause 11.102) Except when forming a pointer to member (5.3.1), the access must be through a pointer to, reference to, or object of the derived class itself (or any class derived from that class) (5.2.5). If the access is to form a pointer to member, the nested-name-specifier shall name the derived class (or any
class derived from that class).
And the example follows from the Standard (2003) itself as:
[Example:
class B {
protected:
int i;
static int j;
};
class D1 : public B {
};
class D2 : public B {
friend void fr(B*,D1*,D2*);
void mem(B*,D1*);
};
void fr(B* pb, D1* p1, D2* p2)
{
pb->i = 1; // ill-formed
p1->i = 2; // ill-formed
p2->i = 3; // OK (access through a D2)
p2->B::i = 4; // OK (access through a D2, even though naming class is B)
int B::* pmi_B = &B::i; // ill-formed
int B::* pmi_B2 = &D2::i; // OK (type of &D2::i is int B::*)
B::j = 5; // OK (because refers to static member)
D2::j =6; // OK (because refers to static member)
}
void D2::mem(B* pb, D1* p1)
{
pb->i = 1; // ill-formed
p1->i = 2; // ill-formed
i = 3; // OK (access through this)
B::i = 4; // OK (access through this, qualification ignored)
int B::* pmi_B = &B::i; // ill-formed
int B::* pmi_B2 = &D2::i; // OK
j = 5; // OK (because j refers to static member)
B::j = 6; // OK (because B::j refers to static member)
}
void g(B* pb, D1* p1, D2* p2)
{
pb->i = 1; // ill-formed
p1->i = 2; // ill-formed
p2->i = 3; // ill-formed
}
—end example]
Note in the above example fr() is a friend function of D2, mem() is a member function of D2, and g() is neither a friend, nor a member function.
Consider:
class A {
protected:
int x;
};
class C : public A
{
};
class B : public A {
protected:
unique_ptr<A> a;
public:
B() : a(new C) // a now points to an instance of "C"
{ }
void foo() {
int w = a->x; // B accessing a protected member of a C? Oops.
}
};
In Public Inheritance:
All Public members of the Base Class become Public Members of the derived class &
All Protected members of the Base Class become Protected Members of the Derived Class.
As per the above rule:
protected member x from A becomes protected member of class B.
class B can access its own protected members in its member function foo but it can only access members of A through which it was derived not all A classes.
In this case, class B contains a A pointer a, It cannot access the protected members of this contained class.
Why can the B::foo() access the members of the contained class B pointer b?
The rule is:
In C++ access control works on per-class basis, not on per-object basis.
So an instance of class B will always have access to all the members of another instance of class B.
An Code Sample, which demonstrates the rule:
#include<iostream>
class MyClass
{
public:
MyClass (const std::string& data) : mData(data)
{
}
const std::string& getData(const MyClass &instance) const
{
return instance.mData;
}
private:
std::string mData;
};
int main() {
MyClass a("Stack");
MyClass b("Overflow");
std::cout << "b via a = " << a.getData(b) << std::endl;
return 0;
}
Why can B::foo() access b's x field, but not a's x field?
A protected member can only be accessed by other members of the same class (or derived classes).
b->x points to a protected member of an instance of class B (through inheritance), so B::foo() can access it.
a->x points to a protected member of an instance of class A, so B::foo() cannot access it.
Class B is not identical to class A. That's why members of class B cannot access non-public members of class A.
On the other hand, class B derives publicly from class A, so class B now has a (protected) member x which any member of class B can access.
Lets start with basic concept,
class A {
protected:
int x;
};
class B : public A {
public:
void foo() {
int u = x; // OK : accessing inherited protected field
}
};
Since child is inheriting parent, child gets x. Hence you can access x directly in foo() method of child. This is the concept of protected variables. You can access protected variables of parent in child directly.
Note : Here I am saying you can access x directly but not through A's object! Whats the difference ? Since, x is protected, you cannot access A's protected objects outside A. Doesnt matter where it is - If its main or Child . That's why you are not able to access in the following way
class B : public A {
protected:
A *a;
public:
void foo() {
int u = x; // OK : accessing inherited protected field x
int w = a->x; // ERROR : accessing a's protected field x
}
};
Here comes an interesting concept. You can access a private variable of a class using its object with in the class!
class dummy {
private :
int x;
public:
void foo() {
dummy *d;
int y = d->x; // Even though x is private, still you can access x from object of d - But only with in this class. You cannot do the same outside the class.
}
};
//Same is for protected variables.Hence you are able to access the following example.
class B : public A {
protected:
A *a;
B *b;
public:
void foo() {
int u = x; // OK : accessing inherited protected field x
int y = b->x; // OK : accessing b's protected field x
int w = a->x; // ERROR : accessing a's protected field x
}
};
Hope it explains :)
C++ is complete Object Oriented Programming, where as Java is pure Object oriented :)