Форум программистов, компьютерный форум CyberForum.ru

Правильное подключение заголовочных файлов - C++

Восстановить пароль Регистрация
 
 
Рейтинг: Рейтинг темы: голосов - 30, средняя оценка - 4.63
deniska91
54 / 3 / 3
Регистрация: 17.05.2014
Сообщений: 72
04.08.2014, 22:22     Правильное подключение заголовочных файлов #1
Как подключать заголовочные файлы я знаю, но вот у меня есть вопрос, ответ на который я нигде не видел, не видел даже рекомендаций как правильней писать. А ситуация следующая: Допустим у нас есть два класса - one.h (one.cpp) и two.h (two.cpp). В two.h подключен заголовочный файл one.h. А в one.h подключен допустим библиотечный файл iostream. Так вот вопрос, если в two.cpp я хочу воспользоваться одной из функций файла iostream нужно ли мне и в этом классе подключать этот файл? Ведь по сути класс two.h видит iostream через one.h или все таки каждый класс должен быть в этом плане независим от других классов?

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

Ну и если есть книги, рассматривающие подобные вопросы архитектуры кода, подскажите плиз)


Заранее благодарен!
Лучшие ответы (1)
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
04.08.2014, 22:22     Правильное подключение заголовочных файлов
Посмотрите здесь:

C++ Подключение заголовочных файлов
Подключение заголовочных файлов C++
C++ Перекрестное подключение заголовочных файлов
Подключение заголовочных файлов. C++
Подключение заголовочных файлов C++
После регистрации реклама в сообщениях будет скрыта и будут доступны все возможности форума.
-=ЮрА=-
Заблокирован
Автор FAQ
04.08.2014, 22:30     Правильное подключение заголовочных файлов #2
deniska91, сделай заголовочный файл к примеру standerdincl.h пропиши там все стандартные хедеры а в самом верху #pragma once не забудь и потом прописівай первім инклудом в других файлах standerdincl.h

standerdincl
C++
1
2
3
#pragma once
#include <iostream>
using namspace std;
one.h
C++
1
2
3
4
#pragma once
#include "standerdincl.h"
 
class cOne{};
two.h
C++
1
2
3
4
5
#pragma once
#include "standerdincl.h"
#include "one.h"//если класс 2 зависит от первого
 
class cTwo{};
Добавлено через 1 минуту
Для чего так - тот кто будет разбирать листинг всегда будет видеть что есть подключение стандартных хедеров
прагмы - чтобы хедеры подключались лишь единожды и не было ошибок аля
бла бла бла already defined
stima
429 / 284 / 16
Регистрация: 22.03.2011
Сообщений: 923
Завершенные тесты: 1
04.08.2014, 22:31     Правильное подключение заголовочных файлов #3
Цитата Сообщение от deniska91 Посмотреть сообщение
Так вот вопрос, если в two.cpp я хочу воспользоваться одной из функций файла iostream нужно ли мне и в этом классе подключать этот файл? Ведь по сути класс two.h видит iostream через one.h или все таки каждый класс должен быть в этом плане независим от других классов?
Зависит от реализации one и two. Если two является логическим продолжением, то можно и через one подключить общий хедер. Если нет, то по моему, лучше отдельно. Хотя это все условно.

Цитата Сообщение от deniska91 Посмотреть сообщение
И второй вопрос по этой же части. Если я использую функции файла iostream в файле реализации (и нет никаких намеков на это в заголовочном файле), так может вообще нужно подключать файл iostream не в two.h, а в two.cpp.
Да. Это предпочтительней.
Цитата Сообщение от deniska91 Посмотреть сообщение
Ну и если есть книги, рассматривающие подобные вопросы архитектуры кода, подскажите плиз)
Вообще, такое придет с опытом, выработается собственный или будет навязан общий стиль. Лучше почитать более практические вещи, заодно и посмотрите как другие делают.
deniska91
54 / 3 / 3
Регистрация: 17.05.2014
Сообщений: 72
04.08.2014, 22:32  [ТС]     Правильное подключение заголовочных файлов #4
-=ЮрА=-, Спасибо за быстрый ответ. В данном случае iostream я привел для примера, вместо него может быть 3 собственный класс three.h к примеру. Как тогда поступать в этом случае?
-=ЮрА=-
Заблокирован
Автор FAQ
04.08.2014, 22:35     Правильное подключение заголовочных файлов #5
Цитата Сообщение от deniska91 Посмотреть сообщение
вместо него может быть 3 собственный класс three.h к примеру. Как тогда поступать в этом случае?
- если три нужен всем другим классам и кроме него больше ничего то замени
Цитата Сообщение от -=ЮрА=- Посмотреть сообщение
#pragma once
#include "tree.h"
- прагма не даст произойти множественному подключению и как я уже сказал избежать ошибки с типом "уже объявлено"
Опять е тот кто будет читать твой код будет знать что действительно нужно классу а не рыскать по цепочкам хедеров
deniska91
54 / 3 / 3
Регистрация: 17.05.2014
Сообщений: 72
04.08.2014, 22:42  [ТС]     Правильное подключение заголовочных файлов #6
stima, спасибо за ответ.
Цитата Сообщение от stima Посмотреть сообщение
Лучше почитать более практические вещи
Вы имеете ввиду книги или исходники? Я стараюсь просматривать С++ проекты на github, хотя это дается с трудом.

