LINUX.ORG.RU

Почему у меня не работает динамический полиморфизм в C++ ?

 , динамический полиморфизм,


0

2

Имею класс KnowTreeModel, унаследованный от QAbstractItemModel.

Согласно концепции динамического полиморфизма, указатель базового класса может указывать на объект производного. Однако у меня это никогда не получалось:

currentModel=knowTreeView->model();

Error: invalid conversion from 'QAbstractItemModel*' to 'KnowTreeModel*' [-fpermissive]

где:

- currentModel - имеет тип KnowTreeModel*
- knowTreeView->model() - возвращает тип QAbstractItemModel*

И я постоянно пользуюсь static_cast(), чтобы эти типы преобразовывать. Но мне говорят, что этого делать не нужно. А компилятор считает по-другому. Почему так?

★★★★★

Последнее исправление: Wizard_ (всего исправлений: 1)

Потому, что барбара задумала всё не так.

pon4ik ★★★★★
()

Проще говоря - указатель базового класса, может указывать на обьект производного, однако, пока ты работаешь в терминах базового класса ты можешь использовать только интерфейс базового класса.

Иначе - синтаксис бьёт тебя по рукам, и говорит - фу, плохой Xintrea, либо используй двойную диспетчирезацию, либо кушай что дают. Либо, пиши на питоне :)

pon4ik ★★★★★
()
Последнее исправление: pon4ik (всего исправлений: 1)
Ответ на: комментарий от pon4ik

двойную диспетчирезацию

Ну и как в данном случае использовать двойную диспетчеризацию? В обязательном порядке переопределить метод model(), и тогда сработает?

Xintrea ★★★★★
() автор топика

И, алыверды.

В данном случае, если уж у тебя всё выстроенно так угловато, ты можешь получить двойную диспетчирезацию дёшево используя dynamic_cast. static_cast же, позволяет получить тебе ссылку на тыкву, которая банан, хотя - тоже овощь, ну почти, но растение, да.

pon4ik ★★★★★
()
Ответ на: комментарий от pon4ik

И совсем алыверды, раз уж ты используешь (ни приведи боги) Qt - лучше тогда использовать qobject_cast, который до кучи ещё и на QMetaObject в своих изысканиях опирается а не только на рантайм.

pon4ik ★★★★★
()
Ответ на: комментарий от Xintrea

Ты - пытаешься получить ссылку на наследника из ссылки на родителя в рантайме.

Это и есть прямое применение двойной диспетчирезации - получить ссылку, или получить по шаловливым рукам.

См. queryinterface в com - один из самых ярких примеров в истории, самого тупого применения сий методологии.

Суть - правильно обработать запрос через полиморфный интерфейс. В данном случае, запрос есть получение ссылки на обьект интерфейс.

pon4ik ★★★★★
()
Последнее исправление: pon4ik (всего исправлений: 1)

http://www.bogotobogo.com/cplusplus/upcasting_downcasting.php

Используй static_cast если точно уверен в типе, на объект которого указывает твой указатель на базовый класс. В противном случае - только dynamic_cast.

EDIT2: И убедись, что KnowTreeModel известен в точке, где ты делаешь преобразование. Если использовал предварительное объявление ( class KnowTreeModel; ), то компилятор просто не знает, что типы являются родственниками.

m0rph ★★★★★
()
Последнее исправление: m0rph (всего исправлений: 3)
Ответ на: комментарий от Xintrea

Оффтоп

Я вооще тобой восхищаюсь (без стёба).

Ты сделал продукт, но не в теме довольно таки основных весчей, по крайней мере судя по постам на лорчике:)

Если не секрет - сколько камрадов используют поделие?

И сколько фич было реализованно последние 40% от времени всей разработки по сравнению со стартом разработки? По факту - интересует метрика насколько замедлился рост продукта без применения общепринятых методологий.

Лично у меня, иногда закрадывается мнение - что всё это туфта, можно крутить пока не взлетело или не загнулось совсем, а потом нанять толпу индусов на саппорт если таки вышло.

Ещё, интересно соотношение фичереквест/pullrequest.

