Re: Difference between pointer to the no data member and the pointer
to the first member
On Sunday, 30 June 2013 17:25:24 UTC+1, somenath wrote:
I am trying to understanding the difference between the
pointer to the no data member and pointer to the first member
of class.
By "no data member", I presume you mean a null pointer (of type
pointer to member).
Also I have learned that =93The value returned from taking the
member's address, however, is always bumped up by 1=94.
That's the usual implementation, but it certainly isn't
required. An implementation could also use -1 as the
representation for null pointers when they are pointers to
(non-function) member.
To understand this concept I wrote the following simple program.
#include<iostream>
using namespace std;
class A
{
public:
int data;
int data2;
};
int main(void)
{
A a1;
int A::*first_data_member =&A::data;
int A::*second_data_member =&A::data2;
int A::*no_data_member ;
cout<<"no_data_member = "<<(no_data_member)<<endl;
cout<<"first_data_member = "<<(first_data_member)<<endl;
cout<<"second_data_member = "<<(second_data_member)<<endl;
return 0;=09
}
The output of the above program is as follows.
=========================
=========================
no_data_member = 1
first_data_member = 1
second_data_member = 1
=========================
========================
I am not able to understand the output of the program.
I am:-). But I can understand your surprize for the last entry.
My expectation is if no_data_member is 1 then
first_data_member sould be = no_data_member + 1 and
second_data_member should be = first_data_member +1.
Please let me know where I am going wrong?
Two things. The first is that you never initialize
no_data_member, so using it is undefined behavior. In this
case, what's happening is that it contains random junk (which
isn't 0). You should define it as:
int A::*no_data_member = NULL; // or nullptr, if you have C++11
The second is that there isn't an overload of << for outputting
pointers to members. So the compiler tries to find a conversion
for which there is an overload. For horrible historical
reasons, pointers (including pointers to members) convert to
bool, and there is a << defined for bool, so what you're seeing
is the default output for each of the pointers defined as
a bool.
Formally, for this sort of thing, you should be dumping the
pointers using something along the lines of:
template <typename T>
class Dump
{
T const& myObj;
public:
Dump( T const& obj ) : myObj( obj ) {}
std::ostream& operator<<( std::ostream& dest, Dump const& obj )
{
IOSave stateSaver( dest ); // Saves fmtflags, etc.
dest.setf( std::ios_base::hex, std::ios_base::baseflags );
dest.fill( '0' );
unsigned char const* begin
= reinterpret_cast<unsigned char const*>( &obj.myObj =
);
unsigned char const* end = begin + sizeof( T );;
for ( char const* current = begin; current != end; ++ curre=
nt ) {
if ( current != begin ) {
dest << ' ';
}
dest << std::setw(2) << *current;
}
return dest;
}
};
template <typename T>
Dump<T>
dump( T const& obj )
{
return Dump<T>( obj );
}
You can then do things like:
std::cout << "no data member = " << dump( no_data_member ) << std::en=
dl;
and get a hex dump of the values.
This is a generic solution for looking at the representation of
any type, and should be generally useful if you're trying to
figure out what the compiler is doing. Depending on what you
are looking at, you may want to modify it to dump the data as
unsigned or size_t, rather than as bytes. Or in specific cases
(like this one, perhaps), you might want to cast the pointer to
an appropriately sized unsigned integer, and use it. (Pointers
to data members are almost always implemented as an integral
type under the hood.)
--
James