Страницы

Поиск по вопросам

вторник, 26 марта 2019 г.

Общий вопрос по работе *_cast< >()?

Привет всем.
Нужно разобраться как работает static_cast, dynamic_cast, да и вообще любой cast из серии кастов, но особенно эти 2, чтобы потом далее без помощи думать над casts.
На сколько смог вычитать, static_cast занимается тем, что берет и побитово( или все же побайтово?) копирует данные одного типа в данные другого типа. Вроде просто, но мне еще интересна реализация. Как найти релизацию? В visual studio я не могу перейти по goToDeclaration/defenition к описанию тела этой функции. *_cast вообще функция или что это? Похоже на какую-то типа шаблонную функцию или что-то типа generic в C#.
dynamic_cast. Преобразование с проверкой. То есть на сколько понял он позволяет делать upCast/downCas, но не позволяет делать crossCast. Тут у меня холиварный большой вопрос: зачем делать upCast - понятно, на этом работает полиморфизм. А вот downCast зачем в С++ нужен? Я пытался на stackowerflow найти ответ, читая посты с подобным вопросом на c#, но я пока не могу думать глобальными концепциями c#, потому мало что понял.
Можно еще приводить один тип объектов к другому (crossCast). Ну это для меня вообще дремучий лесище. Во-первых: указатели-то может как-то и приведутся, но а вообще как это будет работать-то??? Для этого нужно знать как вообще работают недра вызова методов (про раннее и позднее связывание знаю). Во-вторых: а зачем такое может быть нужно??? Можно пример попроще? В-третьих: я так понимаю, что после приведения одного объекта к другому, поля перемешаются и будут содержать мусор. Так как информация о том как приводить не имеется, на сколько я знаю, в классе нет такой информации. Ну а методы вообще непонятно как будут работать.
Помогите пожалуйста залатать столь огромную дыру в моих знаниях)


Ответ

На сколько смог вычитать, static_cast занимается тем, что берет и побитово (или все же побайтово?) копирует данные одного типа в данные другого типа.
Ни одно из преобразований в С++ не работает "побитово" или "побайтово". Потому они и называются преобразованиями. Преобразования выполняют конвертирование данных из одного формата в другой (зачастую - нетривиальное). В общем случае с "побитовой" точки зрения представление результата такого преобразования не имеет ничего общего с представлением исходного значения.
Побитовым/побайтовым копированием занимается функция memcpy, а не преобразования.
static_cast - пожалуй самый универсальный каст. Он умеет делать арифметические преобразования, преобразования указателей в/из типа void *, преобразования объектных указателей вверх-вниз по иерархии, преобразования указателей на члены вверх-вниз по иерархии и т.п.
Как найти релизацию?
Реализацию чего? Все преобразования являются операторами языка и, соответственно, реализуются на уровне ядра языка.
dynamic_cast. Преобразование с проверкой. То есть на сколько понял он позволяет делать upCast/downCas, но не позволяет делать crossCast.
Тут у вас наблюдается какая-то терминологическая путаница. Наоборот, dynamic_cast - это единственный из кастов, который умеет делать cross-cast. Cross-cast-ом называется прямое преобразование от одного базового подобъекта к другому базовому подобъекту в рамках одного общего содержащего объекта. Т.е. сross-cast может возникать только в условиях множественного наследования
#include
struct B { virtual ~B() {} }; struct C {}; struct D : B, C {};
int main() { D d; B *b = &d; // <- upcast C *c1 = &d; // <- upcast C *c2 = dynamic_cast(b); // <- cross-cast assert(c1 == c2); }
Также dynamic_cast умеет делать downcast сквозь виртуальное наследование (чего не умеет делать static_cast)
#include
struct A { virtual ~A() {} }; struct B : virtual A {}; struct C : virtual A {}; struct D : B, C {};
int main() { D d; A *a = &d; // <- upcast
D *d1 = dynamic_cast(a); // <- downcast, OK assert(d1 == &d);
D *d2 = static_cast(a); // <- downcast, ERROR }
dynamic_cast предназначен для нетривиальных полиморфных преобразований, но только внутри связной иерархии полиморфных классов. Ну и, разумеется, dynamic_cast умеет проверять корректность downcast-ов и сross-cast-ов.
А вот downCast зачем в С++ нужен?
Во многих жизненных ситуациях избежать downcast-а не удается, хоть с пьюристско-педантичной токи зрения downcast-ы возможно и идут вразрез с принципами чистого ООП. Во многих случаях код с downcast-ом получается проще, чем та же функциональность, реализованная с упорным избежанием downcast-а.
Одним из классических примеров идиоматического применения downcast является Curiously Recurring Template Pattern ("странно повторяющийся шаблон").
Можно еще приводить один тип объектов к другому (crossCast).
Приведение типов между посторонними несвязанными типами не является и не называется cross-cast-ом.
Делать приведение типов между несвязанными между собой типами может только reinterpret_cast, но по поводу результата такого приведения и его полезности почти никаких гарантий языком не дается.
В-третьих: я так понимаю, что после приведения одного объекта к другому, поля перемешаются и будут содержать мусор.
Так приводить можно не сами объекты, а только указатели или ссылки на них. Такое преобразования делает именно и только reinterpret_cast. И да, при доступе через такие приведенные указатели или ссылки получится ерунда. Но лазить в данные через такие приведенные указатели язык все равно запрещает - поведение не определено (за редкими исключениями). Так что это функциональность из серии "сам виноват".

Комментариев нет:

Отправить комментарий