Your question is focused mostly on calling regular functions of the virtual base, not the (far) more interesting case of virtual functions of the virtual base class (class A in your example)-- but yes, there can be a cost. Of course everything is compiler dependent.
When the compiler compiled A::foo, it assumed that "this" points to the start of where the data members for A resides in memory. At this time, the compiler might not know that class A will be a virtual base of any other class. But it happily generates the code.
Now, when the compiler compiles B, there won't really be a change because while A is a virtual base class, it is still single inheritance and in the typical case, the compiler will layout class B by placing class A's data members immediately followed by class B's data members-- so a B * can be immediately castable to a A * without any change in value, and hence, the no adjustments need to be made. The compiler can call A::foo using the same "this" pointer (even though it is of type B *) and there is no harm.
The same situation is for class C-- its still single inheritance, and the typical compiler will place A's data members immediately followed by C's data members so a C * can be immediately castable to an A * without any change in value. Thus, the compiler can simply call A::foo with the same "this" pointer (even though it is of type C*) and there is no harm.
However, the situation is totally different for class D. The layout of class D will typically be class A's data members, followed by class B's data members, followed by class C's data members, followed by class D's data members.
Using the typical layout, a D * can be immediately convertable to an A *, so there is no penalty for A::foo-- the compiler can call the same routine it generated for A::foo without any change to "this" and everything is fine.
However, the situation changes if the compiler needs to call a member function such as C::other_member_func, even if C::other_member_func is non-virtual. The reason is that when the compiler wrote the code for C::other_member_func, it assumed that the data layout referenced by the "this" pointer is A's data members immediately followed by C's data members. But that is not true for an instance of D. The compiler may need to rewrite and create a (non-virtual) D::other_member_func, just to take care of the class instance memory layout difference.
Note that this is a different but similar situation when using multiple inheritance, but in multiple inheritance without virtual bases, the compiler can take care of everything by simply adding a displacement or fixup to the "this" pointer to account for where a base class is "embedded" within an instance of a derived class. But with virtual bases, sometimes a function rewrite is needed. It all depends on what data members are accessed by the (even non-virtual) member function being called.
For example, if class C defined a non-virtual member function C::some_member_func, the compiler might need to write:
- C::some_member_func when called from an actual instance of C (and not D), as determined at compile time (because some_member_func isn't a virtual function)
- C::some_member_func when the same member function is called from an actual instance of class D, as determined at compile time. (Technically this routine is D::some_member_func. Even though the definition of this member function is implicit and identical to the source code of C::some_member_func, the generated object code may be slightly different.)
if the code for C::some_member_func happens to use member variables defined in both class A and class C.