Ибо другой интересный пример это rtags - тип явно обскакал ycm и прочие аналоги по скорости и юзабилити из коробки. Но дико налажал в архитектуре и торчащих наружу интерфейсах, а щас сидит - решает текущую минорщину, по факту в два лица. И за последние два с половиной месяца, что я за ним наблюдаю - не запилил ни одной фичи. Я сам примерялся к тому, что бы внести изменения которые нужны для интеграции в vim, но понял что надо пару тройку дней ажно потратить, что на опенсурс за который не платят - довольно много.

pon4ik ★★★★★
()
Ответ на: Оффтоп от pon4ik

Ты сделал продукт, но не в теме довольно таки основных весчей, по крайней мере судя по постам на лорчике:)

Так у меня нет профессионального окружения. Обсуждения на лорчике на такое звание не тянут, здесь обсуждаторам плевать, понимает их собеседник или нет.


Если не секрет - сколько камрадов используют поделие?

Понятия не имею, мне никто не докладывает. Неравнодушных по моим подсчетам человек 150 (это те, кто так или иначе мне писал фичреквесты).

Но меня удивляет некто BeImprovised, который в начале года форкнул проект и неистово бомбит изменения: https://github.com/BeImprovised/mytetra_webengine/commits/develop . Правда я пока не могу посмотреть во что превратилась программа, ибо он на Qt 5.6 пишет. Выпущу свой релиз, и попробую собрать этого китайца.


И сколько фич было реализованно последние 40% от времени всей разработки по сравнению со стартом разработки? По факту - интересует метрика насколько замедлился рост продукта без применения общепринятых методологий.

Никак не замедлился, вообще. Но это особенность разработки в одно рыло. Ты можешь делать как знаешь, и как тебе удобно. Ну я конечно пытаюсь оглядываться на то что вокруг происходит, но даже если я применю какую-то методологию, я даже не буду знать, правильно ли я сделал, потому что никого рядом нет, кто бы сказал: вот это ты сделал не кошерно, сматри как нада. Скажу больше, все попытки применить вычитанные приемы/методологии приводили только к торможению проекта и запутыванию кода. И сейчас я не все еще вычистил из-за Qt-Интервьюва вместо нормального MVC, из-за прокси-моделей, которые не пропускают нестандартные методы интерфейса модели, и так далее.


Лично у меня, иногда закрадывается мнение - что всё это туфта, можно крутить пока не взлетело или не загнулось совсем, а потом нанять толпу индусов на саппорт если таки вышло.

Китаец, сделавший форк, показывает что так и есть.

Единственное что, у меня выпуск релиза всегда проходит через стадию глобального изменения кода. То есть, я знаю, какие проблемы накопились (всякие суперклассы например, непоследовательность в реализации схожих объектов или взаимодейсвий объектов), и привожу все к единому виду, дроблю классы по своим умозрительным представлениям. Так вот, оказывается, что принцип «наличие плохой системы гораздо лучше, чем её остутствие» обеспечивает 80% всей разработки. Если стараться сделать все единообразно, то вообще можно не заморачиваться на кривизну дизайна. И на таком принципе можно тянуть до бесконечности: ты обеспечиваешь единообразие кода и периодически подтягиваешь код к своим новым представлениям. Незнаю, насколько большим должен стать проект, чтобы этот метод перестал работать. Сейчас имею ~45 тыщ. строк, пока управляюсь.


Ещё, интересно соотношение фичереквест/pullrequest.

Практически бесконечность. Еще ни одного действительно нужного пуллреквеста ни от кого небыло. Пару раз мне помогли пофиксить багу, недавно я принял от доброго товарища два реквеста на какую-то мелочь, и все.

У меня уже полгода висит примитивная задача на написание всего лишь одного метода: «Очистка форматирования текста в редакторе» - никто не может сделать. Причем, нет никакой завязки на другой код программы - нужно просто знание Qt и класса QTextEdit, не более. Я вообще подумываю: нафига этот OpenSource нужен? Уже так разозлился, что решил не делать релиз, пока кто-нибудь не поможет решить эту задачу.


но понял что надо пару тройку дней ажно потратить, что на опенсурс за который не платят - довольно много.

Я трачу на это годы, просто потому что считаю, что моя программа полезна обществу. Возможно, я самообманываюсь.

Xintrea ★★★★★
() автор топика

