![]() |
Здравствуйте, гость ( Вход | Регистрация )
![]() ![]() |
![]() |
dsp |
![]()
Сообщение
#1
|
Студент ![]() Группа: Участник Сообщений: 51 Регистрация: 12.10.2010 Пользователь №: 2109 Спасибо сказали: 4 раз(а) Репутация: ![]() ![]() ![]() |
Подскажи пожалуйста.
В разных примерах программ на Qt классы виджетов не добавляются через инклуд т.е. ,а пишутся так:
и т.д. с чем это связано? и что использовать? |
|
|
Алексей1153 |
![]()
Сообщение
#2
|
![]() фрилансер ![]() ![]() ![]() ![]() ![]() ![]() Группа: Участник Сообщений: 2944 Регистрация: 19.6.2010 Из: Обливион Пользователь №: 1822 Спасибо сказали: 215 раз(а) Репутация: ![]() ![]() ![]() |
это форварды (предопределения) классов для возможности применить паттерн проектирования pimpl (pointer to implementation) . Правда, форварды и не только для этого используются.
А упомянутый паттерн имеет и плюсы, и минусы, поэтому совсем бездумно каждый раз повсюду применять не стоит ) Нормальную статью я с ходу не нашёл. Поищи в тырнете , почитай |
|
|
igor_bogomolov |
![]()
Сообщение
#3
|
Профессионал ![]() ![]() ![]() ![]() ![]() Группа: Сомодератор Сообщений: 1215 Регистрация: 22.3.2009 Из: Саратов Пользователь №: 630 Спасибо сказали: 235 раз(а) Репутация: ![]() ![]() ![]() |
Это называется "предварительное объявление классов". Делается что бы снизить зависимость между файлами при компиляции и тем самым ускорить саму компиляцию.
Т.е. правило такое, везде где только можно используйте предварительное объявление. В заголовочном файле (.h) часто ничего не нужно знать о классе, кроме того что он существует. Поэтому делается предварительное объявление класса class QPushButton. А вот в файле реализации (.cpp), уже подключаются подробности #include <QPushButton> |
|
|
Litkevich Yuriy |
![]()
Сообщение
#4
|
![]() разработчик РЭА ![]() ![]() ![]() ![]() ![]() ![]() ![]() Группа: Сомодератор Сообщений: 9669 Регистрация: 9.1.2008 Из: Тюмень Пользователь №: 64 Спасибо сказали: 807 раз(а) Репутация: ![]() ![]() ![]() |
Существенная оговорка.
Предварительное объявление годится только в случае, если в заголовочнике объявляется ссылка или указатель на некий класс. Тогда компилятору достаточно сказать "такой-то класс действительно существует". Т.к. и ссылка и указатель на данной конкретной платформе всегда одинаковое кол-во байт занимает. Если же ты используешь класс для наследования, или для создания переменной на стеке (обычной) или используешь члены некого класса, то придётся использовать инклюд. Иначе компилятор не будет ничего знать об особенностях класса. Примеры, когда без инклюда нельзя
|
|
|
Алексей1153 |
![]()
Сообщение
#5
|
![]() фрилансер ![]() ![]() ![]() ![]() ![]() ![]() Группа: Участник Сообщений: 2944 Регистрация: 19.6.2010 Из: Обливион Пользователь №: 1822 Спасибо сказали: 215 раз(а) Репутация: ![]() ![]() ![]() |
Цитата(dsp @ 9.2.2011, 2:14) Link class VS #include блин, я долго думал, при чём тут студия ![]() Цитата(Litkevich Yuriy @ 9.2.2011, 8:19) Link Если же ты используешь класс для наследования, или для создания переменной на стеке (обычной) или используешь члены некого класса, то придётся использовать инклюд. ...но при суровой необходимости и это можно обойти ![]() |
|
|
Litkevich Yuriy |
![]()
Сообщение
#6
|
![]() разработчик РЭА ![]() ![]() ![]() ![]() ![]() ![]() ![]() Группа: Сомодератор Сообщений: 9669 Регистрация: 9.1.2008 Из: Тюмень Пользователь №: 64 Спасибо сказали: 807 раз(а) Репутация: ![]() ![]() ![]() |
Цитата(Алексей1153 @ 9.2.2011, 11:03) Link .но при суровой необходимости и это можно обойти как?
|
|
|
Алексей1153 |
![]()
Сообщение
#7
|
![]() фрилансер ![]() ![]() ![]() ![]() ![]() ![]() Группа: Участник Сообщений: 2944 Регистрация: 19.6.2010 Из: Обливион Пользователь №: 1822 Спасибо сказали: 215 раз(а) Репутация: ![]() ![]() ![]() |
Litkevich Yuriy,
например так хотим класс QMyLineEdit:public QLineEdit QMyLineEdit.h
QMyLineEdit.cpp
но тут есть один жёсткий минус - для всех нужных функций нужно будет делать эти трамплины |
|
|
kwisp |
![]()
Сообщение
#8
|
![]() астарожна ынтжинэр ![]() ![]() ![]() ![]() ![]() Группа: Участник Сообщений: 1404 Регистрация: 26.11.2008 Из: ТаганрогРодинаЧехова Пользователь №: 435 Спасибо сказали: 113 раз(а) Репутация: ![]() ![]() ![]() |
Цитата(Litkevich Yuriy @ 9.2.2011, 20:40) Link как? проще говоря, дублированием интерфейса. в заголовочнике только класс с указателем внутри и форвардом класса этого указателя, а так же все желаемые методы продублированы. в cpp наследуешься, а в реализации дублирующих методов вызываешь соответсвующие методы наследника. пример: допустим ты хочешь спрятать наследование в срр файл. заголовочник iface.h
реализация
|
|
|
Rocky |
![]()
Сообщение
#9
|
Старейший участник ![]() ![]() ![]() ![]() Группа: Участник Сообщений: 530 Регистрация: 22.12.2008 Из: Санкт-Петербург Пользователь №: 463 Спасибо сказали: 22 раз(а) Репутация: ![]() ![]() ![]() |
Цитата(Алексей1153 @ 9.2.2011, 10:03) Link Цитата(Litkevich Yuriy) Если же ты используешь класс для наследования, или для создания переменной на стеке (обычной) или используешь члены некого класса, то придётся использовать инклюд. ...но при суровой необходимости и это можно обойти Если класс используется для наследования (и далее по тексту), хидер включать необходимо. И легальными средствами имхо это не обойти. Компилятор должен обладать информацией о том, что это за класс. Может я жестко туплю конечно, либо придираюсь... А в чем приведенный код Алексей1153, kwisp, позволяет обойти то, о чем говорит Litkevich Yuriy? То что вы приводите, называется паттерн проектирования пимпл - ака идиома скрытой реализации. Мне кажется это не есть обход в том смысле в котором имеется ввиду. Ведь можно не создавать объект на стеке в капсуле класса, а использовать указатель на него. Наследование можно опять-таки заменить через указатель (практически всегда). И тогда тоже не нужно будет подключать хидер с капсулой класса в своем хидере. Вопрос ведь какой, как сделать так, чтобы при наследовании или создании объекта класса на стеке не нужно было включать хидер класса. Держу пари что как-то можно. Но схоу не могу сообразить. Вероятно, тут будет что-то из жесткого хака (типа define private public)... |
|
|
Алексей1153 |
![]()
Сообщение
#10
|
![]() фрилансер ![]() ![]() ![]() ![]() ![]() ![]() Группа: Участник Сообщений: 2944 Регистрация: 19.6.2010 Из: Обливион Пользователь №: 1822 Спасибо сказали: 215 раз(а) Репутация: ![]() ![]() ![]() |
Rocky,
Цитата(Rocky @ 10.2.2011, 13:28) Link хидер включать необходимо да, но включать его надо уже только в файл реализации ![]() Цитата(Rocky @ 10.2.2011, 13:28) Link А в чем приведенный код Алексей1153, kwisp, позволяет обойти а обходить в данном случае не нужно. Это было сказано о случае СУРОВОЙ необходимости )) То есть - костыль Цитата(Rocky @ 10.2.2011, 13:28) Link Наследование можно опять-таки заменить через указатель (практически всегда). оу, расскажи, как ?. Особенное внимание удели конструктору, деструктору и виртуальным функциям Сообщение отредактировал Алексей1153 - 10.2.2011, 11:34 |
|
|
Rocky |
![]()
Сообщение
#11
|
Старейший участник ![]() ![]() ![]() ![]() Группа: Участник Сообщений: 530 Регистрация: 22.12.2008 Из: Санкт-Петербург Пользователь №: 463 Спасибо сказали: 22 раз(а) Репутация: ![]() ![]() ![]() |
Цитата(Алексей1153 @ 10.2.2011, 12:33) Link Цитата(Rocky @ 10.2.2011, 13:28) * хидер включать необходимо да, но включать его надо уже только в файл реализации Алексей1153, ты вырываешь слова из контекста. Если есть класс В, который наследуется от класса А, то хидер класса А обязательно нужно включать в хидере класса В. То что пишешь ты - да. Но если ты будешь наследоваться от QMyLineEditWrapper - тебе опять-таки нужно будет включение хидера с этой структурой. От этого никуда не уйти. А как я понял твою задумку, то что ты сделал - это ответ на вопрос Цитата(Алексей1153 @ 10.2.2011, 12:33) Link Цитата('я') Наследование можно опять-таки заменить через указатель (практически всегда). оу, расскажи, как ?. из которого следует, что да, в этом случае достаточно будет предварительного объявления. Но это не обход Цитата Если есть класс В, который наследуется от класса А, то хидер класса А обязательно нужно включать в хидере класса В это обход наследования. А в случае, если тебе нужно делать override функций базовых классов (virtual), то тут да, нужно наследоваться. Просто есть люди, которые где надо и не надо лепят наследование, думая, что без него никак. Вообще по этому вопросу советую оч хорошую книжку...То-ли Александреску, то-ли Саттера... Щас не вспомню, нужно дома посмотреть. Там вобщем рассказно оч подробно как делать всякие интересные штуки. Хотя, вероятно я придираюсь к словам ![]() |
|
|
Алексей1153 |
![]()
Сообщение
#12
|
![]() фрилансер ![]() ![]() ![]() ![]() ![]() ![]() Группа: Участник Сообщений: 2944 Регистрация: 19.6.2010 Из: Обливион Пользователь №: 1822 Спасибо сказали: 215 раз(а) Репутация: ![]() ![]() ![]() |
Цитата(Rocky @ 10.2.2011, 13:51) Link Алексей1153, ты вырываешь слова из контекста да нет, не вырываю. Ты , во-первых, сам их жирным выделил. Ну а включать надо - это факт ![]() Цель пимпла: сделать содержимое хидера реально видимым только в файле реализации. Это его единственный плюс (но как раз он иногда требуется). А вот если у тебя есть большой массив элементов, и ты вдруг захотел сделать его массивом указателей, а класс ячейки засунул по паттерну pimpl в реализацию, то тут сильно проиграешь в скорости работы и фрагментации кучи. Поэтому в этом случае лучше разместить в реализации весь массив как единый объект и дописать интерфейсные методы для работы с ним извне Цитата(Rocky @ 10.2.2011, 13:51) Link Просто есть люди, которые где надо и не надо лепят наследование, думая, что без него никак ну, по затратам памяти и скорости (кхм) наследование абсолютно ничем не отличается от включения мембера с классом, какой был бы у класса-родителя. Но тут становится недоступен или труднодоступен полифорфизм |
|
|
igor_bogomolov |
![]()
Сообщение
#13
|
Профессионал ![]() ![]() ![]() ![]() ![]() Группа: Сомодератор Сообщений: 1215 Регистрация: 22.3.2009 Из: Саратов Пользователь №: 630 Спасибо сказали: 235 раз(а) Репутация: ![]() ![]() ![]() |
to Алексей1153
Цитата(Litkevich Yuriy @ 9.2.2011, 6:19) Link Если же ты используешь класс для наследования, или для создания переменной на стеке (обычной) или используешь члены некого класса, то придётся использовать инклюд. Иначе компилятор не будет ничего знать об особенностях класса. Цитата(Алексей1153 @ 10.2.2011, 8:16) Link
Юрий пытался объяснить ТС при каких условиях можно использовать предварительное объявление, при каких нет. Ты же как как всегда перевернул всё с ног на голову. to Алексей1153, to kwisp Да в пимпл без предварительного объявления никуда, и поговорить про это интересно. Вот только ТС спрашивал не про это. Тут скорее можно было написать, что в некоторых случаях без предварительного объявления не обойтись, и показать это на примере пимпла. А вот говорить что можно отнаследоваться от класса class QMyLineEdit:public QLineEdit не сделав в том же файле includ не правильно. to Алексей1153 Цитата Цель пимпла: сделать содержимое хидера реально видимым только в файле реализации Ты путаешь цели и средства достижения цели. То о чем ты говоришь - это средство/способ решения, а цели у пимпла другие.
|
|
|
Rocky |
![]()
Сообщение
#14
|
Старейший участник ![]() ![]() ![]() ![]() Группа: Участник Сообщений: 530 Регистрация: 22.12.2008 Из: Санкт-Петербург Пользователь №: 463 Спасибо сказали: 22 раз(а) Репутация: ![]() ![]() ![]() |
igor_bogomolov, спасибо, хоть ты понял что я пытался сказать
![]() |
|
|
Алексей1153 |
![]()
Сообщение
#15
|
![]() фрилансер ![]() ![]() ![]() ![]() ![]() ![]() Группа: Участник Сообщений: 2944 Регистрация: 19.6.2010 Из: Обливион Пользователь №: 1822 Спасибо сказали: 215 раз(а) Репутация: ![]() ![]() ![]() |
igor_bogomolov, мы просто напросто в ненужные дебри полезли )) А в целом не всё так трагично, как ты воспринимаешь
|
|
|
kwisp |
![]()
Сообщение
#16
|
![]() астарожна ынтжинэр ![]() ![]() ![]() ![]() ![]() Группа: Участник Сообщений: 1404 Регистрация: 26.11.2008 Из: ТаганрогРодинаЧехова Пользователь №: 435 Спасибо сказали: 113 раз(а) Репутация: ![]() ![]() ![]() |
по-моему вы ребята уже предвзято к друг другу относитесь. это по градусу сообщения видно.
![]() опять же по-моему ТС разницу между форвардами и инклюдами понял. цель достигнута. это хорошо. П.С. что касается моего ответа. Юрию, я наверное действительно не понял, что в точности он спрашивал, и в ответе написал как уйти от включения заголовочника в заголовочник.... |
|
|
Алексей1153 |
![]()
Сообщение
#17
|
![]() фрилансер ![]() ![]() ![]() ![]() ![]() ![]() Группа: Участник Сообщений: 2944 Регистрация: 19.6.2010 Из: Обливион Пользователь №: 1822 Спасибо сказали: 215 раз(а) Репутация: ![]() ![]() ![]() |
Цитата(kwisp @ 11.2.2011, 12:58) Link по-моему вы ребята уже предвзято к друг другу относитесь ни грамма )) |
|
|
Litkevich Yuriy |
![]()
Сообщение
#18
|
![]() разработчик РЭА ![]() ![]() ![]() ![]() ![]() ![]() ![]() Группа: Сомодератор Сообщений: 9669 Регистрация: 9.1.2008 Из: Тюмень Пользователь №: 64 Спасибо сказали: 807 раз(а) Репутация: ![]() ![]() ![]() |
Резюме:
Если класс наследник другого, то заголовочник от базового всё равно нужно включать. И т.д. Т.е. те ограничения которые я написал, будут действовать всегда и для всех описанных случаев. |
|
|
![]() ![]() ![]() |
![]() |
|
Текстовая версия | Сейчас: 23.8.2025, 19:24 |