Форум программистов «Весельчак У»
  *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

  • Рекомендуем проверить настройки временной зоны в вашем профиле (страница "Внешний вид форума", пункт "Часовой пояс:").
  • У нас больше нет рассылок. Если вам приходят письма от наших бывших рассылок mail.ru и subscribe.ru, то знайте, что это не мы рассылаем.
   Начало  
Наши сайты
Помощь Поиск Календарь Почта Войти Регистрация  
 
Страниц: [1]   Вниз
  Печать  
Автор Тема: Зачем .h?  (Прочитано 37189 раз)
0 Пользователей и 7 Гостей смотрят эту тему.
abrahadabra
Интересующийся

gb
Offline Offline
Пол: Женский

« : 08-03-2016 13:38 » 

Вопрос может показаться странным, поэтому чуть поясню.

В принципе, в программировании я уже не первый день, но реальный опыт есть только с вебом, да и знания только по вебу. Соответственно, языки в основном python и javascript. На любом из этих языков для описания класса достаточно одного файла, и сам класс только в одном месте описывается. Более того, даже идеологически приветствуется всё связанное по смыслу держать в одном месте.

А вот в порядке хобби теперь разбираюсь с C++/Qt. Вроде бы прогресс движется, но как-то пока не улавливаю, зачем описание класса делать в двух файлах .h и .cpp. В чём высший смысл такого разделения? В учебниках о таком не пишут, там просто говорят: оно устроено так. Но почему — молчат, собаки! А у меня голова взрывается. Подскажите, пожалуйста, в чём тут дело.
Записан
Алексей++
глобальный и пушистый
Глобальный модератор

ru
Offline Offline
Сообщений: 13


« Ответ #1 : 08-03-2016 14:06 » 

abrahadabra, в идеале - в заголовках описываются прототипы, в cpp - реализация. Никто не запрещает всё описывать в заголовках, а cpp вообще удалить (кроме содержащего main() )

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

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

abrahadabra
Интересующийся

gb
Offline Offline
Пол: Женский

« Ответ #2 : 08-03-2016 14:16 » 

Так вот проблема с пониманием: зачем вообще разделять прототипы и реализацию? И как это влияет на скорость компиляции — тоже совсем непонятно.
Записан
Алексей++
глобальный и пушистый
Глобальный модератор

ru
Offline Offline
Сообщений: 13


« Ответ #3 : 08-03-2016 14:36 » 

abrahadabra, по скорости компиляции - компилируются все файлы cpp , поэтому, если файлов сотня, да в каждом по 20 заголовков, то все заголовки будут скомпилированы повторно 100 раз и столько же раз их код будет включён в модуль

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

вот это не скомпилится
Код:
//.h
class A
{
public:
   A()
   {
        B b;//класс B ещё не описан
   }
};

class B
{
public:
   B()
   {
        A a;
   }
};


а вот это скомпилится

Код:
//AB.h
class A
{
public:
   A();
};

class B
{
public:
   B()
   {
        A a;
   }
};


//AB.cpp
#include "AB.h"
   A::A()
   {
        B b;//класс B описан в "AB.h"
   }

Записан

abrahadabra
Интересующийся

gb
Offline Offline
Пол: Женский

« Ответ #4 : 08-03-2016 14:59 » 

На примере чуть более понятно стало. То есть, в .h просто объявление типов, и компилятор их все читает прежде чем перейти непосредственно к коду, верно? Аналогию проводя, js работает схожим образом: в первый проход выстрагивает в памяти картинку того, с чем предстоит работать: переменные, классы - а затем интерпретирует. Но здесь просто записывается более явно. Так?
Записан
Finch
Спокойный
Администратор

il
Offline Offline
Пол: Мужской
Пролетал мимо


« Ответ #5 : 08-03-2016 17:17 » 

Компиляция проекта проходит в три этапа.
1) Препроцессор. Раскрываются все макросы и включения.
2) Компиляция. Компиляция в объектные фвйлы.
3) Линковка. Сборка всех объектных файлов в единый исполгяемый файл. + разрешение всех зависимостей.
Расмотрим простой проект
A.h
Код: (C++)
#ifndef A_H
#define A_H

class A {
public:
    A();
    ~A();
};

#endif //A_H
A.cpp
Код: (C++)
#include "A.h"

A::A() {
}

A::~A() {
}
B.h
Код: (C++)
#ifndef B_H
#define B_H

#include "A.h"

class B: public A {
public:
    B();
    ~B();
   
};

#endif //B_H
B.cpp
Код: (C++)
#include "B.h"

B::B():A() {
}

B::~B() {
}
main.cpp
Код: (C++)
#include "B.h"

int main() {
    B b;
    return 0;
}
В качестве примера, я покажу, какой код будет подан на компиляцию после препроцессора файла A.cpp
Код: (C++)
class A {
public:
    A();
    ~A();
};


A::A() {
}

A::~A() {
}
Попробуй по аналогии раскрыть два остальных .cpp.
Записан

Не будите спашяго дракона.
             Джаффар (Коша)
