Даункастинг с использованием "static_cast" в C++
Рассматривать:
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();
}
В приведенном выше коде я сделал даункастинг базового указателя, который указывает на базовый объект на указатель производного класса. Мне интересно, как у производного указателя есть весь объект производного класса. Я могу вызвать функцию производного класса (объявлена только в производном классе). Я не получил понятие здесь.
3 ответа
С помощью static_cast
приведение объекта к типу, который на самом деле не имеет, приводит к неопределенному поведению. Симптомы УБ широко варьируются. Ничто не говорит о том, что UB не может допустить успешного вызова производной функции-члена (но нет ничего, что гарантировало бы это, так что не рассчитывайте на это).
Вот правило для использования downcasting static_cast
, найденный в разделе 5.2.9 ([expr.static.cast]
) стандарта C++ (формулировка C++0x):
Значение типа "указатель на cv1
B
", гдеB
является типом класса, может быть преобразован в значение типа "указатель на cv2D
", гдеD
это класс, полученный изB
, если действительное стандартное преобразование из "указателя наD
указатель наB
"существует, cv2 - это та же квалификация cv, что и, или более высокая квалификация cv, чем cv1, иB
не является ни виртуальным базовым классомD
ни базовый класс виртуального базового классаD
, Значение нулевого указателя преобразуется в значение нулевого указателя типа назначения. Если значение типа "указатель на cv1B
"указывает наB
это на самом деле подобъект объекта типаD
результирующий указатель указывает на включающий объект типаD
, В противном случае результат приведения не определен.
Единственное приведение, которое выполняет проверку во время выполнения dynamic_cast<>()
, Если есть вероятность того, что приведение не будет работать во время выполнения, то следует использовать это приведение.
Таким образом, кастинг из листа-> корень (до кастинга) static_cast<>()
работает отлично.
Но приведение из root->leaf (приведение вниз) опасно и (на мой взгляд) всегда должно выполняться с dynamic_cast<>()
так как будут зависимости от информации во время выполнения. Стоимость небольшая, но всегда стоит заплатить за безопасность.
sizeof
существует во время компиляции. Он не знает и не заботится о том, что во время выполнения ваш базовый объект не указывает на derived
, Вы пытаетесь повлиять на поведение во время компиляции с помощью переменной времени выполнения, что в принципе невозможно.