As we know, a direct or indirect base class's of a derived class public
and protected
members are available in that derived one.
So I have this example:
struct Foo{int x_ = 10;};
struct Bar : Foo{};
struct FooBar : Bar{
void f()const{
std::cout << &x_ << " : " << x_ << '\n';
std::cout << &Foo::x_ << " : " << Foo::x_ << '\n';
std::cout << &Bar::x_ << " : " << Bar::x_ << '\n';
std::cout << &FooBar::x_ << " : " << FooBar::x_ << '\n';
}
};
int main(){
FooBar fb{};
fb.f();
}
When I compile and run the program I get the output:
0x7ffc2f7ca878 : 10
1 : 10
1 : 10
1 : 10
So why accessing the address of the member data A::x_
through a fully-qualified names yields an "Invalid" address? but accessing it directly (unqualified lookup) is OK.
Is my program in Undefined Behavior?
I've compiled my program using GCC and CLANG.
First of all, most likely you did not intend to repeat the &
operator in each std::cout
statement, so I've removed each repeated instance, to print the value of a member rather than its address.
Now watch this:
#include <iostream>
struct Foo{int x_ = 10;};
struct Bar : Foo{};
struct FooBar : Bar
{
void f()const
{
std::cout << &x_ << " : " << x_ << '\n';
std::cout << &(Foo::x_) << " : " << Foo::x_ << '\n';
std::cout << &(Bar::x_) << " : " << Bar::x_ << '\n';
std::cout << &(FooBar::x_) << " : " << FooBar::x_ << '\n';
}
};
int main(){
FooBar fb{};
fb.f();
}
Output:
0x7fffe136c594 : 10
0x7fffe136c594 : 10
0x7fffe136c594 : 10
0x7fffe136c594 : 10
Everything works just fine! What I changed was to enclose expressions like Foo::x_
in parenthesis. Why? Because &Foo::x_
uses the Built-in address-of operator, see Member access operators in cppreference.com. Its value is a pointer to data member, which is NOT an ordinary pointer, as it needs to be bound to an object in order to return an address. See also Similar stackoverflow question for additional explanation.
EDIT
You might wonder why std::cout
displays 1
for your pointer-to-member pointers. Its because of the implicit conversion to bool
:
Boolean conversions
A prvalue of integral, floating-point, unscoped enumeration, pointer, and pointer-to-member types can be converted to a prvalue of type bool.
The converted value is, of course, true
, because your pointers are valid ones, and only nullptr
(and 0) is converted to false
. By other rule, true
is converted to 1. Q.E.D.