you are doing it wrong.

Должно быть:

QAbstractModel *currentModel = knownTreeView->model();
Если тебе вдруг надо вернуться к конкретной реализации KnownTreeModel - возможно что-то у тебя в проекте буквально вывернуто наизнанку и надо переделать.

invy ★★★★★
()

указатель базового класса может указывать на объект производного
currentModel=knowTreeView->model();

Ты указателю класса-наследника присваиваешь указатель на базовый класс. То есть делаешь ровно наоборот

XMs ★★★★★
()
Ответ на: Оффтоп от pon4ik

Я сам примерялся к тому, что бы внести изменения которые нужны для интеграции в vim, но понял что надо пару тройку дней ажно потратить, что на опенсурс за который не платят - довольно много.

А вот я (да и другие пользователи vim) вам сказал бы огромное спасибо. Может все же найдете время и сделаете то, что не осилили разработчики rtags?

andreyu ★★★★★
()
Ответ на: комментарий от andreyu

Если только в отпуске (где то летом). У меня сейчас локально есть подпиленный плагин lyuts'sa в котором работает комплит, но без плюшек типа перехода по аргументам функций и поддержки перегрузок. И работает оно адекватно только в месте с neocomplete (что может и не так уж и плохо).

Упирается всё в выдачу rtags - elisp формат умеет в перегрузки, но не умеет во всё остальное, надо, на стороне rtags сделать выдачу выхлопа completeAt как в питонячем биндинге. Тогда будет простор для плюшек. Альтернатива - допилить elisp выхлоп, но это compatibility break, а перепелить заодно и плагин к эмаксу я не осилю.

В принципе, на мои правки в плагине мне осталось только доку подправить и пулриквест выдать. Но вот когда я залезу в сам rtags, это вилами по воде, там довольно большой обьём работ в силу текущего подхода к проектированию и практически нет тестов.

pon4ik ★★★★★
()
Ответ на: комментарий от Xintrea

Спасибо за ответы.

OpenSource это вообще боль, особенно если поделием пользуется меньше пары тысяч человек или это не что то узкозадростокое написанное на технологии которую юзают те, кто пользуется поделием.

Не думал переписать проект на python? Имхо, там и сообщество поболее, и язык попроще.

Обладая неким опытом, могу заявить что переписать поделку на чём угодно когда точно знаешь как и что должно быть, занимает не так уж и много времени.

pon4ik ★★★★★
()

- knowTreeView->model() - возвращает тип QAbstractItemModel*

Поменяй тип, чтобы возвращал KnowTreeModel*

anonymous
()
Ответ на: комментарий от m0rph

Используй static_cast если точно уверен в типе, на объект которого указывает твой указатель на базовый класс. В противном случае - только dynamic_cast.

Вот я и не пойму. Я точно уверен в типе. А мне компилятор показывает, что не может сконвентировать from 'QAbstractItemModel*' to 'KnowTreeModel*'. А я точно уверен, что KnowTreeModel наследуется от QAbstractItemModel. Значит должен работать динамический полиморфизм.

Вместо этого ты пишешь использовать static_cast/dynamic_cast. С ним то работает. Но мне хочется понять, почему без него не работает. Ведь если в C++ есть динамический полиморфизм, то должно срабатывать без static_cast/dynamic_cast.

Xintrea ★★★★★
() автор топика
Ответ на: Оффтоп от pon4ik

Я вообще тобой восхищаюсь (без стёба).

У меня примерно так же. Всегда пугали большие GUI приложения, все эти колбеки, куча перегруженных виртуальных методов, с которыми нет никакой уверенности в том, что ты именно перегружаешь метод, а не создаёшь новый. Когда увидел объявление о выходе очередной версии его софта, ещё думал, мол, вот молодец, как-то разбирается в этом всём.

С каждой новой темой с вопросами удивление росло и росло. Как? Как можно получить работающий код с неправильными предпосылками? Вот уж упорство, которому можно позавидовать. (Серьёзно).

Вспомнил ещё, как я на лабе сделал правильно работающее задание по семафорам, неправильно понимая их работу. Сидели потом с преподом, разбирались, почему оно вообще работает. Повезло, что преподаватель был не постоянный, а молодой выпускник. Ему тоже было интересно.

