В каком порядке я включаю заголовочные файлы? - PullRequest
7 голосов
/ 06 апреля 2011

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

Сейчас у меня есть stdafx.h, main.cpp, затем классы A, B, C и D, содержащиеся в Ah, A.cpp, Bh, B.cpp, Ch, C.cpp, Dh и D. каст.

В каком порядке я бы включил заголовки во все файлы, если

  • все классы содержат экземпляр класса SFML
  • класс D содержит экземпляр класса A и класса C
  • класс C содержит экземпляр класса B Мой код: (примечание: все заголовки имеют защиту заголовков)

stdafx.h:

#include <SFML/Graphics.hpp>
#include <iostream>

хиджры

#include "stdafx.h"
class A
{
    //sfml class
};

a.cpp

#include "stdafx.h"
#include "A.h"

B.h

#include "stdafx.h"
class B
{
    //sfml class
};

B.cpp

#include "stdafx.h"
#include "B.h"

C.h

#include "B.h"
class C: public B
{

};

C.cpp

#include "stdafx.h"
#include "C.h"

D.h

#include "A.h"
#include "C.h"
class D
{
    A a;
    C C; // if left uncommented I recieve a '1 unresolved externals' error
    //sfml class
}

D.cpp

#include "stdafx.h"
#include "D.h"

main.cpp

#include "stdafx.h"
#include "D.h"

Ответы [ 5 ]

9 голосов
/ 06 апреля 2011

Моя философия заключается в том, что в хорошо написанном коде заголовочные файлы должны включать все остальные заголовочные файлы, от которых они зависят.Я считаю, что не должно быть возможности включить заголовочный файл и получить ошибку компилятора для этого.Следовательно, каждый заголовочный файл должен (после #ifdef или #pragma once включать защиту ) включать все остальные заголовки, от которых он зависит.

Для того, чтобы неофициально проверить, что вы запомниливключите правильные заголовки в ваши файлы заголовков, файлы * .cpp должны #include минимальный набор файлов заголовков, который должен работать.Поэтому, если существуют отдельные заголовочные файлы для A, B, C и D, а ваш файл cpp использует класс D, то он должен включать только Dh .Ошибки компиляции не должны возникать, потому что Dh #include s Ah и Ch , Ch включает Bh Ah и Bh включают заголовок SFML (что бы это ни было). Ch и Dh могут включать заголовок SFML, если это кажется подходящим, но это не является действительно необходимым, если вы можете быть уверены, что зависимости ( Bh и Ах ) уже включил его.

Однако способ, которым Visual C ++ делает "предварительно скомпилированные заголовки", портит эту логику. требует , чтобы вы включили "StdAfx.h" в качестве самого первого заголовочного файла, что заставляет многих разработчиков просто помещать все #include s для всего проекта в StdAfx.h , а неиспользовать #include в любом из других заголовочных файлов.Я не рекомендую это.Или они поместят все внешние зависимости в StdAfx.h (например, windows.h, boost заголовки) и #include локальные зависимости в другом месте, так что изменение одного заголовочного файла не обязательно приведет к перестройке всего проекта.

Как я пишу свой код, большинство моих файлов CPP включают StdAfx.h и соответствующий файл .H.Таким образом, A.cpp включает StdAfx.h и Ah, B.cpp включает StdAfx.h и Bh и так далее.Единственные другие #include, помещенные в файл cpp, являются «внутренними» зависимостями, которые не отображаются в заголовочном файле.Например, если класс A вызывает printf(), то A.cpp (не Ah ) будет #include <stdio.h>, поскольку Ah не зависит от stdio.h .

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

1 голос
/ 06 апреля 2011

C наследует класс B . Итак, он должен увидеть идентификатор B. Итак, включите B.h здесь -

#include "B.h"    // Newly added
// Or you can forward declare class B ; 
class C: public B
{

};

D имеет объекты класса A, B. Итак, включите заголовки A, B в сам «D.h».

class D
{
    A a;  // Should see the definition of class A
    C c;  // Should see the definition of class B
    //sfml class
}

D.cpp

#include "A.h"
#include "C.h"
#include "D.h"  // Notice that A.h and C.h should definitely placed before

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

1 голос
/ 06 апреля 2011

Ah должен включать SFML

A.cpp должен включать Ah

Dh должен включать SFML, Ah и Ch

D.cpp должен включать Dh

main.cpp должен включать любой из A, B, C, D и SFML, который он использует напрямую.

Обычно в файле .cpp I не включает любые известные вам заголовкидолжен быть включен его соответствующим .h, потому что они содержат определения членов данных классов, определенных в этом .h.Следовательно, в моем коде D.cpp не будет включать Ah Это только я, однако, вы все равно можете включить его, чтобы напомнить вам, что файл .cpp (предположительно) использует его.

Это оставляет stdafx -где это нужно, зависит от того, что в нем используется.Вероятно, это необходимо везде, и MSVC ничего не обрабатывает (или обрабатывает, но отбрасывает?) До #include "stdafx.h" в исходном файле, поэтому это должно быть первым в каждом файле .cpp и больше нигде не появляться.

У всех заголовочных файлов должна быть защита для нескольких включений.

Вы можете добавить SFML (или что-то еще, что вам нравится) в stdafx.h, и в этом случае вы также можете удалить эти включения из любого другого места.

Как только вы это сделаете, больше не имеет значения в каком порядке вы включаете заголовки в каждый файл.Таким образом, вы можете делать то, что вам нравится, но я рекомендую руководство по стилю Google C ++ по теме (нажмите на стрелку), настроенное для учета stdafx.h.

1 голос
/ 06 апреля 2011

Взгляните на аналогичный вопрос , чтобы узнать хороший подход к созданию заголовков.

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

0 голосов
/ 06 апреля 2011

Зависит от зависимостей.В отличие от C # и других подобных языков, C ++ делает вещи в том порядке, в котором он написан, поэтому может возникнуть проблема.Если у вас есть проблемы с заказом, он не скомпилируется.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...