(Я отредактировал этот вопрос, чтобы избежать отвлечения внимания. Существует один ключевой вопрос, который нужно будет прояснить, прежде чем любой другой вопрос будет иметь смысл. Извиниться перед кем-либо, чей ответ теперь кажется менее актуальным.)
Задайте конкретный пример:
struct Base {
int i;
};
Нет виртуального метода, и наследования нет, и, как правило, это очень немой и простой объект. Следовательно, "Обычные старые данные" (POD), и он возвращается к прогнозируемому макету. В частности:
Base b;
&b == reinterpret_cast<B*>&(b.i);
Это соответствует Wikipedia (который, как утверждается, ссылается на стандарт С++ 03):
Указатель на объект POD-структуры, подходящим образом преобразованный с использованием реинтерпрета, указывает на его начальный элемент и наоборот, подразумевая, что в начале POD-структуры нет отступов. [8]
Теперь рассмотрим наследование:
struct Derived : public Base {
};
Опять же, нет виртуальных методов, нет виртуального наследования и нет множественного наследования. Поэтому это также POD.
Вопрос: Этот факт (Derived - POD в С++ 11) позволяет нам сказать, что:
Derived d;
&d == reinterpret_cast<D*>&(d.i); // true on g++-4.6
Если это так, то будет определено следующее:
Base *b = reinterpret_cast<Base*>(malloc(sizeof(Derived)));
free(b); // It will be freeing the same address, so this is OK
Я не спрашиваю о new
и delete
здесь - проще рассмотреть malloc
и free
. Мне просто интересно узнать о правилах создания объектов в простых случаях, подобных этому, и где исходный нестатический член базового класса находится в предсказуемом месте.
Является ли производным объект, который должен быть эквивалентен:
struct Derived { // no inheritance
Base b; // it just contains it instead
};
без прокладки заранее?