Как стать автором
Обновить

Комментарии 59

>2. dynamic_cast
>В случае неправильного приведения типов вызывается исключительная ситуация std::bad_cast и будет возвращен NULL

Как-то интересно у вас получилось, если исключение кинулось, то куда NULL тогда вернулся?
Да, справедливо, bad_cast, вызывается только при работе со ссылками. При работе с указателями возвращается NULL
В С++ используется не NULL, а 0
да, поправил)
#ifdef __cplusplus
#define NULL 0
© stddef.h

NULL тоже используется, просто задефайнен как 0. Использую для указателей именно NULL — так наглядней, мне кажется.
на некоторых платформах NULL это -1

а -1 это всегда число, а 0 тип контекстнозависим
мне кажется это FALSE на некоторых платформах (базы данных, например, может не все) равен -1, а не NULL. Можно пример, чтоб я понял, что я ошибаюсь?
не FALSE, а TRUE, конечно.
в С нет boolean'а. Для if, while, и так далее используются целочисленный типы: нуль/не нуль
в С++ все же приводится к типу boolean:
* целочисленный приводятся нуль/не нуль
* указатели: валидный/невалидный

Опять же в С указатели — это фактически целочисленные типы (хотя это очень приблеженно) — но в любом случае они приводятся к целому. В С++ они к целому не приводятся, а только к boolean'у

Не надо путать физическое значение, и логическое, которое в С++ куда более важно

Всегда интересовал вопрос, чем при использовании C++ отличается reinterpret_cast и C-style cast?
по сути ничем
Спасибо, очень обстоятельный тред :-)
reinterpret_cast, например не снимает константность
Ну и по коду их проще грепать
Например, при касте к одному из предков, участвовавших в множественном наследовании, reinterpret_cast не сдвинет указатель (и он станет невалидным), а си-стайл каст сдвинет.
Такой каст может применяться, чтобы обойти ограничения private/protected наследования, есличо.
обновил статью — насчет порядка вызова cast-ов при C-Style cast
ой-ой.

вовремя я ушёл в javascript с плюсов :)

язык должен помогать решать задачу, а не ломать себе мозг
Зря вы так… Адепты объектно-ориентированного проектирования, включая меня, вас сотрут в порошок :)

ЗЫ Поставил плюсик вашему комментарию, но это, судя по всему вас все равно не спасет :)
Обнаружена холивар-вероятная точка. Каждый язык хорош для своей области.
ООП != C++ Можно быть адептом ООП и не ломать себе мозг выбором способа приведения типов
динамическая типизация != статическая. При статической «ломать мозг» придется в любом ЯП, просто синтаксис операторов приведения типов будет другим.
НЛО прилетело и опубликовало эту надпись здесь
НЛО прилетело и опубликовало эту надпись здесь
НЛО прилетело и опубликовало эту надпись здесь
НЛО прилетело и опубликовало эту надпись здесь
НЛО прилетело и опубликовало эту надпись здесь
НЛО прилетело и опубликовало эту надпись здесь
НЛО прилетело и опубликовало эту надпись здесь
Не все задачи можно на javascript-е решить)
Если для вас это ломка мозга, то зачем вы вообще в программисты пошли? Вы не знаете чем отличается статическая от динамической типизации?
Друзья, я и не думал холиварить :)

Это была всего лишь внезапная эмоция, которой я счёл уместным поделиться, скорее даже в качестве иронии. Так сложилось, что за c++ мне нынче остаётся только наблюдать. А может даже в тайне ото всех я мечтаю когда-нибудь вернуться ;)
пацаны, зацените мой юмор:
#define c_dynamic_cast(__struct,__field,__ptr) ((__struct*)&(((char*)__ptr)[(char*)0 - (char*)&((__struct*)0)->__field]))
dynamic_cast — это не такая тривиальная функция. Ей для работы необходимо, грубо говоря, по дереву RTTI проходить. В compile-time это не решается.
поэтому отнес к юмору, поскольку в Си (речь про Си без плюсов, иначе как бы зачем макрос?), работы с наследованием структур нет. Макрос может пригодится, когда из указателя на поле нужно получить указатель на заголовок структуры. Не хотел никак покушаться на нетривиальность Си++ ;)
А почему вы её назвали «dynamic_cast»? В С++ dynamic_cast делает совсем другое.

Чтобы запутать того, кто потом код читать будет?
Во первых не «dynamic_cast», а «c_dynamic_cast», как бы намекая. Во вторых, если например в структуре используется вложение:

struct child {
struct parent head; // Как это в том же конкуренте топика — gobject
struct field1 field1;

struct fieldN fieldN;
};

то приведение типов:

struct parent* p = getSome();
struct child* c = (struct child*)p;

будет менее предпочтительней, чем

struct parent* p = getSome();
struct child* c = c_dynamic_cast(struct child, head, p);

поскольку перед head может быть встрена, скажем, структура отладки, или структура выравнивания. Вот чем руководствовался:
— «dynamic» — динамическое;
— «cast» — приведение типа.
В них не скрывается сакрального смысла. Во всяком случае угловые скобки все расставят по местам.
Мне кажется, вы offsetof (стандартный макрос из stdlib) с dynamic_cast'ом путаете.
#define offsetof(type, field) ((size_t)(&((type *)0)->field))

