#include
#include
struct A { int a; };
struct B : virtual A { int b; };
struct C : virtual A { int c; };
struct D : B,C { int d; };
in
Just a precision: a way to implement virtual inheritance is to push (all) the virtual base classes at the end of the classes after all the own member fields declarations. Here should be the organization of class D and class B.
class D:
-----
pvmt for B, D (include shift to find A)
int b;
-----
pvmt for C (include shift to find A)
int c;
-----
int a;
-----
class B:
-----
pvmt for B (include shift to find A)
int b;
-----
int a;
-----
class C:
-----
pvmt for C (include shift to find A)
int c;
-----
int a;
-----
It is not new
that chooses the layout for void* rawObject= new (storage) B;
; It is the fact that you create a concrete B object. So the layout is the same than the one for contiguous
- the second one.
Where is the guarantee that the layout created by new fits into a buffer of size sizeof(B) and with offset zero
From the the type being named in new
as its argument being B
. A B
is being made, not an D
. The type B
"knows nothing" about D
. The declaration of D
has no influence on B
; the B
declaration can be put into translation units in which D
doesn't appear, yet everywhere in the program there will be agreement about the size of B
and is layout, regardless of whether D
is also known in those places or not.
A C++ object of type T
has a size sizeof T
. This means that it fits into sizeof T
bytes; it cannot be the case that (sizeof T) + k
bytes are required for its representation, where k > 0
.
There are two things happening in a new expression:
Allocating memory for a type by calling operator new (which is no new expression)
Construction of the desired type.
Usually the operator new can utilize the size, which is passed by the compiler inside the new expression. Having a placement new (offering storage), the programmer is responsible to provide a storage large enough to hold the desired type.
Anyway: Do not mix allocation and object construction. These are two distinct tasks.
There is no option to create what you call a "separate" layout, other than creating a derived type, and fishing B
out of it.
"Layout of B
as portion of its derived class" is not the same as "Layout of B
". Placement new
and regular new
use the layout based on the type itself, with is the default, stand-alone layout.
Where is the guarantee that the layout created by new fits into a buffer of size
sizeof(B)
?
sizeof(B)
returns the size of B
itself, not B
-as-part-of-some-other-class. That is all the space needed to store a stand-alone B
, regardless of the way that you allocate memory for it.