Форум программистов, компьютерный форум, киберфорум
С++ для начинающих
Войти
Регистрация
Восстановить пароль
Карта форума Темы раздела Блоги Сообщество Поиск Заказать работу  
 
 
Рейтинг 4.78/131: Рейтинг темы: голосов - 131, средняя оценка - 4.78
54 / 3 / 2
Регистрация: 17.05.2014
Сообщений: 72
1

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

04.08.2014, 22:22. Показов 25591. Ответов 20
Метки нет (Все метки)

Author24 — интернет-сервис помощи студентам
Как подключать заголовочные файлы я знаю, но вот у меня есть вопрос, ответ на который я нигде не видел, не видел даже рекомендаций как правильней писать. А ситуация следующая: Допустим у нас есть два класса - 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.

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


Заранее благодарен!
0
Лучшие ответы (1)
Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
04.08.2014, 22:22
Ответы с готовыми решениями:

Правильное подключение заголовочных файлов
Всем привет!!!Начал разбираться с ООП , и ... тут же возникла проблема. Пишу программу следующую ...

Правильное включение заголовочных файлов
Привет, хочу задать такой вопрос. У меня есть классы в файлах Menu.h, Options.h, About.h, Game.h,...

Подключение заголовочных файлов
Здравствуйте. Возникают ошибки при компиляции проекта: 1. Указывает на указатель: 2. Указывает...

Подключение заголовочных файлов
Итересует меня вопрос : нужно ли при компиляции программ оставлять только нужные хэдеры ? т.е. их...

20
Заблокирован
Автор 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
0
503 / 352 / 94
Регистрация: 22.03.2011
Сообщений: 1,112
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 Посмотреть сообщение
Ну и если есть книги, рассматривающие подобные вопросы архитектуры кода, подскажите плиз)
Вообще, такое придет с опытом, выработается собственный или будет навязан общий стиль. Лучше почитать более практические вещи, заодно и посмотрите как другие делают.
1
54 / 3 / 2
Регистрация: 17.05.2014
Сообщений: 72
04.08.2014, 22:32  [ТС] 4
-=ЮрА=-, Спасибо за быстрый ответ. В данном случае iostream я привел для примера, вместо него может быть 3 собственный класс three.h к примеру. Как тогда поступать в этом случае?
0
Заблокирован
Автор FAQ
04.08.2014, 22:35 5
Цитата Сообщение от deniska91 Посмотреть сообщение
вместо него может быть 3 собственный класс three.h к примеру. Как тогда поступать в этом случае?
- если три нужен всем другим классам и кроме него больше ничего то замени
Цитата Сообщение от -=ЮрА=- Посмотреть сообщение
#pragma once
#include "tree.h"
- прагма не даст произойти множественному подключению и как я уже сказал избежать ошибки с типом "уже объявлено"
Опять е тот кто будет читать твой код будет знать что действительно нужно классу а не рыскать по цепочкам хедеров
1
54 / 3 / 2
Регистрация: 17.05.2014
Сообщений: 72
04.08.2014, 22:42  [ТС] 6
stima, спасибо за ответ.
Цитата Сообщение от stima Посмотреть сообщение
Лучше почитать более практические вещи
Вы имеете ввиду книги или исходники? Я стараюсь просматривать С++ проекты на github, хотя это дается с трудом.

Добавлено через 3 минуты
-=ЮрА=-, по поводу директивы #pragma once я знаю. Меня интересовал вопрос правильности с точки зрения архитектуры программирования.
0
503 / 352 / 94
Регистрация: 22.03.2011
Сообщений: 1,112
04.08.2014, 22:50 7
Книги. Читать код, тем более не смежного проекта, трудно да и не зачем.

п.с. Пользуйтесь принципом простоты (KISS).
1
Ушел с форума
Эксперт С++
16473 / 7436 / 1187
Регистрация: 02.05.2013
Сообщений: 11,617
Записей в блоге: 1
04.08.2014, 23:06 8
Лучший ответ Сообщение было отмечено deniska91 как решение

Решение

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

Не по теме:

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

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

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