Finch
Спокойный
Администратор

il
Offline Offline
Пол: Мужской
Пролетал мимо


« Ответ #6 : 08-03-2016 17:23 » 

abrahadabra, в идеале - в заголовках описываются прототипы, в cpp - реализация. Никто не запрещает всё описывать в заголовках, а cpp вообще удалить (кроме содержащего main() )
Компилятору пофигу абсолютно, файл с каким расширением ему подсовывывается на компиляцию. Самое главное, чтобы был текстовый файл с содержимым программы. Такие ограничение накладывает сама студия. В принципе через Makefile можно собрать проект полностью сделанный на .h файлах. Но это будет один большой WTF при дальшейшей поддержки данного проекта.
« Последнее редактирование: 08-03-2016 17:25 от Finch » Записан

Не будите спашяго дракона.
             Джаффар (Коша)
abrahadabra
Интересующийся

gb
Offline Offline
Пол: Женский

« Ответ #7 : 08-03-2016 18:01 » 

Finch, я правильно понимаю?

После препроцессора компилятор получит b.cpp:

Код:
class A {
public:
    A();
    ~A();
};

class B: public A {
public:
    B();
    ~B();
   
};

B::B():A() {
}

B::~B() {
}

Если правильно понимаю, то смысл в том, что код методов класса A в данном случае компилятору скормлен не будет?
Записан
Finch
Спокойный
Администратор

il
Offline Offline
Пол: Мужской
Пролетал мимо


« Ответ #8 : 08-03-2016 18:06 » 

Да. Компилятор только булет знать, что такой класс сушествует ну и его методы. На третьем этапе, эти зависимости уже слинкуются.
Записан

Не будите спашяго дракона.
             Джаффар (Коша)
abrahadabra
Интересующийся

gb
Offline Offline
Пол: Женский

« Ответ #9 : 08-03-2016 18:14 » 

Но с другой стороны, если рассмотреть аналогичную историю на питоне.

a.py
Код:
class A:
    def __init__(self):
        pass

b.py
Код:
from a import A


class B(A):
    def __init__(self):
        pass

main.py
Код:
from b import B


b = B()

То есть, объявления и реализация не разделены. И это совершенно точно проще для восприятия. При этом повторной интерпретации методов класса A не будет.
Так же и во многих других языках. Вот немножко мозг и взрывается.

То есть, то, что реализация методов отделена от определения класса, стоит просто принять как правило языка, а объяснение этому в порядке компиляции?
Записан
Finch
Спокойный
Администратор

il
Offline Offline
Пол: Мужской
Пролетал мимо


« Ответ #10 : 08-03-2016 18:27 » 

Не путай мягкое с теплым. Питон не компилируется. А интерприируется. Т.е ты не получаеш бинарного кода. Про компиляторы питона я лично не слышал. Соответственно, С++ только компидируется. В питоне для быстроты все нужно хранить как можно компактнее. Для С++ для быстроты компиляции, все нужно хранить как можно рассредоточенее. Чтобы не компилировать одни и теже куски кода по несколько раз. При малейшем изменении.
Записан

Не будите спашяго дракона.
             Джаффар (Коша)
abrahadabra
Интересующийся

gb
Offline Offline
Пол: Женский

« Ответ #11 : 08-03-2016 18:42 » 

Понятное дело, что путать не стоит. Но я почему и упомянула в начале темы, что опыт есть только с вебом и интерпретируемыми языками. И волей-неволей, а что новое изучаешь, то сравниваешь с уже знакомым. Про питон и компиляцию я как-нибудь в другой теме могу немножко рассказать, там тоже не так всё просто, есть и компиляция и кэш и много чего ещё. Если для быстроты, то наверное и утиную типизацию надо отменять.
А если вернуться к C++, то сейчас я так понимаю, что всё, что в этом языке выглядит странным с точки зрения питонщиков, сделано для компилятора, чтобы ему не оставалось простора для фантазии, чтобы он вынужден был бинарник собирать максимально оптимизированным.
Записан
Finch
Спокойный
Администратор

il
Offline Offline
Пол: Мужской
Пролетал мимо


« Ответ #12 : 08-03-2016 18:48 » 

abrahadabra, Компилятор не любит неоднозначности Улыбаюсь Иноглда это вгоняет в тупик. Кстати С++ довольно сложный язык. Можно лет 20 на нем работать, и не разработать всех пластов его возможностей. А их все время добавляют.
Оптимизируется скорость сборки проектов. Если у тебя скажем тысячи файлов в проекте. И собираются несколько бинарников и под разные платформы и в разных сборках. Да еше и юнит тесты собираются. Тут уже скорость очень важна. Я как-то ради интереса собирал у себя из исходников ядро Linux (чистый С + ассемблер) Сборка взяла около 50 минут. И это только для одного таргета.
« Последнее редактирование: 08-03-2016 18:55 от Finch » Записан

Не будите спашяго дракона.
             Джаффар (Коша)
abrahadabra
Интересующийся

gb
Offline Offline
Пол: Женский

« Ответ #13 : 08-03-2016 18:54 » 

Да, видно, что сложный, хотя и только пару недель как знакомлюсь с ним.
Надеюсь, не возражаете, если иногда буду вот такие глупые вопросы задавать. Хочется понять, что это, и как с ним дружить.
Пока очень понравилось, что на уровне языка можно разграничить доступ к свойствам и методам. Статическая типизация тоже понравилась, хотя к ней и привыкать ещё нужно.
Записан
Finch
Спокойный
Администратор

il
Offline Offline
Пол: Мужской
Пролетал мимо


« Ответ #14 : 08-03-2016 18:55 » new

Всегда пожайлуста Улыбаюсь
Записан

Не будите спашяго дракона.
             Джаффар (Коша)
abrahadabra
Интересующийся

gb
Offline Offline
Пол: Женский

« Ответ #15 : 10-03-2016 05:16 » 

Однако же, продолжая играться эту новую для себя тему, нахожу пример: http://doc.qt.io/qt-5/qtsql-books-initdb-h.html
Официальная документация, вроде как достоверный источник. Но как-то… с трудом, что ли в голове укладывается.
Смысл тут таков, что это набор упрощающих жизнь функций строго для данного конкретного проекта. И все в .h-файле.
Это нормальная практика, да?
То есть, что смутило:
  • в .h не объявления, а сам код, реализация.
  • это почему-то не класс, хотя класс тут напрашивается сам собой. Тот же initDb() бы в конструктор
или я где-то чего-то крепко не понимаю?

Ну и ещё такой странный момент, что многовато кода для типовых задач. По опыту тех же Python/Javascript обычно для подобных задач ORMы всяческие используются. А тут просто не принято так?
Записан
Джон
просто
Администратор

de
Offline Offline
Пол: Мужской

« Ответ #16 : 10-03-2016 10:50 » 

abrahadabra, всё дело в подходе - учить С++ по "учебнику" Qt. Это всё-равно, что учить великий и могучий по какому-нить иностранно-русскому разговорнику, или механику по устройству конкретной машины.

Лучше обратиться к первоисточникам. Например к "родителю".

Записан

Я вам что? Дурак? По выходным и праздникам на работе работать. По выходным и праздникам я работаю дома.
"Just because the language allows you to do something does not mean that it’s the correct thing to do." Trey Nash
"Physics is like sex: sure, it may give some practical results, but that's not why we do it." Richard P. Feynman
"All science is either physics or stamp collecting." Ernest Rutherford
"Wer will, findet Wege, wer nicht will, findet Gründe."
Finch
Спокойный
Администратор

il
Offline Offline
Пол: Мужской
Пролетал мимо


« Ответ #17 : 10-03-2016 18:38 » 

С Страуструпа начинать слишком круто. В свое время я тоже пробовал начинать с него. Эта книга хороший справочник. Но не учебник. Где то на форуме уже обсуждались книги по С/С++. \

Вот например одна из веток https://forum.shelek.ru/index.php/topic,27218.0.html
« Последнее редактирование: 10-03-2016 18:44 от Finch » Записан

Не будите спашяго дракона.
             Джаффар (Коша)
Finch
Спокойный
Администратор

il
Offline Offline
Пол: Мужской
Пролетал мимо


« Ответ #18 : 10-03-2016 18:53 » 

abrahadabra, Насчет твоего вопроса. Язык С++ не ограничивает фантазию. Можно писать как дуще угодно. Другое дело, что потом это нужно сопровождать и поддерживать. Вот тогда и будет сыпаться коричневое с неба на такого писателя. Тот код, который ты привела в качестве примера. Скорее всего писался по быстрому на коленке. Только показать пример применения. И не больше этого.
Записан

Не будите спашяго дракона.
             Джаффар (Коша)
Алексей++
глобальный и пушистый
Глобальный модератор

ru
Offline Offline
Сообщений: 13


« Ответ #19 : 11-03-2016 04:55 » 

abrahadabra, там приведён пример вызова функций класса QSqlDatabase , а не пример класса для работы с классом QSqlDatabase ))  Человек должен посмотреть, что за чем следует, затем написать свой код, использующий эти знания
Записан

Джон
просто
Администратор

de
Offline Offline
Пол: Мужской

« Ответ #20 : 11-03-2016 09:51 » 

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

В данном же случае ситуация несколько другая. Человек имеет опыт программирования, поэтому хороший справочник именно то, что нужно.
Записан

Я вам что? Дурак? По выходным и праздникам на работе работать. По выходным и праздникам я работаю дома.
"Just because the language allows you to do something does not mean that it’s the correct thing to do." Trey Nash
"Physics is like sex: sure, it may give some practical results, but that's not why we do it." Richard P. Feynman
"All science is either physics or stamp collecting." Ernest Rutherford
"Wer will, findet Wege, wer nicht will, findet Gründe."
Страниц: [1]   Вверх
  Печать  
 

Powered by SMF 1.1.21 | SMF © 2015, Simple Machines