Добавлено через 3 минуты
-=ЮрА=-, по поводу директивы #pragma once я знаю. Меня интересовал вопрос правильности с точки зрения архитектуры программирования.
stima
429 / 284 / 16
Регистрация: 22.03.2011
Сообщений: 923
Завершенные тесты: 1
04.08.2014, 22:50     Правильное подключение заголовочных файлов #7
Книги. Читать код, тем более не смежного проекта, трудно да и не зачем.

п.с. Пользуйтесь принципом простоты (KISS).
Убежденный
Системный программист
 Аватар для Убежденный
14183 / 6198 / 984
Регистрация: 02.05.2013
Сообщений: 10,324
Завершенные тесты: 1
04.08.2014, 23:06     Правильное подключение заголовочных файлов #8
Сообщение было отмечено автором темы, экспертом или модератором как ответ
Цитата Сообщение от deniska91 Посмотреть сообщение
И второй вопрос по этой же части. Если я использую функции файла iostream в файле реализации (и нет никаких намеков на это в заголовочном файле), так может вообще нужно подключать файл iostream не в two.h, а в two.cpp.
Разумеется !
Это снижает зависимости, а еще может существенно повлиять на время сборки проекта.
Один глобальный хидер, в который включено все, что можно - это обычно бывает хорошо
лишь в специфических ситуациях, например если используются precompiled headers.
В остальных случаях лучше не плодить ненужных включений заголовков, особенно если в
какой-то конкретной единице трансляции они вообще не используются.
-=ЮрА=-
04.08.2014, 23:54
  #9

Не по теме:

Убежденный, честно странно слышать такое от системного программиста под ВИН.
Создал классы и закинул в stdafx.h хедерами - вместо предлагаемого в одном h-нике податтачил то в другом другое а в третьем и рад бы и первое и второе так нет в каком то из классов алреади дефайнд. И выходит месиво из перекрёстных и повторных включений...
Особенно для окон это ж*па.

Убежденный
Системный программист
 Аватар для Убежденный
14183 / 6198 / 984
Регистрация: 02.05.2013
Сообщений: 10,324
Завершенные тесты: 1
05.08.2014, 10:08     Правильное подключение заголовочных файлов #10
Никакого месива здесь нет. Заголовки подключаются только туда, где они реально нужны.
Простейший пример привел автор: в two.h описан интерфейс класса, а two.cpp включает
<iostream> и все остальное, что необходимо для реализации. Клиенты класса вообще
"не в курсе", что используется в файле реализации, и это хорошо - нет лишних
зависимостей, а главное, на мой взгляд - снижение времени компиляции, причем оно
может быть существенным. Из личного опыта: проект собирался где-то 20 минут, но
после редизайна инклудов это время сократилось примерно до 4-6 минут. Впрочем,
если ты используешь stdafx.h и прекомпилированные заголовки, тут другая картина.

Что касается already defined и перекрестных/повторных включений - я не понял.
Есть же pragma once. От того, что один и тот же заголовок неявно включен в два
или более файлов внутри одной единицы трансляции, ошибок не будет.
Ну или приведи пример, при котором ошибки такого плана могут возникать.

