Нет специального указателя на данные базового класса. Расположение членов данных в C++ близко к C. (На самом деле в вашем примере нет виртуальных методов, поэтому он должен точно следовать C). Итак, давайте рассмотрим, как ваш код будет выглядеть на C:
struct Base
{
int anint;
float afloat;
};
struct Derived
{
struct Base; // C style inherit from struct Base
int a2ndInt;
};
В C структура памяти определяется так, как вы ее пишете. Это означает, что структура Derived имеет следующую структуру памяти.
struct Derived
{
int anint;
float afloat;
int a2ndInt;
};
Указатель this указывает на начало структуры, поэтому доступ к anint или afloat из указателя на Derived или Base требует одинакового смещения памяти. . Таким образом, заброс вниз здесь всегда прост.
Все становится сложнее, когда у вас есть виртуальные функции, поскольку структура данных должна иметь скрытый указатель на свои виртуальные функции, но такой указатель должен быть только один. Давайте рассмотрим случай одиночного наследования, и вы можете представить что-то вроде макета (фактический макет зависит от ABI):
struct Base
{
<ABI defined pointer type> * class_; // hidden virtual function table
int anint;
float afloat;
};
struct Derived
{
struct Base; // inherit from struct Base
int a2ndInt;
};
Теперь структура Derived может иметь следующую структуру памяти. Обратите внимание, что при создании производного объекта конструктор должен установить указатель class_. Это одна из причин, по которой конструкторы начинаются с конструктора базового класса, поскольку каждый производный класс может затем переопределить указатель class_.
struct Derived
{
<ABI defined pointer type> * class_;
int anint;
float afloat;
int a2ndInt;
};
Таким образом, снова доступ к anint или afloat из указателя на Derived или Base включает одно и то же смещение. Таким образом, заброс вниз здесь снова прост.
Множественное наследование намного сложнее, и именно здесь необходимо использовать static_cast‹> для приведения вниз. Этот случай наиболее близок к тому, что вы думаете, но по-прежнему включает смещение только одного указателя this.
struct Base1
{
<ABI defined pointer type> * class_; // hidden virtual function table
int anint;
};
struct Base2
{
<ABI defined pointer type> * class_; // hidden virtual function table
float afloat;
};
Я не так хорошо знаком с ABI, но я полагаю, что скрытые указатели виртуальных таблиц могут быть каким-то образом объединены, что приведет к примерному расположению памяти:
struct Derived
{
<ABI defined pointer type> * class_; // merged Base1 and Base2
int anint;
float afloat;
int a2ndInt;
};
или не объединены (в зависимости от ABI)
struct Derived
{
<ABI defined pointer type> * class_; // from Base1
int anint;
<ABI defined pointer type> * class_; // from Base2
float afloat;
int a2ndInt;
};
Итак, снова доступ к anint из указателя на Derived или Base1 требует того же смещения, но доступ к на плаву не работает. Это означает, что использование приведения в стиле C (т. е. использование (Base2*)
) из указателя Derived в указатель Base2 не работает, вам нужен static_cast<>
, который обрабатывает изменение смещения.
Обратите внимание, что это не так сложно, если только один из базовых классов имеет данные-члены. Вот почему часто рекомендуется, чтобы при использовании множественного наследования только один из базовых классов имел данные.
ПРИМЕЧАНИЕ. Реальный ABI определяет истинное расположение данных в структуре. То, что показано здесь, предназначено только для иллюстрации.
person
Justin Finnerty
schedule
19.09.2017
this + member offset ->
или даже полностью оптимизировано, если компилятору удастся встроить класс и просто сохранитьanint
иafloat
в регистрах. Возможно, связано. - person user7860670   schedule 18.09.2017derivedInstance->this->somethingToBaseObjectThatHoldsTheMembers->anint
как о шагах, необходимых для вычисления смещения члена. Но поскольку каждое смещение известно во время компиляции (если нет виртуального наследования), результирующее смещение также будет вычисляться во время компиляции, и никаких дополнительных перенаправлений не происходит. В случае виртуального наследования будет дополнительное перенаправление через указатель на базовый класс. - person user7860670   schedule 18.09.2017this
pointer, который вы можете написать явно, для доступа к членам, которые с точки зрения памяти находятся внутри безымянного подобъекта базового класса, только гипотетический? - person   schedule 18.09.2017