Here is a piece of code:
struct Base
{
virtual void Foo() = 0;
virtual ~Base() { }
};
struct Derived : Base
{
virtual void Foo() override { }
unsigned long long some_new_data_members[42];
};
int test_offset()
{
Derived object{};
Base* base_subobject = &object;
return reinterpret_cast<unsigned char*>(base_subobject) - reinterpret_cast<unsigned char*>(&object);
}
The function test_offset
always returns 0 on all versions of gcc, clang and msvc compilers that I have checked.
My question is: does the C++ standard guarantee that this function will be always returning 0 in case of single inheritance between Base
and Derived
?
If it does not, can somebody provide a real-life example (maybe with some exotic platform) where this code will return something different from 0?
Please do not answer about multiple inheritance!
upd.:
As pointed out by user VTT, code like this can lead to a non-zero offset:
struct Base
{
};
struct Derived : Base
{
virtual void Foo() { }
};
It yields an offset equal to the size of a pointer on msvc.
But the fundamental difference of this example from my code snippet is that the Derived
class here introduces some new virtual functions. Thus, a new vtable pointer has to appear somewhere in Derived
, and it might be placed before the Base
subobject, giving us a non-zero offset.
So, now I want to ask more specifically about my scenario.
What if the Base
class has already had some virtual functions, and Derived
just overrides them without adding any new ones (although it might add some new non-static member fields).
Are such non-zero offsets possible in this particular case?
Property of the pointers to different objects to have the same value is called pointer-interconvertible. The standard lists all possible cases when this is guaranteed:
6.7.2 Compound types [basic.compound]
4 Two objectsa
andb
are pointer-interconvertible if:
(4.1) they are the same object, or
(4.2) one is a union object and the other is a non-static data member of that object (12.3), or
(4.3) one is a standard-layout class object and the other is the first non-static data member of that object, or, if the object has no non-static data members, the first base class subobject of that object (12.2), or
(4.4) there exists an objectc
such thata
andc
are pointer-interconvertible, andc
andb
are pointer-interconvertible.
If two objects are pointer-interconvertible, then they have the same address, and it is possible to obtain a pointer to one from a pointer to the other via areinterpret_cast
(8.5.1.10). [Note: An array object and its first element are not pointer-interconvertible, even though they have the same address. —end note ]
Example:
struct Base{};
struct Derived : Base
{
virtual void Foo() { }
};
offset will be 8 (on typical 64-bit platform) for extra vtable pointer added by Derived
infront of Base class subobject.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With