Downcasting с использованием "static_cast" в С++
Рассмотрим:
class base
{
base();
virtual void func();
}
class derived : public base
{
derived();
void func();
void func_d();
int a;
}
main
{
base *b = new base();
sizeof(*b); // Gives 4.
derived * d = static_cast<derived*>(b);
sizeof(*d); // Gives 8- means whole derived obj size..why?
d->func_d();
}
В приведенном выше коде я исказил базовый указатель, который указывает на базовый объект на указатель производного класса. Мне интересно, как производный указатель имеет весь производный объект класса. Я могу вызвать функцию производного класса (только в производном классе). Я не понял эту концепцию.
Ответы
Ответ 1
Используя static_cast
, чтобы отличить объект от типа, он фактически не имеет поведения undefined. Симптомы UB сильно различаются. Там нет ничего, что говорит, что UB не может позволить вызываемой функции-члена быть вызванным успешно (но там ничего, что гарантирует, что он будет, поэтому не рассчитывайте на него).
Вот правило для downcasting с использованием static_cast
, найденного в разделе 5.2.9 ([expr.static.cast]
) стандарта С++ (формулировка С++ 0x):
Значение типа "указатель на cv1 B
", где B
является типом класса, может быть преобразовано в prvalue типа "указатель на cv2 D
", где D
- это производный от класса из B
, если существует допустимое стандартное преобразование из "указателя на D
" в "указатель на B
", cv2 является той же самой cv-квалификацией, что и более высокая cv-квалификация, чем cv1 и B
не является ни виртуальным базовым классом D
, ни базовым классом виртуального базового класса D
. Значение нулевого указателя преобразуется в значение нулевого указателя для типа назначения. Если значение prawue типа "указатель на cv1 B
" указывает к B
, который на самом деле является подобъектом объекта типа D
, результирующий указатель указывает на охватывающий объект типа D
. В противном случае результат приведения undefined.
Ответ 2
Единственный листинг, выполняющий проверку времени выполнения, dynamic_cast<>()
. Если есть вероятность, что приведение не будет работать во время выполнения, то этот прилив должен использоваться.
Таким образом, отливка из leaf- > root (up casting) static_cast<>()
отлично работает.
Но литье из root- > leaf (down casting) опасно и, по-моему, всегда должно выполняться с dynamic_cast<>()
, так как будут зависимости от времени выполнения. Стоимость небольшая, но всегда стоит платить за безопасность.
Ответ 3
sizeof
существует во время компиляции. Он не знает и не заботится о том, что во время выполнения ваш базовый объект не указывает на derived
. Вы пытаетесь влиять на поведение во время компиляции с переменной времени выполнения, что принципиально невозможно.