Given the following code:
#include <iostream>
using std::cout;
class A {
public:
virtual ~A() {}
int x,y,z;
};
int main (void)
{
std::cout<<&A::x;
std::cout<<&A::y;
std::cout<<&A::z;
}
The output is:
111
What is the meaning of the output? Why is it 1? Are there any good reason to access class members via pointers (without created object)?
EDIT - Using:
printf("%p",&A::x);
printf("%p",&A::y);
printf("%p",&A::z);
prints: 4 , 8 and C.
It makes more sense now I guess.. (bytes) But still, is there any use for that?
There is no operator<<(std::ostream&, T)
defined for T = &C::m
. Normally you'd get an error.
But instead, there is one for T = bool
and an implicit conversion from a member-pointer to bool
. So the output you're seeing is just the result of those pointers not being null (being converted to true
).
Try this, for example:
#include <iomanip>
#include <iostream>
struct A
{
int x, y, z;
};
int main()
{
std::cout << std::boolalpha; // print boolean values as text
std::cout << &A::x << std::endl;
std::cout << &A::y << std::endl;
std::cout << &A::z << std::endl;
}
Output:
true
true
true
Note that in the code printf("%p", &A::X)
, you have undefined behavior.
The value for the %p
specifier must be a void*
, and there is no conversion from a member-pointer to a void*
. Instead, what you have aliases (type-puns) to void*
, which is undefined behavior. (Imagine that sizeof(&A::x)
was 4 while sizeof(void*)
was 64; nothing says this cannot be the case.)
You just have to come to terms with the idea that not all pointers can be viewed as integer offsets. That we can even print a pointer is implementation-defined: it could print "apple" for null, "pear" for one value, and "milk" for another if a (dumb) implementation wanted to. I've touched on this difference between values and their representations before.
And in this case, there is no output for the value at all. And that's okay, not all values have meaningful printed outputs. The most you can do is print out the individual bits:
#include <climits>
#include <iostream>
#include <type_traits>
template <typename T>
auto print_bits(const T& value)
-> typename std::enable_if<std::is_standard_layout<T>::value>::type
{
// it's okay to alias a standard-layout type as a sequence of bytes:
const auto valueAsBytes = reinterpret_cast<const unsigned char*>(&value);
for (std::size_t byte = 0; byte < sizeof(T); ++byte)
{
// print in reverse order
const std::size_t byteIndex = sizeof(T) - byte - 1;
const unsigned char byteValue = valueAsBytes[byteIndex];
for (std::size_t bit = 0; bit < CHAR_BIT; ++bit)
{
// print in reverse order
const std::size_t bitIndex = CHAR_BIT - bit - 1;
const bool bitValue = (byteValue & (1U << bitIndex)) != 0;
std::cout << (bitValue ? 1 : 0);
}
std::cout << ' ';
}
std::cout << std::endl;
}
(I print the bytes and bits in reverse order because on my architectures this puts the least-significant bit on the right. I prefer to view binary values this way.)
This gives:
struct A
{
int x, y, z;
};
int main()
{
// example:
for (unsigned i = 0; i < 64; ++i)
print_bits(i);
std::cout << std::endl;
// member-pointers:
print_bits(&A::x);
print_bits(&A::y);
print_bits(&A::z);
}
Output:
00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000001
00000000 00000000 00000000 00000010
[...]
00000000 00000000 00000000 00111101
00000000 00000000 00000000 00111110
00000000 00000000 00000000 0011111100000000 00000000 00000000 00000000
00000000 00000000 00000000 00000100
00000000 00000000 00000000 00001000
There are no guarantees on what you see for the member-pointers.
&A::x
creates a pointer to member of class A
. A pointer to member is, in a way, a representation of the "position" of the member within the class. What these numbers mean exactly depends on the particular implementation. I would guess that in your particular implemtation, it means EDIT Actually, GManNickG's answer shows I was wrong with this assumption and it's just printing the pointer to member implicitly converted to x
is on index 1 in the class (the virtual function table pointer being on index 0).bool
.
Note that a pointer to member is not a pointer in the classic sense. You can't dereference a pointer to member directly. You always need a pointer/reference to an object to go along with it. Example (using your class):
int main()
{
int A::*pm; // pm is a pointer to member of A of type int
A a;
pm = &A::x;
std::cout << a.*pm; //will output a.x
pm = &A::y;
std::cout << a.*pm; //will output a.y
A *pa = &a;
std::cout << pa->*pm; //will output pa->y
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With