P.S.
Кстати, раньше я всегда делал один большой заголовок и по мере написания проекта
включал в него все, что требуется. Ни к чему хорошему, кроме увеличения времени
компиляции и постоянных пересборках при малейших изменениях в нем (т.к. зависимости
лезут во все файлы) это не привело.
krv
71 / 51 / 11
Регистрация: 10.07.2014
Сообщений: 328
05.08.2014, 11:01     Правильное подключение заголовочных файлов #11
Всегда считал что обрамление в хедере (пример uMain.h)
C++
1
2
3
4
#ifndef uMainH
#define uMainH
...
#endif
приводит к однократному включению хедера для компилятора
только препроцессор больше пашет и время компиляции само собой.
Чем отличается от этого кода #pragma once?
SatanaXIII
Супер-модератор
Эксперт С++
 Аватар для SatanaXIII
5547 / 2561 / 233
Регистрация: 01.11.2011
Сообщений: 6,330
Завершенные тесты: 1
05.08.2014, 11:08     Правильное подключение заголовочных файлов #12
Цитата Сообщение от krv Посмотреть сообщение
Чем отличается от этого кода #pragma once?
Тем, что pragma once не все компиляторы поддерживают.
И вообще тут разговор идет в .cpp или в .h включать всю эту хренотень.
Evg
Эксперт С++Автор FAQ
 Аватар для Evg
16824 / 5245 / 320
Регистрация: 30.03.2009
Сообщений: 14,125
Записей в блоге: 26
05.08.2014, 11:18     Правильное подключение заголовочных файлов #13
Цитата Сообщение от Убежденный Посмотреть сообщение
Разумеется !
Это снижает зависимости, а еще может существенно повлиять на время сборки проекта.
Один глобальный хидер, в который включено все, что можно - это обычно бывает хорошо
лишь в специфических ситуациях, например если используются precompiled headers.
В остальных случаях лучше не плодить ненужных включений заголовков, особенно если в
какой-то конкретной единице трансляции они вообще не используются.
+1

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

Формировать один файл, который является свалкой для подключения системных хидеров - это порочная практика. Она годится только на начальных уровнях обучения программированию, чтобы не тратить время на вкуривание того, как правильно проектировать программу. Когда выходишь на более-менее серьёзный уровень программирования, то от таких вещей надо отказываться. Особенно для языка Си++, т.к. в стандартных хидерах идут огромные описания шаблонных классов и функций. Если в каждый модуль программы бездумно будет подключаться по 20 заголовочных файлов (через один общий файл-свалку), то для каждого модуля компилятор будет тратить время на пережёвывание всего того барахла, которое растёт из этих файлов, в то время как всё это барахло в реальности оказывается ненужным
krv
71 / 51 / 11
Регистрация: 10.07.2014
Сообщений: 328
05.08.2014, 11:20     Правильное подключение заголовочных файлов #14
Чем позже включать, тем лучше. Если есть возможность в .cpp - лучше конечно. Меньше зависимостей. Ну и архитектурное решение - где что описывать и как распределять по файлам - самое главное...
Evg
Эксперт С++Автор FAQ
 Аватар для Evg
16824 / 5245 / 320
Регистрация: 30.03.2009
Сообщений: 14,125
Записей в блоге: 26
05.08.2014, 11:25     Правильное подключение заголовочных файлов #15
Цитата Сообщение от krv Посмотреть сообщение
Чем позже включать, тем лучше. Если есть возможность в .cpp - лучше конечно
Не всегда правильно. Возьмём такой пример

C++
/* Файл module.cpp */
#include <iostream>
#include "module.h"
 
...
C++
/* Файл module.h */
class MyClass
{
...
  void method (void)
  {
    std::cout << "hello";
  }
...
};
Втащив инклюд в *.cpp мы получили модуль, который сам по себе компилируется. Но вот пользователи модуля (те, которые подключают module.h), имеют шанс обломаться на компиляции (если у себя они не подключают iostream).

Т.е. ответ на вопрос, где именно писать инклюды, сложно дать формальным образом. Всё зависит от того, как у тебя устроена программа
SatanaXIII
Супер-модератор
Эксперт С++
 Аватар для SatanaXIII
5547 / 2561 / 233
Регистрация: 01.11.2011
Сообщений: 6,330
Завершенные тесты: 1
05.08.2014, 11:47     Правильное подключение заголовочных файлов #16
Evg, Убежденный, и в особенности хотелось бы послушать мнение славного -=ЮрА=-, такой конкретный пример:
есть множество классов, выполненных своими отдельными .h и .cpp файлами. И есть другое множество программных модулей, использующих эти классы. Хороша (или не знаю как выразиться) ли следующая реализация их подключения: переписать все файлы используемых классов в отдельный .h файл, который потом подключить в каждом .cpp файле каждого модуля. При чем не все классы используются в каждом модуле, а только лишь часть, и данная реализация позволяет не выписывать каждый требуемый класс в новый создаваемый модуль, а лишь подключать суммирующий заголовок. Какие у нее сильные/слабые стороны?
Evg
Эксперт С++Автор FAQ
 Аватар для Evg
