Если приведение в Си стиле (float)i; или float(i);, то по сути в обоих случаях вызывается конструктор и создается временный объект? Но а что в случае с указателями, если привести int* p к (float*)p, то почему нельзя написать float*(p) и что делается в случае с (float*)p?
UPD:
@VladD, За static_cast что-то не понятно. К примеру есть Си стиль:
char* str = "123456789";
int* pi = (int*)str;
а с static_cast будет :
char* str = "123456789";
void* pv = static_cast
Ответ
Вообще-то, приведение типов — огромная тема, в ней сброшены в одну кучу и преобразования между арифметическими типами (расширение/сужение различных видов целого, преобразование между целым и плавающей запятой и обратно), и переход вверх/вниз по иерархии наследования через указатели, и динамический контроль типов времени выполнения, и добавление/снятие модификаторов const/volatile, всё подряд. Все правила охватить — тема для раздела с исследованиями.
Продублирую ссылки на документацию:
const_cast
static_cast
reinterpret_cast
dynamic_cast
C-style cast
По поводу вашего вопроса о const_cast: смотрите.
Вы не можете сделать static_cast из char* в int* по правилам, перечисленным тут. Самым подходящим могли бы быть правила 1 и 5, но поскольку нет неявной конверсии между char* и int* (char и int не являются подклассами друг друга), то и прямой static_cast невозможен.
С другой стороны, static_cast из char* в void* возможен по правилу 1, поскольку есть неявная конверсия из любого указателя на данные в void*. Обратная конверсия из void* в int* возможна по правилу 10.
Возникает закономерный вопрос, а зачем нужны такие ограничения? Дело в следующем. Прямая конверсия запрещена, потому что использовать полученный указатель иначе чем для того, чтобы преобразовать его назад к char*, вы не имеете права по стандарту. Это происходит вследствие так называемого strict aliasing rule. Лучше всего почитать подробное объяснение с указанием причин здесь, вкратце: если указатель указывает на char, вы не можете обращаться к int'у по этому адресу. [Единственное исключение — преобразование в char*.]
Поэтому язык предохраняет вас от ошибки: если вы уж написали дважды static_cast через void*, вы должны понимать, что делаете что-то специальное.
Напротив, C-style cast — гораздо более безалаберная штука: компилятор пробует по очереди const_cast, static_cast, static_cast + const_cast, reinterpret_cast, reinterpret_cast + const_cast, и берёт первое, что подходит. Такое поведение более типично для языков типа Visual Basic'а: вы не контролируете, что именно происходит, вы говорите компилятору «короче, реши за меня сам».
C-style cast в C — единственный существующий вид явного приведения типов. Поскольку в нём нету семантики наследования, в нём все операции преобразования указателей являются по существу пустыми, и просто изменяют взгляд компилятора на данные по данному адресу. (Вообще, грубо говоря, C работает с байтами, а C++ — с абстрактными сущностями.) Тем не менее, strict alisaing rule работает и в C.
Заметьте, что в C++ преобразование указателя между базовым и производным типами может приводить к изменению адреса — в отличие от C. Это означает, что reinterpret_cast может дать неправильный результат, даже если static_cast даёт правильный! То есть, нельзя бездумно использовать reinterpret_cast в надежде, что он всё сделает правильно. И это также объясняет, почему C-style cast не сводится к reinterpret_cast
Комментариев нет:
Отправить комментарий