i-rinat ★★★★★
()
Ответ на: комментарий от Xintrea

Ведь если в C++ есть динамический полиморфизм, то должно срабатывать без static_cast/dynamic_cast.

У тебя какое-то странное понимание «динамического полиморфизма». Представь такой вот (псевдо) код:

QAbstractItemModel* create() {
    switch (rand(1..3)) {
        case 1: return new KnowTreeModel();
        case 2: return new UnknowTreeModel();
        case 3: return new SomeOtherTreeModel();
    }
}

void main() {
    const auto* model = create();
}
Как компилятор может знать что окажется в model?

DarkEld3r ★★★★★
()
Ответ на: комментарий от Xintrea

Не должен. У тебя KnowTreeModel может содержать доп. поля и методы использующие эти новые поля. Соотв. при касте QAbstractItemModel к KnowTreeModel работа методов, завязанных на уникальные для KnowTreeModel поля, будет нарушена (т.к. нет этих полей в QAbstractItemModel).

Norgat ★★★★★
()
Ответ на: комментарий от pon4ik

Не думал переписать проект на python? Имхо, там и сообщество поболее, и язык попроще.

Тогда уж проще ничего не делать, а просто перейти на OutWicker.

Но дело в том, что я вижу у своей программы потенциал. Во-первых, единая кодовая база для десктопа и Андроида, а это дорогого стоит. На питоне ты такого не получишь. Во-вторых, быстродействие, что тоже для мобильного сегмента важно. В-третьих я сам могу контролировать формат, и потому без оглядки на сторону могу делать Web-сервиса, например MyTetra Share.

Xintrea ★★★★★
() автор топика
Ответ на: комментарий от Xintrea

По поводу производительности - в ПО которое 99% спит пока пройдёт i/o (пользовательский ввод и отрисовка) не важно на чём оно писанно.

Насчёт кроссплатформы - тут нужно смотреть, но я почти уверен есть варианты для скриптоты. Опять же со скриптами проще прыгнуть в web.

Тогда уж проще ничего не делать, а просто перейти на OutWicker.

Главное фан :) Но тогда надо бы тебе плюсы подучить. Пройди курс хоть на том же степике. Неделя времени по паре часов в день, зато многие вещи могут стать понятней.

pon4ik ★★★★★
()
Ответ на: комментарий от DarkEld3r

Как компилятор может знать что окажется в model?

Так компилятору и не нужно знать, что окажется в model. Ему достаточно в ячейку памяти, где хранится указатель, поместить указатель на KnowTreeModel/UnknowTreeModel/SomeOtherTreeModel. Указателю же без разницы, куда указывать. Компилятор в статике должен проверить возможность такого действия, основываясь на наследуемом типе, не более того.

Xintrea ★★★★★
() автор топика
Ответ на: комментарий от Xintrea

Вот я и не пойму. Я точно уверен в типе. А мне компилятор показывает, что не может сконвентировать from 'QAbstractItemModel*' to 'KnowTreeModel*'. А я точно уверен, что KnowTreeModel наследуется от QAbstractItemModel.

Ну это ты точно уверен, а компилятор такой информацией не располагает. Точный тип становится известен только в run-time, а не в compile-time. Поэтому при downcast'е ты должен дать подсказку компилятору.

m0rph ★★★★★
()
Последнее исправление: m0rph (всего исправлений: 1)
Ответ на: комментарий от Xintrea

Ему достаточно в ячейку памяти, где хранится указатель, поместить указатель на KnowTreeModel/UnknowTreeModel/SomeOtherTreeModel.

Да, он это и делает.

Ты же хочешь, чтобы он обратные действия производил. Неужели из кода не понятно почему это невозможно без дополнительных действий в рантайме? Поэтому эти действия и ложатся на тебя.

DarkEld3r ★★★★★
()
Ответ на: комментарий от pon4ik

Пройди курс хоть на том же степике.

Бесполезно. Нужен преподаватель под рукой. Я уже пересмотрел по два раза лекции «Основы C++» с LerktoriumTv https://www.youtube.com/watch?v=atVgLRzl3rI . Но толку нет. У меня куча вопросов по ходу лекции. А кому их задать, стенке что ли?

