Search code examples
c++virtual-inheritancemember-pointers

Why is it disallowed to convert from VirtualBase::* to Derived::*?


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 cv T”, where B is a class type, can be converted to a prvalue of type “pointer to member of D of type cv T”, where D is a derived class (Clause 10) of B. If B is an inaccessible (Clause 11), ambiguous (10.2), or virtual (10.1) base class of D, or a base class of a virtual base class of D, a program that necessitates this conversion is ill-formed.

Both function and data member pointers are affected.


Solution

  • 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 through pa within foo(), since the actual type of pa can vary with each of foo()'s invocations. Rather, the compiler must transform the code doing the access so that the resolution of X::i can be delayed until runtime.

    Essentially, the presence of a virtual base class invalidates bitwise copy semantics.