16824 / 5245 / 320
Регистрация: 30.03.2009
Сообщений: 14,125
Записей в блоге: 26
05.08.2014, 12:44     Правильное подключение заголовочных файлов #17
Любое разделение на отдельные файлы в первую очередь должно носить идеологический характер и только потом технический. Крайности типа "свалить всё в один файл" или "завести на каждый чих отдельный файл" тоже не уместны. Если ты в один *.h файл свалишь классы "треугольник", "квадрат" и "пятиугольник" - это нормальная ситуация. Если ты в один *.h файл свалишь классы "треугольник", "сотрудник офиса" и "барабан" - это будет выглядеть весьма сомнительно

Добавлено через 30 минут
Да, ещё один "бонус" от использования свалки с инклюдами. Предположим, у нас есть проект с 1000 файлов *.cpp. Есть хидер module.h. Из 1000 файлов только 3 файла в реальности потребляют module.h. Но, благодаря наносистеме из одного чудо-хидера, получается, что module.h подцепляется во все 1000 файлов проекта. Далее при изменении в module.h у нас идёт перекомпиляция всех 1000 файлов, хотя при нормальном подходе перекомпилировалось бы только 3 файла
deniska91
05.08.2014, 14:47  [ТС]
  #18

Не по теме:

Спасибо всем за ответы на мой вопрос

-=ЮрА=-
05.08.2014, 21:11
  #19

Не по теме:

...Мы написали 15 классов, некоторые с зависмостями от предыдущих. Мы хотим собрать один большой окнный проект, взаимодействуя между диалогами через указатели на объекты классов. Когда я вижу подобное подключение хедера

C++
1
2
#include "MyCustomcontrol.h"
class CustomDlg : public CDialog
(а в срр никак не закинуть т.к контрол нужен в диалоге. Мне хочется такому человеку отрубить руку и запретить писать. Глобальный файл дефайнов и хедеров имеет место быть.
А ещё больше нравится когда выкручиваются и делают неполное объявление класса
C++
1
2
class CCustomcontrol;
class CustomDlg : public CDialog
- такой народ хочется вообще стрелять.
Да иногда можно обойтись полумерами и подключать лишь то что необходимо, НО такое работает лишь до определённой сложности проекта, а потом начинаются повторные инклуды полотен хедеров, которых легко можно было бы избежать подключив всё в stdafx.h либо подобном по значению файле.
Если из вашего опыта вы не встречались с ситуациями когда проект просто нечитабелен из за постоянного беганья по цепочкам хедеров, то я рад за вас, но это ещё ничего не значит...
На счёт времени компиляции - с современными то аппаратными средствами на него вообще можно забить отдав предпочтение понятности и элеганстности листинга.

MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
05.08.2014, 23:41     Правильное подключение заголовочных файлов
Еще ссылки по теме:

Правильное подключение заголовочных файлов C++
Подключение заголовочных файлов C++
Правильное включение заголовочных файлов C++

Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
winnisp
 Аватар для winnisp
0 / 0 / 0
Регистрация: 10.09.2012
Сообщений: 25
05.08.2014, 23:41     Правильное подключение заголовочных файлов #20
Цитата Сообщение от deniska91 Посмотреть сообщение
Как подключать заголовочные файлы я знаю, но вот у меня есть вопрос, ответ на который я нигде не видел, не видел даже рекомендаций как правильней писать.
Вроде бы уже люди все объяснили, но всеже добавлю. Книга Скотта Майерса "Эффективное использование С++" третье издание.
Правило 31: Уменьшайте зависимости файлов при компиляции.
В правиле затрагивается данный вопрос и подробно разбираются причины, но лучше не поленится и прочесть книгу полностью, ибо все советы просветляют разум и наделяют кучей экспириенса)
Yandex
Объявления
05.08.2014, 23:41     Правильное подключение заголовочных файлов
Ответ Создать тему
Опции темы

Текущее время: 02:58. Часовой пояс GMT +3.
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2016, vBulletin Solutions, Inc.
Рейтинг@Mail.ru