Смотрим степик: «Программирование на языке C++». Формат курса: Видео-лекции, задачи на программирование. Пусть они себе этот формат в жопу засунут. Придумали дурилку в стиле дистанционного образования и парят мозг окружающим. Ничему они не научат. Проще книжку прочитать, результат будет гораздо лучше.

Вот i-rinat пишет: «Я на лабе сделал правильно работающее задание по семафорам, неправильно понимая их работу. Сидели потом с преподом, разбирались, почему оно вообще работает. Повезло, что преподаватель был не постоянный, а молодой выпускник». На степике никто рядом не сядет и не объяснит что не так. В лучшем случае что-нибудь напишут по емайл. Эффективность от такого обучения минимальна. Мы вот в этом топике вторые сутки разобраться не можем с простым вопросом по динамическому полиморфизму. Потому что нету общения. Так, перестукивание по клавишам.

Xintrea ★★★★★
() автор топика
Ответ на: комментарий от m0rph

А я точно уверен, что KnowTreeModel наследуется от QAbstractItemModel.

Ну это ты точно уверен, а компилятор такой информацией не располагает.

Вот тут поподробней. В чем проблема компилятору увидеть, что один класс наследуется от другого???

Xintrea ★★★★★
() автор топика
Ответ на: комментарий от Xintrea

В чем проблема компилятору увидеть, что один класс наследуется от другого???

Проблема не в этом, а в том, чтобы узнать указатель на какой именно класс-наследник, в данный момент, у нас есть.

DarkEld3r ★★★★★
()
Ответ на: комментарий от Xintrea

Мы вот в этом топике вторые сутки разобраться не можем с простым вопросом по динамическому полиморфизму.

Но тебе же объяснили уже. Потомок наследует интерфейс родителя, поэтому знает родителя; но родитель никак не может знать своих потомков. Когда ты класс-потомок передаёшь в метод, который принимает класс-родитель, ты уничтожаешь информацию о типе объекта. Если потом нужно преобразовать обратно, используется dynamic_cast<>, который может обломаться, так как типы проверяются во время исполнения, а не во время компиляции.

i-rinat ★★★★★
()
Ответ на: комментарий от Xintrea

В чем проблема компилятору увидеть, что один класс наследуется от другого???

В этом проблемы нет. Проблема — увидеть всех потомков одного класса.

i-rinat ★★★★★
()
Ответ на: комментарий от i-rinat

Потомок наследует интерфейс родителя, поэтому знает родителя;

Ты хотел сказать: «Потомок наследует интерфейс родителя, поэтому знает класс родителя», правильно? Но тут вопрос в другом: кто должен знать класс родителя: потомок или компилятор?


но родитель никак не может знать своих потомков.

А в чем проблема? И тут тот же самый вопрос: кто должен знать классы потомков: родитель или компилятор?


Когда ты класс-потомок передаёшь в метод, который принимает класс-родитель, ты уничтожаешь информацию о типе объекта.

Ты, наверно хотел сказать объекты-потомки? В методы передаются объекты, а не классы. А класс - это тип.


Если потом нужно преобразовать обратно, используется dynamic_cast<>, который может обломаться, так как типы проверяются во время исполнения, а не во время компиляции.

Ты мне порвал весь шаблон. Что значит «может»? Может преобразуется тип, а может и нет, так что ли? Разве можно так жить?

Xintrea ★★★★★
() автор топика
Ответ на: комментарий от Xintrea

Что значит «может»?

Это и значит.

struct Base { virtual ~Base() {} };
struct A : Base { virtual ~A() {} };
struct B : Base { virtual ~B() {} };

void main() {
    Base* p = new B();
    auto* pa = dynamic_cast<A*>(p); // pa == nullptr
    auto& ra = dynamic_cast<A&>(*p); // exception
}

DarkEld3r ★★★★★
()
Последнее исправление: DarkEld3r (всего исправлений: 2)
Ответ на: комментарий от Xintrea

На степике или курсере можно и с преподавателем. На степике надо ловить момент, когда курс перезапустят.

