crossplatform.ru

Здравствуйте, гость ( Вход | Регистрация )

2 страниц V   1 2 >  
Ответить в данную темуНачать новую тему
dsp
  опции профиля:
сообщение 9.2.2011, 0:14
Сообщение #1


Студент
*

Группа: Участник
Сообщений: 51
Регистрация: 12.10.2010
Пользователь №: 2109

Спасибо сказали: 4 раз(а)




Репутация:   0  


Подскажи пожалуйста.
В разных примерах программ на Qt классы виджетов не добавляются через инклуд

т.е.

#include <QPushButton>
#include <QLabel>
,

а пишутся так:

class QPushButton;
class QLabel;


и т.д.

с чем это связано? и что использовать?
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
Алексей1153
  опции профиля:
сообщение 9.2.2011, 0:31
Сообщение #2


фрилансер
******

Группа: Участник
Сообщений: 2944
Регистрация: 19.6.2010
Из: Обливион
Пользователь №: 1822

Спасибо сказали: 215 раз(а)




Репутация:   34  


это форварды (предопределения) классов для возможности применить паттерн проектирования pimpl (pointer to implementation) . Правда, форварды и не только для этого используются.

А упомянутый паттерн имеет и плюсы, и минусы, поэтому совсем бездумно каждый раз повсюду применять не стоит )

Нормальную статью я с ходу не нашёл. Поищи в тырнете , почитай
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
igor_bogomolov
  опции профиля:
сообщение 9.2.2011, 0:39
Сообщение #3


Профессионал
*****

Группа: Сомодератор
Сообщений: 1215
Регистрация: 22.3.2009
Из: Саратов
Пользователь №: 630

Спасибо сказали: 235 раз(а)




Репутация:   29  


Это называется "предварительное объявление классов". Делается что бы снизить зависимость между файлами при компиляции и тем самым ускорить саму компиляцию.
Т.е. правило такое, везде где только можно используйте предварительное объявление.

В заголовочном файле (.h) часто ничего не нужно знать о классе, кроме того что он существует.
Поэтому делается предварительное объявление класса class QPushButton.
А вот в файле реализации (.cpp), уже подключаются подробности #include <QPushButton>
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
Litkevich Yuriy
  опции профиля:
сообщение 9.2.2011, 6:19
Сообщение #4


разработчик РЭА
*******

Группа: Сомодератор
Сообщений: 9669
Регистрация: 9.1.2008
Из: Тюмень
Пользователь №: 64

Спасибо сказали: 807 раз(а)




Репутация:   94  


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

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

Примеры, когда без инклюда нельзя
#include <SameClass>

class SubClass : public SameClass
{

...
}
#include <SameClass>

class MyClass
{
...
private:
SameClass var;
}
#include <SameClass>

class MyClass
{
...
public:
    SameClass func_1(); // возвращает значение
    
    func_2(SameClass var); // принимает значение
}
#include <SameClass>

class MyClass
{
...
public:
    SameClass func_1(SameClass *var)
    {
        var->method(); // обращение к члену класса
    }
}
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
Алексей1153
  опции профиля:
сообщение 9.2.2011, 9:03
Сообщение #5


фрилансер
******

Группа: Участник
Сообщений: 2944
Регистрация: 19.6.2010
Из: Обливион
Пользователь №: 1822

Спасибо сказали: 215 раз(а)




Репутация:   34  


Цитата(dsp @ 9.2.2011, 2:14) Link
class VS #include

блин, я долго думал, при чём тут студия :D А "versus" пишется маленькими буквами

Цитата(Litkevich Yuriy @ 9.2.2011, 8:19) Link
Если же ты используешь класс для наследования, или для создания переменной на стеке (обычной) или используешь члены некого класса, то придётся использовать инклюд.

...но при суровой необходимости и это можно обойти :)
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
Litkevich Yuriy
  опции профиля:
сообщение 9.2.2011, 20:40
Сообщение #6


разработчик РЭА
*******

Группа: Сомодератор
Сообщений: 9669
Регистрация: 9.1.2008
Из: Тюмень
Пользователь №: 64

Спасибо сказали: 807 раз(а)




Репутация:   94  


Цитата(Алексей1153 @ 9.2.2011, 11:03) Link
.но при суровой необходимости и это можно обойти
как?
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
Алексей1153
  опции профиля:
сообщение 10.2.2011, 8:16
Сообщение #7


фрилансер
******

Группа: Участник
Сообщений: 2944
Регистрация: 19.6.2010
Из: Обливион
Пользователь №: 1822

Спасибо сказали: 215 раз(а)




Репутация:   34  


Litkevich Yuriy,

например так
хотим класс QMyLineEdit:public QLineEdit

QMyLineEdit.h
class QMyLineEdit;

struct QMyLineEditWrapper
{
   QMyLineEdit* p;
   QMyLineEditWrapper(QWidget* parent=0);
};



QMyLineEdit.cpp
#include "QMyLineEdit.h"
#include <QLineEdit>

