struct Base {
virtual ~Base() {}
private:
double dummy1;
};
struct A : virtualpublic Base {
double test;
};
struct B : public A {
int dummy2;
};
// A and B not standard-layout.
#include <iostream>
int main()
{
B b;
b.test = 100;
A* a_inside_b_simple = &b;
A a;
A* a_inside_b_hairy = reinterpret_cast<A*>(
reinterpret_cast<char*>( &b.test )
- size_t( &reinterpret_cast<char&>( a.test )
- &reinterpret_cast<char&>( a ) ) );
std::cout << a_inside_b_simple->test << std::endl; // prints 100
std::cout << a_inside_b_hairy->test << std::endl; // prints 100
}
offsetof is only *meaningful* with standard-layout classes.
Your "hairy" code enters undefined behavior multiple times, from pointer arithmetic to accessing aliased lvalue of the wrong type, but for certain kinds of objects, with certain compilers, it can work.
For fun, make dummy1 public and try accessing it the same way.
Surely it won't work when accessing dummy1 the same way (by substituting test in the expression), but then A is not the immediate enclosing class to dummy1. Replacing both test with dummy1 and A with Base, it still works fine.
I still struggle a little how it will ever fail with the premise that you only use the immediate enclosing class when computing member offset. E.g.
1 2 3
B b;
Base base;
Base* basePtr = &b;
So you are you saying that (&basePtr->dummy1 - basePtr) may be different from (&base.dummy1 - &base), even when dummy1 is defined immediately inside class Base?
It seems rather strange to me why anyone would make such a compiler, but I suppose you are right ;)