Насчёт формата - сначала попробуй а потом плюйся (любым удобным местом :) ). Я для знакомых неофитов его смотрел - там тип дельно рассказывает, и задачи хорошо подобранны. Там формат вброс/вопрос/ответ. С интервалами от 2 до 15 минут примерно. Почти как на лекции.

Раз в полгода курсы перезапускают и можно с толпой вместе поспрашивать препода в том числе. Раз в год делают подборочку (правда она там платная, чет 15к вроде стоит) на год там тебе препод будет больше времени уделять.

pon4ik ★★★★★
()
Ответ на: комментарий от Xintrea

В догонку - на степике только один адекватный курс по крестам (имхо, и без обид мэйл ру и прочие). От этот, от csc.

pon4ik ★★★★★
()
Ответ на: комментарий от DarkEld3r

Неужели из кода не понятно почему это невозможно без дополнительных действий в рантайме? Поэтому эти действия и ложатся на тебя.

Хорошо, давай поставим вопрос по другому. По теме топика (а не по твоему примеру с рандомом).

Вот я проверил, и у меня компилится:

KnowTreeModel* currentModel=static_cast<KnowTreeModel*>( knowTreeView->model() );

То есть, даже в статике есть возможность преобразовать QAbstractItemModel* к KnowTreeModel*. Тем более что у них отношения родитель-ребенок.

Вопрос. Почему компилер не может закомпилить конструкцию:
KnowTreeModel* currentModel=knowTreeView->model();

Что ему мешает увидеть целевой тип KnowTreeModel*, и преобразовать из QAbstractItemModel*?

И второй вопрос: какого хрена тогда мне парили мозг, что касты не нужны в обсуждении, на которое я дал ссылку в топике: Почему сегфолт в деструкторе? (комментарий).

Xintrea ★★★★★
() автор топика
Ответ на: комментарий от Xintrea

Почему компилер не может закомпилить конструкцию

Выше уже было написано, указателю на родителя можно присваивать указатели на потомков, но не наоборот. KnowTreeModel* — это указатель на потомка QAbstractModel*, такое присваивание не разрешено без явного приведения типа. Наоборот можно:

QAbstractModel *cm = knowTreeView->model();

bormant ★★★★★
()
Ответ на: комментарий от Xintrea

потомок или компилятор?

Странный вопрос. Компилятор, наверное. Тут важно понимать, что компилятор обрабатывает по одному файлу за раз. Когда в файле объявлен класс-потомок, ты так или иначе обязан включить определение класса-родителя, обычно include'ом. Иначе не соберётся. То есть компилятор всегда знает всех родителей твоего класса. Но так как потомки класса-родителя могут быть объявлены в других файлах, информации о потомках при компиляции класса-родителя просто нет. То есть каким бы умным не был компилятор, он не может угадать то, чего не видит. (Ну а вдруг ты скомпилировал класс-родитель, а уже потом создал исходник с классом-потомком.)

А в чем проблема?

А в том, что ты хочешь указатель на объект класса-родителя преобразовать в указатель на объект класса-потомка.

Ты, наверно хотел сказать объекты-потомки?

На C++ в этом всё равно нет неоднозначности.

Что значит «может»? Может преобразуется тип, а может и нет, так что ли? Разве можно так жить?

Ну вот так. А может кинуть исключение std::bad_cast.

Жить так можно, потому что без dynamic_cast<> можно вполне обойтись, если спроектировать систему по-другому. Если тебе нужно стереть информацию о типе, чтобы потом массово выполнять какое-то действие, просто создаёшь виртуальный метод, а в потомках его переопределяешь. Тогда на обезличенных объектах просто дёргаешь этот метод и всё.

i-rinat ★★★★★
()
Ответ на: комментарий от bormant

Ты навел меня на мысль. Тут оказывается вообще касты не нужны.

Срабатывает и так:

knowTreeModel=(KnowTreeModel*)( knowTreeView->model() );

Тогда возникает другой вопрос: нафига нужны static_cast(), если по-сути они дублируют явное приведение типа?

Xintrea ★★★★★
() автор топика
Ответ на: комментарий от Xintrea

вообще касты не нужны.
Срабатывает и так:
(KnowTreeModel*)( knowTreeView->model() )
нафига нужны static_cast(), если по-сути они дублируют явное приведение типа?

Жесть.

