Is it legal to cast between member pointers of unrelated base classes?

51 views Asked by At

Given a struct Derived: Base, Other, is it legal to cast T Other::* -> T Derived::* -> T Base::* and dereference it on a Base* that points to a Derived?

I know that the two casts required to do this are valid individually: I can go from a T Other::* to a T Derived::* with an implicit conversion. And it's also allowed to go from a T Derived::* to a T Base::* as long as the resulting member pointer gets dereferenced on an actual Derived (even if it's through a Base*). What I'm not sure about is whether it's allowed to combine these two casts to cast between member pointer types of unrelated base classes.

Here's some example code (should return 2):

struct Base {
    int m_baseInt = 1;
};

struct Other {
    int m_int = 2;
};

struct Derived: Base, Other {};

int main() {
    Derived d;
    int Derived::* derivedMemPtr = &Other::m_int; // Legal, refers to m_int within Derived's Other subobject
    int Base::* baseMemPtr = static_cast<int Base::*>(derivedMemPtr); // Also legal on its own

    Base *basePtr = &d; // Obviously legal
    return basePtr->*baseMemPtr; // Legal? Is this guaranteed to refer to Derived::Other::m_int?
}

Background:

I've got a non-templated base class that performs complex initialization of member variables in derived classes. These members can't be initialized independently. Derived classes pass pointers to their members to the base class:

Base::addMemberToInitialize(static_cast<Type Base::*>(&Derived::m_whatever), other_info);

I'd now like to expand this to members of other bases of the Derived class so that I can break Derived up into functionally independent pieces and re-use them. Essentially, I'd like to do something like this:

struct Base {
protected:
  void addMemberToInitialize(Type Base::*, Info);
  void doTheComplexInitialization(Stuff);
  /* Protected constructors/destructor/operators */
};
struct Derived final: Base, Other, Another, ... {
  Derived() {
    addMemberToInitialize(
      static_cast<Type Base::*>(static_cast<Type Derived::*>(&Other::m_whatever)),
      other_info);
    /* ... */
    doTheComplexInitialization(some_stuff);
  }
}
0

There are 0 answers