c++runtimevtablestatic-castvirtual-inheritance

c++ static_cast to virtual base in runtime


Suppose we have such code:

struct Granny {
  int g;
};
struct Mom : virtual Granny {
  int m;
};
struct Son : Mom {
  int s;
};

int main() {
  int x;
  std::cin >> x;
  Mom* mom = (x ? new Son : new Mom);
  Granny* granny = static_cast<Granny*>(mom);
}

Classes are not polymorphic, so Granny doesn't has a vtable. Now, depending on x, there can be different memory layout under mom pointer. So, sub-object Granny will be shifted from the object start by either 16 or 12 bytes.

Question: is static_cast instead of "simply shift pointer" compiled in "dereference vptr(vtable) in mom object, then look at some index to find virtual offset, then, finally, shift pointer by this offset"? So, would static_cast has 2 additional runtime operations? If not, please, explain what happens.


Solution

  • You can just throw both cases into Compiler explorer:

    Granny* from_Son(Son* x) { return static_cast<Granny *>(x); }
    Granny* from_Mom(Mom* x) { return static_cast<Granny *>(x); }
    

    compiles to the following three instructions (with error checking around it):

            mov     rax, QWORD PTR [rdi]    
            add     rdi, QWORD PTR [rax-24]
            mov     rax, rdi
    

    In this snippet, rdi is x. [rdi] is your vtable, and the offset to Granny is thus stored 24 bytes before the vtable.