anonymous
()
Ответ на: комментарий от Xintrea

Что ему мешает увидеть целевой тип KnowTreeModel*, и преобразовать из QAbstractItemModel*?

Потому что компилятор разрешает только те преобразования, которые гарантированно пройдут без проблем. А если в процессе преобразования возможны проблемы, он их запрещает. В твоём model() может лежать что угодно, KnownTreeModel или UnknownTreeModel или FooBarTreeModel или что-нибудь ещё. Все эти классы являются наследниками AbstractTreeModel и может быть ещё 50 других классов, про которые компилятор ещё не знает. Поэтому такое преобразование ни в коем случае не может быть безопасным. Оно опасно и компилятор его запрещает без явного указания того, что ты хочешь его сделать. Вот если ты настаиваешь, то компилятор сгенерирует нужный код и ты получишь переменную нужного типа и будешь делать с ней что угодно.

Ещё надо делать различие между static_cast и dynamic_cast. Первый тебе гарантированно вернёт какой-то указатель. Только если твоя model() вернула не KnownTreeModel а что-нибудь другое, то в твоей программе скорее всего начнёт твориться кавардак. А вот dynamic_cast умеет проверять тип. Из-за этого у него более сложная реализация, зато ты можешь быть уверен, что он тебе вернёт объект именно этого типа (или NULL).

Ещё надо добавить, что такие downcast-ы (приведение от типа родителя к типу потомка) является признаком неправильной архитектуры. Это может быть обусловлено неправильной архитектурой Qt, а может быть неправильной архитектурой твоего кода.

Legioner ★★★★★
()
Ответ на: комментарий от anonymous

Жесть.

Ага.

Оказывается, явное приведение типа через скобки оставлено для совместимости. Обычные скобки заменила конструкция:

static_cast<ИмяТипа>( Переменная )


Громоздкие ключевые слова являются напоминанием программисту о том, что приведение типа чревато проблемами.

«Крики жены будут напоминать вам крики чаек на пляже».

Xintrea ★★★★★
() автор топика
Ответ на: комментарий от Xintrea

Вот тут поподробней. В чем проблема компилятору увидеть, что один класс наследуется от другого???

В том, что он оперирует указателем на объект. Какого конкретно типа объект там на самом деле неизвестно. Например, ты можешь заполнить вектор кучей указателей на базовый класс, котораы на самом деле ссылаются на конкретные (и разные) производные классы. Вектор заполняется во время работы программы и более того, каждый раз он может заполняться по разному. В такой ситуации компилятор никаким образом не может узнать, что там будет в рантайме.

m0rph ★★★★★
()
Ответ на: комментарий от Xintrea

Громоздкие ключевые слова являются напоминанием программисту о том, что приведение типа чревато проблемами.

Где ты вычитал такую глупость? Тот, кто пишет, и так это знает.

Эти преобразования нужны другим программистам, которые код рецензируют или просто читают. Их видно, их легко найти в исходниках обычным текстовым поиском. Попробуй найди си-стайл касты.

i-rinat ★★★★★
()
Ответ на: комментарий от Xintrea

У меня такое ощущение, что всё это пишется людьми, которые пишут и читают только учебный код на пару сотен строк максимум. Не спорю, суть производимых действий они понимают. Причём, скорее всего, гораздо глубже, чем её когда-либо буду понимать я. Но вот с изоляцией сложности, и вообще с пониманием того, почему надо изолировать сложность, у них абсолютные нелады.

i-rinat ★★★★★
()
Ответ на: комментарий от Xintrea

То есть, даже в статике есть возможность преобразовать QAbstractItemModel* к KnowTreeModel*.

Что значит «даже в статике»? В этом коде ты говоришь «я обещают, что по указателю лежит KnowTreeModel» и компилятор тебе верит. Попробуй передать туда другого наследника - код тоже скомпилится, но в рантайме будет сюрприз.

И второй вопрос: какого хрена тогда мне парили мозг, что касты не нужны в обсуждении, на которое я дал ссылку в топике

Всё читать лень, дай ссылку на конкретное сообщение - попробую ответить.

DarkEld3r ★★★★★
()
Последнее исправление: DarkEld3r (всего исправлений: 1)
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.