Почему Вы не должны расширять JFrame и другие компоненты?

static_cast - это первый бросок, который вы должны попытаться использовать. Он делает такие вещи, как неявные преобразования между типами (например, int - float или указатель на void*), и он также может вызывать явные функции преобразования (или неявные). Во многих случаях явно не указано static_cast, но важно отметить, что синтаксис T(something) эквивалентен (T)something, и его следует избегать (подробнее об этом позже). Однако T(something, something_else) является безопасным и гарантированно вызывает конструктор.

static_cast также может выполняться через иерархии наследования. Это необязательно при бросании вверх (в сторону базового класса), но при отбрасывании вниз его можно использовать до тех пор, пока он не наследует virtual наследование. Однако он не проверяет, и это неопределенное поведение static_cast вниз по иерархии к типу, который на самом деле не является типом объекта.


const_cast может использоваться удалить или добавить const к переменной; ни один другой C ++-способ не способен удалить его (даже не reinterpret_cast). Важно отметить, что изменение ранее значения const не определено, если исходная переменная const; если вы используете его, чтобы удалить const ссылку на то, что не было объявлено с помощью const, это безопасно. Это может быть полезно, например, при перегрузке функций-членов на основе const. Его также можно использовать для добавления const к объекту, например, для вызова перегрузки функции-члена.

const_cast также работает аналогично на volatile, хотя это менее распространено.


dynamic_cast используется почти исключительно для обработки полиморфизма. Вы можете наложить указатель или ссылку на любой полиморфный тип на любой другой тип класса (полиморфный тип имеет хотя бы одну виртуальную функцию, объявленную или унаследованную). Вы можете использовать его больше, чем просто бросать вниз - вы можете бросить боком или даже еще одну цепочку. dynamic_cast будет искать желаемый объект и, если возможно, вернуть его. Если он не может, он вернет nullptr в случае указателя или выбросит std::bad_cast в случае ссылки.

dynamic_cast имеет некоторые ограничения. Это не работает, если в иерархии наследования есть несколько объектов одного типа (так называемый «ужасный бриллиант»), и вы не используете наследование virtual. Он также может проходить только через наследование наследования - он всегда будет не в состоянии пройти через protected или private наследование. Это редко бывает проблемой, так как такие формы наследования встречаются редко.


reinterpret_cast является самым опасным персонажем и его следует использовать очень экономно. Он превращает один тип непосредственно в другой - например, отбрасывая значение от одного указателя к другому или сохраняя указатель в int или всевозможные другие неприятные вещи. Во многом, единственная гарантия, которую вы получаете с reinterpret_cast, состоит в том, что обычно, если вы возвращаете результат обратно к исходному типу, вы получите то же самое значение (но not , если промежуточный тип меньше, чем оригинальный type). Существует ряд преобразований, которые reinterpret_cast также не может сделать. Он используется в первую очередь для особо странных преобразований и манипуляций с битами, таких как превращение потока необработанных данных в фактические данные или хранение данных в младших битах выровненного указателя.


C-style cast and function- стиль cast - это отливки с использованием (type)object или type(object), соответственно. Листинг C-стиля определяется как первое из следующего, которое преуспевает:

  • const_cast
  • static_cast (хотя и игнорирует ограничения доступа)
  • static_cast (см. выше), затем const_cast
  • reinterpret_cast
  • reinterpret_cast, затем const_cast

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

Приведения в стиле C также игнорируют управление доступом при выполнении static_cast, что означает, что у них есть возможность выполнить операцию, которую не может выполнять другая акция. Это, в основном, kludge, и, на мой взгляд, это еще одна причина, чтобы избежать приведения в стиле C.

25
задан Thomas Owens 17 July 2009 в 15:16
поделиться

5 ответов

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

Обычно намерение состоит в том, чтобы строго использовать класс для рисования фрейма, и композиция предпочтительнее наследования.

При этом подклассы должны быть прекрасными, когда вы намереваетесь добавить свой подкласс к фрейму. (такие как удобные методы и т.п.), где подкласс будет использоваться вместо самого фрейма, но использоваться как фрейм в целом, а не как представление определенного фрейма в приложении.

23
ответ дан 28 November 2019 в 21:23
поделиться

Если ваше приложение действительно является JFrame, продолжайте и расширяйте его. Однако лучше использовать композицию объектов, а не наследование, если вы просто используете JFrame.

Если ваш объект расширяет какой-то другой объект, у вас не будет выбора в этом вопросе.

4
ответ дан AlbertoPL 15 October 2019 в 16:43
поделиться

Я знаю, что это старый пост, но я только что натолкнулся на него и должен сказать вам ... расширение ограничило мои возможности вызова определенных действий объекта. Сейчас я переписываю некоторые части кода, чтобы избавиться от нанесенного мне ущерба. Если я не пишу однофайловую программу, я не собираюсь снова использовать расширенный.

0
ответ дан B.K. 15 October 2019 в 16:43
поделиться

Я не вижу проблемы, пока вы расширяете класс и можете сохранить аспекты наследования "is-a".

Когда вы расширяете JPanel, но ваш новый объект не является истинным специализация JPanel, вот где у вас проблемы. Но если вы создадите новый SpecialFormattedJLabel , который расширяет JLabel , я не вижу в этом проблем.

2
ответ дан 28 November 2019 в 21:23
поделиться

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

Компоненты Swing и событийного AWT ужасно сложны. Вы не хотите попасть в этот беспорядок. Вы можете легко случайно переопределить методы. В случаях, когда вам действительно нужно переопределить методы, трудно увидеть, где это делается, если это в обычном коде.

9
ответ дан 28 November 2019 в 21:23
поделиться
Другие вопросы по тегам:

Похожие вопросы: