Стоит ли ожидать, что указатели повышают и понижают в одиночном наследовании?
Предположим, у меня есть:
class Base {
public:
virtual void Nothing() {}
};
class MiddleDerived : public Base {
virtual void Nothing() {}
};
class Derived : public MiddleDerived {
virtual void Nothing() {}
};
и мой код выглядит так:
Derived* object = new Derived();
Base* base = object; //implicit conversion here
void* derivedVoid = object;
void* baseVoid = base;
Должен ли я ожидать, что baseVoid == derivedVoid
?
Я знаю, что большинство реализаций работают таким образом, но гарантировано ли это?
2 ответа
Я думаю, что часть стандарта, которая имеет дело с этим - §5.2.9 (13)
Который утверждает (в двух словах), что T* приведен к пустоте *, а затем обратно к T* должен ссылаться на тот же объект.
Однако нет никаких оговорок адрес Derived
должен совпадать с адресом его Base
,
Таким образом, мой ответ будет: "нет - код, который ожидает, что эта эквивалентность является плохо сформированной и не допускает неопределенного поведения".
То, что вы "должны ожидать", может отличаться от того, что гарантировано.
static_cast
вверх или вниз по цепочке наследования может изменить адрес.
Канонический пример, где это происходит на практике, - это когда базовый класс является неполиморфным, а производный класс представляет некоторую виртуальную функцию, которая со многими компиляторами затем вводит указатель vtable в начале каждого производного объекта.