class QMyLineEdit:public QLineEdit
{
    Q_OBJECT
public:
    explicit QMyLineEdit(QWidget* parent=0):QLineEdit(parent)
    {
    }
    
    QString text() const;//"трамплин"
};

struct QMyLineEditWrapper
{
   QMyLineEdit* p;
   QMyLineEditWrapper(QWidget* parent):p(new QMyLineEdit(parent))
   {
   }
   
   ~QMyLineEditWrapper()
   {
       delete p;
   }
      
   QString text() const
   {
       return p->text();
   }
};


но тут есть один жёсткий минус - для всех нужных функций нужно будет делать эти трамплины
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
kwisp
  опции профиля:
сообщение 10.2.2011, 10:29
Сообщение #8


астарожна ынтжинэр
*****

Группа: Участник
Сообщений: 1404
Регистрация: 26.11.2008
Из: ТаганрогРодинаЧехова
Пользователь №: 435

Спасибо сказали: 113 раз(а)




Репутация:   23  


Цитата(Litkevich Yuriy @ 9.2.2011, 20:40) Link
как?

проще говоря, дублированием интерфейса.
в заголовочнике только класс с указателем внутри и форвардом класса этого указателя, а так же все желаемые методы продублированы. в cpp наследуешься, а в реализации дублирующих методов вызываешь соответсвующие методы наследника.
пример: допустим ты хочешь спрятать наследование в срр файл.
заголовочник iface.h
class CImpl;

class IFace
{
  CImpl* impl_;

public:
  IFace();
  ~IFace();

void one();
void two();
void three();

};


реализация
# include "iface.h"

class CImpl : public Anything
{
public:
void one();
void two();
void three();
};

void  IFace::one()
{
  return impl_->one();
}

void IFace::two()
{
  return impl_->two();
}

void IFace::three()
{
  return impl_->three();
}


Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
Rocky
  опции профиля:
сообщение 10.2.2011, 11:28
Сообщение #9


Старейший участник
****

Группа: Участник
Сообщений: 530
Регистрация: 22.12.2008
Из: Санкт-Петербург
Пользователь №: 463

Спасибо сказали: 22 раз(а)




Репутация:   7  


Цитата(Алексей1153 @ 9.2.2011, 10:03) Link
Цитата(Litkevich Yuriy)

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

...но при суровой необходимости и это можно обойти

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

Может я жестко туплю конечно, либо придираюсь... А в чем приведенный код Алексей1153, kwisp, позволяет обойти то, о чем говорит Litkevich Yuriy? То что вы приводите, называется паттерн проектирования пимпл - ака идиома скрытой реализации. Мне кажется это не есть обход в том смысле в котором имеется ввиду.

Ведь можно не создавать объект на стеке в капсуле класса, а использовать указатель на него. Наследование можно опять-таки заменить через указатель (практически всегда). И тогда тоже не нужно будет подключать хидер с капсулой класса в своем хидере. Вопрос ведь какой, как сделать так, чтобы при наследовании или создании объекта класса на стеке не нужно было включать хидер класса. Держу пари что как-то можно. Но схоу не могу сообразить. Вероятно, тут будет что-то из жесткого хака (типа define private public)...
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
Алексей1153
  опции профиля:
сообщение 10.2.2011, 11:33
Сообщение #10


фрилансер
******

Группа: Участник
Сообщений: 2944
Регистрация: 19.6.2010
Из: Обливион
Пользователь №: 1822

Спасибо сказали: 215 раз(а)




Репутация:   34  


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
  опции профиля:
сообщение 10.2.2011, 11:51
Сообщение #11


Старейший участник
****

Группа: Участник
Сообщений: 530
Регистрация: 22.12.2008
Из: Санкт-Петербург
Пользователь №: 463

Спасибо сказали: 22 раз(а)




Репутация:   7  


Цитата(Алексей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
  опции профиля:
сообщение 10.2.2011, 12:21
Сообщение #12


фрилансер
******

Группа: Участник
Сообщений: 2944
Регистрация: 19.6.2010
Из: Обливион
Пользователь №: 1822

Спасибо сказали: 215 раз(а)




Репутация:   34  


Цитата(Rocky @ 10.2.2011, 13:51) Link
Алексей1153, ты вырываешь слова из контекста

да нет, не вырываю. Ты , во-первых, сам их жирным выделил. Ну а включать надо - это факт :) вопрос в том - куда включать. Где хидер будет виден только локально, либо же торчать повсюду

Цель пимпла: сделать содержимое хидера реально видимым только в файле реализации. Это его единственный плюс (но как раз он иногда требуется).
А вот если у тебя есть большой массив элементов, и ты вдруг захотел сделать его массивом указателей, а класс ячейки засунул по паттерну pimpl в реализацию, то тут сильно проиграешь в скорости работы и фрагментации кучи. Поэтому в этом случае лучше разместить в реализации весь массив как единый объект и дописать интерфейсные методы для работы с ним извне