P.S.
Кстати, раньше я всегда делал один большой заголовок и по мере написания проекта
включал в него все, что требуется. Ни к чему хорошему, кроме увеличения времени
компиляции и постоянных пересборках при малейших изменениях в нем (т.к. зависимости
лезут во все файлы) это не привело.
0
74 / 54 / 17
Регистрация: 10.07.2014
Сообщений: 329
05.08.2014, 11:01 11
Всегда считал что обрамление в хедере (пример uMain.h)
C++
1
2
3
4
#ifndef uMainH
#define uMainH
...
#endif
приводит к однократному включению хедера для компилятора
только препроцессор больше пашет и время компиляции само собой.
Чем отличается от этого кода #pragma once?
0
Почетный модератор
Эксперт С++
5850 / 2861 / 392
Регистрация: 01.11.2011
Сообщений: 6,907
05.08.2014, 11:08 12
Цитата Сообщение от krv Посмотреть сообщение
Чем отличается от этого кода #pragma once?
Тем, что pragma once не все компиляторы поддерживают.
И вообще тут разговор идет в .cpp или в .h включать всю эту хренотень.
0
Evg
Эксперт CАвтор FAQ
21279 / 8301 / 637
Регистрация: 30.03.2009
Сообщений: 22,659
Записей в блоге: 30
05.08.2014, 11:18 13
Цитата Сообщение от Убежденный Посмотреть сообщение
Разумеется !
Это снижает зависимости, а еще может существенно повлиять на время сборки проекта.
Один глобальный хидер, в который включено все, что можно - это обычно бывает хорошо
лишь в специфических ситуациях, например если используются precompiled headers.
В остальных случаях лучше не плодить ненужных включений заголовков, особенно если в
какой-то конкретной единице трансляции они вообще не используются.
+1

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

Формировать один файл, который является свалкой для подключения системных хидеров - это порочная практика. Она годится только на начальных уровнях обучения программированию, чтобы не тратить время на вкуривание того, как правильно проектировать программу. Когда выходишь на более-менее серьёзный уровень программирования, то от таких вещей надо отказываться. Особенно для языка Си++, т.к. в стандартных хидерах идут огромные описания шаблонных классов и функций. Если в каждый модуль программы бездумно будет подключаться по 20 заголовочных файлов (через один общий файл-свалку), то для каждого модуля компилятор будет тратить время на пережёвывание всего того барахла, которое растёт из этих файлов, в то время как всё это барахло в реальности оказывается ненужным
1
74 / 54 / 17
Регистрация: 10.07.2014
Сообщений: 329
05.08.2014, 11:20 14
Чем позже включать, тем лучше. Если есть возможность в .cpp - лучше конечно. Меньше зависимостей. Ну и архитектурное решение - где что описывать и как распределять по файлам - самое главное...
0
Evg
Эксперт CАвтор FAQ
21279 / 8301 / 637
Регистрация: 30.03.2009
Сообщений: 22,659
Записей в блоге: 30
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).

Т.е. ответ на вопрос, где именно писать инклюды, сложно дать формальным образом. Всё зависит от того, как у тебя устроена программа
0
Почетный модератор
Эксперт С++
5850 / 2861 / 392
Регистрация: 01.11.2011
Сообщений: 6,907
05.08.2014, 11:47 16
Evg, Убежденный, и в особенности хотелось бы послушать мнение славного -=ЮрА=-, такой конкретный пример:
есть множество классов, выполненных своими отдельными .h и .cpp файлами. И есть другое множество программных модулей, использующих эти классы. Хороша (или не знаю как выразиться) ли следующая реализация их подключения: переписать все файлы используемых классов в отдельный .h файл, который потом подключить в каждом .cpp файле каждого модуля. При чем не все классы используются в каждом модуле, а только лишь часть, и данная реализация позволяет не выписывать каждый требуемый класс в новый создаваемый модуль, а лишь подключать суммирующий заголовок. Какие у нее сильные/слабые стороны?
0
Evg
Эксперт CАвтор FAQ
21279 / 8301 / 637
Регистрация: 30.03.2009
Сообщений: 22,659
Записей в блоге: 30
05.08.2014, 12:44 17
Любое разделение на отдельные файлы в первую очередь должно носить идеологический характер и только потом технический. Крайности типа "свалить всё в один файл" или "завести на каждый чих отдельный файл" тоже не уместны. Если ты в один *.h файл свалишь классы "треугольник", "квадрат" и "пятиугольник" - это нормальная ситуация. Если ты в один *.h файл свалишь классы "треугольник", "сотрудник офиса" и "барабан" - это будет выглядеть весьма сомнительно

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

Не по теме:

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

0
-=ЮрА=-
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 либо подобном по значению файле.
Если из вашего опыта вы не встречались с ситуациями когда проект просто нечитабелен из за постоянного беганья по цепочкам хедеров, то я рад за вас, но это ещё ничего не значит...
На счёт времени компиляции - с современными то аппаратными средствами на него вообще можно забить отдав предпочтение понятности и элеганстности листинга.

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

Подключение заголовочных файлов.
У меня есть заголовочный файл: ...\1\2\file.h. в папке &quot;1&quot; есть file2.h. Как подключить к &quot;file.h&quot;...

Подключение заголовочных файлов
Имею два файла Large Factorial.h #include &lt;sstream&gt; #include &lt;iostream&gt; #include &lt;iomanip&gt;...

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

Подключение заголовочных файлов
Начал изучать С++, скачал несколько книг и заметил что в одних при включении заголовочных файлов...


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

Или воспользуйтесь поиском по форуму:
20
Ответ Создать тему
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2024, CyberForum.ru