Yesterday, me and my colleague weren't sure why the language forbids this conversion
struct A { int x; };
struct B : virtual A { };
int A::*p = &A::x;
int B::*pb = p;
Not even a cast helps. Why does the Standard not support converting a base member pointer to a derived member pointer if the base member pointer is a virtual base class?
Relevant C++ standard reference:
A prvalue of type “pointer to member of
B
of type cvT
”, whereB
is a class type, can be converted to a prvalue of type “pointer to member ofD
of type cvT
”, whereD
is a derived class (Clause 10) ofB
. IfB
is an inaccessible (Clause 11), ambiguous (10.2), or virtual (10.1) base class ofD
, or a base class of a virtual base class ofD
, a program that necessitates this conversion is ill-formed.
Both function and data member pointers are affected.
Lippman's "Inside the C++ Object model" has a discussion about this:
[there] is the need to make the virtual base class location within each derived class object available at runtime. For example, in the following program fragment:
class X { public: int i; };
class A : public virtual X { public: int j; };
class B : public virtual X { public: double d; };
class C : public A, public B { public: int k; };
// cannot resolve location of pa->X::i at compile-time
void foo( const A* pa ) { pa->i = 1024; }
main() {
foo( new A );
foo( new C );
// ...
}
the compiler cannot fix the physical offset of
X::i
accessed throughpa
withinfoo()
, since the actual type ofpa
can vary with each offoo()
's invocations. Rather, the compiler must transform the code doing the access so that the resolution ofX::i
can be delayed until runtime.
Essentially, the presence of a virtual base class invalidates bitwise copy semantics.