According to ABI,
A pointer to data member is an offset from the base address of the class object containing it... A NULL pointer is represented as -1
However, according to the c++ standard (I have revision 4296, and there it's in 4.11/1),
the null member pointer value of that type ... is distinguishable from any pointer to member not created from a null pointer constant
and -1 can be a valid offset.
Consider this situation:
#include <iostream>
using namespace std;
struct A {
char a,b,c,d,e,f,g,h;
};
struct B {
int i;
};
struct C : A,B {};
int main() {
char C::*p=&C::h;
char B::*q = static_cast<char B::*>(p);
cout<< (q==nullptr) <<endl; //prints 1
}
In this code, my compiler (g++4.9.2 on x86_64-linux-gnu), places h
at the last byte of A
, and places B
right after A
in C
. Hence, the offset of C::A::h
from the base address of C::B
is -1.
(The conversion is legal, and its result can be used on an object of dynamic type C, even if its static type is B. The standard says (5.2.9/12) "although class B need not contain the original member, the dynamic type of the object with which indirection through the pointer to member is performed must contain the original member")
What am I misunderstanding?
(I suspect that my misunderstanding is about the phrase "the class containing the original member" (5.2.9/12) - considering C::h
, that phrase may refer to A
and not to C
, but the standard explicitly says (10/2) "members of a base class are also considered to be members of the derived class")