I have a base class A and derived class B
class B is derived from A as public
I want to access the member variable’s address if A is class a is member variable
I am observing different behavior when i am using protected and public access specifier.
When member a of class A is protected in this case i am getting:
cout<<&A::a << endl; throwing me an compiler error..
but cout<<&(A::a)<<endl; is valid and giving me proper result.
and When member a of class A is public in this case i am getting:
Why this behavior?
Here is the full code :
#include <iostream>
using namespace std;
class A
{
protected:
int a;
void fun()
{
cout<<"A's fun"<<endl;
}
public:
A(int Aarg):a(Aarg)
{
cout << "A's construction done" <<endl;
}
};
class B: public A
{
protected:
int b;
public:
void fun()
{
cout << "B's fun"<<endl;
}
B(int As, int Bs):A(As), b(Bs)
{
std::cout<<"B's Construction Done" <<std::endl;
}
void show()
{
A::fun();
//cout << a << endl;
cout<<&A::a << endl; //compilation error
}
};
int main()
{
B(10,20).show();
return 0;
}
Now there is a undefined behavior i am able to observe:
If i make my member variable a in class A as public then there will not be any compilation error but output is coming as 1 i dont know why..
class A{
public:
int a
....
....
OUTPUT:
A’s construction done
B’s Construction Done
A’s fun
0027F91C
1 (why 1) and no errors as I was able to get when I tried to access protected member?
Short answer: There is no undefined behavior involved. The behavior you see is:
&A::ais an attempt to obtain a pointer to member pointing to member a of class A. If a is protected in A, this expression only passes access checks within class A (or friends of A). In a class B derived from A, you can get the same pointer to member only via the expression&B::a(note that the type of this expression will still beint A::*). So:A::ais protected in A, the expression&A::ais not allowed in a member function of derived class B. This is your compiler error.A::ais public in A, this expression is valid, producing a pointer to memeber.ostream, for example usingcout << &A::awill print1. This results from invokingostream::operator << (bool). You can use the boolalpha manipulator to see that this is indeed the chosen overload:cout << boolalpha << &A::awill printtrue.&(this->a)) is taken, which is a regular pointer to int. This access to a protected member of a base class subobject of*thisis valid, so that variant can be used even if a is protected in A.Longer explanation:
The standard says (5.3.1/3):
So the expression
&A::aattempts to obtain a pointer-to-member to member a of class A.In the next paragraph (5.3.1/4), it is elaborated that only the &X::m syntax produces a pointer to member – neither
&(X::m), nor&mor plainX::mdo:But such an expression is only valid, if access is allowed. In case of a protected member (11.4/1) applies:
In your case access to the protected member a would be granted, because the reference to a occurs in a member of class B, derived from A. As the expression attempts to form a pointer to member, the nested-name-specifier (the part before the final “::a”) must denote B. Thus the simplest allowed form is
&B::a. The form&A::ais only allowed within members or friends of class A itself.There is no formatted output operator for pointers to member (neither as istream member nor as free operator function), so the compiler will look at overloads that can be called using a standard conversion (sequence). The only standard conversion from pointers to member to something else is described in 4.12/1:
This conversion can be used without additional conversions to call
basic_ostream<charT,traits>& basic_ostream<charT,traits>::operator<<(bool n). Other overloads require longer conversion sequences, so that overload is the best match.As
&A::atakes the address of some member, it is not a null member pointer value. Thus it will convert totrue, which prints as “1” (noboolalpha) or “true” (boolalpha).Finally, the expression
&(A::a)is valid in a member of B, even if a is protected in A. by the above rules this expression does not form a pointer to member, so the special access rule quoted above does not apply. For such cases 11.4/1 continues:Here the object impression is an implicit
(*this), i.e.A::ameans the same as(*this).A::a. The type of(*this)obviously is the same as the class where the access occurs (B), so the access is allowed. [Note:int x = A(42).awould not be allowed within B.]So
&(A::a)withinB::show()means the same as&(this->a)and that is a plain pointer to int.