Цитата(Rocky @ 10.2.2011, 13:51) Link
Просто есть люди, которые где надо и не надо лепят наследование, думая, что без него никак

ну, по затратам памяти и скорости (кхм) наследование абсолютно ничем не отличается от включения мембера с классом, какой был бы у класса-родителя. Но тут становится недоступен или труднодоступен полифорфизм
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
igor_bogomolov
  опции профиля:
сообщение 10.2.2011, 19:34
Сообщение #13


Профессионал
*****

Группа: Сомодератор
Сообщений: 1215
Регистрация: 22.3.2009
Из: Саратов
Пользователь №: 630

Спасибо сказали: 235 раз(а)




Репутация:   29  


to Алексей1153
Цитата(Litkevich Yuriy @ 9.2.2011, 6:19) Link
Если же ты используешь класс для наследования, или для создания переменной на стеке (обычной) или используешь члены некого класса, то придётся использовать инклюд. Иначе компилятор не будет ничего знать об особенностях класса.
Цитата(Алексей1153 @ 10.2.2011, 8:16) Link
class QMyLineEdit;
struct QMyLineEditWrapper 
{    
    QMyLineEdit* p;    
    QMyLineEditWrapper(QWidget* parent=0); 
};
Не увидел в приведенном коде не наследования, ни создания переменной на стеке ни использования членов другого класса.
Юрий пытался объяснить ТС при каких условиях можно использовать предварительное объявление, при каких нет. Ты же как как всегда перевернул всё с ног на голову.

to Алексей1153, to kwisp
Да в пимпл без предварительного объявления никуда, и поговорить про это интересно. Вот только ТС спрашивал не про это.
Тут скорее можно было написать, что в некоторых случаях без предварительного объявления не обойтись, и показать это на примере пимпла. А вот говорить что можно отнаследоваться от класса class QMyLineEdit:public QLineEdit не сделав в том же файле includ не правильно.

to Алексей1153
Цитата
Цель пимпла: сделать содержимое хидера реально видимым только в файле реализации
Ты путаешь цели и средства достижения цели. То о чем ты говоришь - это средство/способ решения, а цели у пимпла другие.
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
Rocky
  опции профиля:
сообщение 10.2.2011, 20:04
Сообщение #14


Старейший участник
****

Группа: Участник
Сообщений: 530
Регистрация: 22.12.2008
Из: Санкт-Петербург
Пользователь №: 463

Спасибо сказали: 22 раз(а)




Репутация:   7  


igor_bogomolov, спасибо, хоть ты понял что я пытался сказать :)
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
Алексей1153
  опции профиля:
сообщение 10.2.2011, 20:10
Сообщение #15


фрилансер
******

Группа: Участник
Сообщений: 2944
Регистрация: 19.6.2010
Из: Обливион
Пользователь №: 1822

Спасибо сказали: 215 раз(а)




Репутация:   34  


igor_bogomolov, мы просто напросто в ненужные дебри полезли )) А в целом не всё так трагично, как ты воспринимаешь
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
kwisp
  опции профиля:
сообщение 11.2.2011, 10:58
Сообщение #16


астарожна ынтжинэр
*****

Группа: Участник
Сообщений: 1404
Регистрация: 26.11.2008
Из: ТаганрогРодинаЧехова
Пользователь №: 435

Спасибо сказали: 113 раз(а)




Репутация:   23  


по-моему вы ребята уже предвзято к друг другу относитесь. это по градусу сообщения видно. :)
опять же по-моему ТС разницу между форвардами и инклюдами понял. цель достигнута. это хорошо.

П.С.
что касается моего ответа. Юрию, я наверное действительно не понял, что в точности он спрашивал, и в ответе написал как уйти от включения заголовочника в заголовочник....

Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
Алексей1153
  опции профиля:
сообщение 11.2.2011, 11:22
Сообщение #17


фрилансер
******

Группа: Участник
Сообщений: 2944
Регистрация: 19.6.2010
Из: Обливион
Пользователь №: 1822

Спасибо сказали: 215 раз(а)




Репутация:   34  


Цитата(kwisp @ 11.2.2011, 12:58) Link
по-моему вы ребята уже предвзято к друг другу относитесь

ни грамма ))
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
Litkevich Yuriy
  опции профиля:
сообщение 12.2.2011, 12:47
Сообщение #18


разработчик РЭА
*******

Группа: Сомодератор
Сообщений: 9669
Регистрация: 9.1.2008
Из: Тюмень
Пользователь №: 64

Спасибо сказали: 807 раз(а)




Репутация:   94  


Резюме:
Если класс наследник другого, то заголовочник от базового всё равно нужно включать. И т.д.
Т.е. те ограничения которые я написал, будут действовать всегда и для всех описанных случаев.
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение

2 страниц V   1 2 >
Быстрый ответОтветить в данную темуНачать новую тему
Теги
Нет тегов для показа


1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0


RSS Рейтинг@Mail.ru Текстовая версия Сейчас: 23.8.2025, 19:24