этот? Его использование менее удобно для указанной выше специфики операции.
Я давно уже програмлю на плюсах, и давно уже програмлю только на С( так как часть работы сидела я линукс кернел).
И на самом деле уже два года это уже не моя работа.
Но я никогда не применял эти касты и не понимал зачем они нужны, и зачем их придумали — тоже не принимал.
И за 10( а то и больше) лет, у меня никогда не было проблем с кастами, приведением типов и виртуальными методами.
Других багов было много, и магия была и не шаманства.
Но старый добрый CBase base=(CBase)сhild; меня никогда не подводил
>Но старый добрый CBase base=(CBase)сhild; меня никогда не подводил

Разве это не будет сделано автоматически без ручного приведения типов? Приведение типов сверху вниз очень полезно при разработке gui приложений, впрочем любовь к ним говорит о недостатках дизайна.
Это я образно. Вообще приведение будет произведено при добавлении в какой либо контейнер.
Просто потому что любой контейнер — что монстров на уровне, что элементов этого ГУЯ( который есть одно из мест где возможны самые интересные применения ООП и приведения разностных типов к единому «работельному» состоянию) — так вот этот контейнер строго типизирован( не строго типизироавный контейнер на самом деле тоже строго типизирован. но его тип не строго следит за тем что в него внутрях и позволяет различные вольности, так что к этой фразе особо не придерайтесь)
Вопрос по существу, насколько оправдано юзание dynamic_cast'ов в Qt. И еще есть, как минимум, еще два вида кастов
qdbus_cast,qstyleoption_cast
Использование dynamic_cast-ов в большинстве своем не оправдано. Во-первых сами тролли, если посмотреть по коду, не используют dynamic_cast и RTTI, во-вторых функции RTTI в основном берет на себя Meta System.

Есть еще qgraphicsitem_cast и qscriptvalue_cast, я просто рассмотрел два наиболее мною используемых
хорошо, а как мне лучше тогда такую проблему обойти?
Есть некий абстрактный класс
class ChatViewController
Но его реализация должна представлять собой QWebPage, в итоге получается
class ChatStyleOutput : public QWebPage, public ChatViewController
Таким образом, контроллер невозможно унаследовать от QObject'а, не говоря даже о том, что возможен случай, в котором контроллер просто не будет вообще никаким местом связан с QObject'ом.
В итоге я не могу пользоваться qobject_cast'ами. А без множественного наследования я получаю весьма сложный код.
А зачем вообще в этом случае кастовать «вниз» — от интерфейса к реализации?
Есть контроллер, а есть view для него, фактически нам нужно менять контроллер для view'а. Тот, кто устанавливает контроллера, не должен знать, что за view юзается, а view должен знать что ему за контроллера подсунули. Тут приведение нужно без вариантов.
Нет, ну это всего лишь рекомендация. Следовать ей или нет решать, собственно, программисту, который использует их библиотеку. Если использование dynamic_cast-а необходимо, то его надо использовать.

Такая же ситуация, например, с применением обработки исключений. Трольтех рекомендует проверять возвращаемое значение, но если основная часть кода написана с применением обработки, то имеет смысл не нарушать общий стиль процесса разработки проекта.
Меня больше интересуют возможности обхода этой проблемы Qtшными средствами, чтобы прога работала при выключенном RTTI
а почему в данном случае нельзя использовать static_cast?
А если классы будут в разных библиотеках?
Не принципиально. Если ChatStyleOutput будет лежать в другой библиотеке, то при объявлении класса подключается header-файл. А значит при сборке библиотеки static_cast должен отработать нормально.
Проблему короче решил через Q_INTERFACES путем небольшой переделки API
у меня есть интересные разработки, который использует исключения. так вот там dynamic cast очень много встречается. но так как это использует цикл обработки сообщений — то это не медленно
спасибо, на си++ не пишу, но всегда было интересно, что все это значит
добавлю статью в избранное
Хочу немного дополнить:

1. const_cast также умеет добавлять cv-квалификаторы
2. для преобразования указателей лучше использовать двойной static_cast через void* вместо reinterpret_cast
или вот такой pointer_cast

/// This template functions should be used when we perform cast from one pointer type to another
/// It's safer than using reiterpret_cast
///
/// It doesn't allow to do such things like:
/// int i = 10;
/// A *a = pointer_cast<A*>(i);
/// Only pointer could be used in this function.

template<typename result, typename source>
result pointer_cast(source *v)
{
  return static_cast<result>(static_cast<void*>(v));
}

template<typename result, typename source>
result pointer_cast(const source *v)
{
  return static_cast<result>(static_cast<const void*>(v));
}

спасибо. насчет добавления cv-квалификаторов знал, забыл упомянуть, а про преобразование через void* — отличное пояснение:
> /// It's safer than using reiterpret_cast
>///
>/// It doesn't allow to do such things like:
>/// int i = 10;
>/// A *a = pointer_cast<A*>(i);
>/// Only pointer could be used in this function.
static_cast так же умеет работать со ссылками и указателями, и с любыми типами, содержащими виртуальные члены, например, не обязательно статический тип.
pastebin.org/251996
Разница в работе.
Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации

Истории