Базовое понимание заголовочных файлов C ++ - PullRequest
5 голосов
/ 26 августа 2010

У меня есть теоретический вопрос, а не отчет об ошибке.

Я новичок в программировании на C ++, пытаюсь его устранить

Использование компилятора VC ++ VS2008

Я часто задаюсь вопросом, ПОЧЕМУ я хочу предпринять некоторые действия в заголовочных файлах.

Например, посмотрите на этот блок кода:

#include "DrawScene.h"
#include "Camera.h"
#include "Player.h"
#include "Grid.h"
#include "InputHandler.h"
#include "GameState.h"

class Controller
{
public:
private:
public:
 Controller();
 ~Controller(){}
 void Update();

private:
};

И подключенный файл CPP, controller.cppнаряду с этим

#include "stdafx.h"
#include "glut.h"
#include "Controller.h"
#include <iostream>

Grid* grid_ptr = new Grid();
InputHandler* inputHandler_ptr = new InputHandler();
DrawScene* drawScene_ptr = new DrawScene();
GameState* gameState_ptr = new GameState();

Controller::Controller()
{

}

void Controller::Update()
{

}

Какой хороший способ решить, что включает в себя куда?До сих пор я использовал метод «все работает», но я нахожу его несколько непрофессиональным.

Теперь, даже если вы можете сказать, что в моем коде есть ошибки синтаксиса X и недостатки в дизайне, пожалуйста, сделайте это, но я хотел бы знать, что информация об использовании файлов .h VS .cpp остается.

Почему вообще такой дизайн?И какие ямы и ловушки всегда должны быть легкими при создании любой программы на С ++, основанной на ООП?

Что вызвало у меня этот вопрос, кстати, было то, что я хотел уведомить читателя о заголовочном файле, который там будетбыть объектами, хранящимися в контроллере, но присвоение этих неинициализированных объектов казалось невозможным, не делая их статичными.

Примечание: я проистекаю из C # -> C ++, может помочь узнать.Это мой взгляд на код на данный момент.

Заранее благодарим вас за ваши усилия!

РЕДАКТИРОВАТЬ: 26/08/2010 18: 16

Итак, сборкавремя - это сущность добраНужно ли быть осторожнее?

Ответы [ 5 ]

15 голосов
/ 26 августа 2010

Это мое личное мнение, а не консенсус, но я рекомендую: в заголовочный файл включать только те заголовки, которые необходимы для содержимого заголовочного файла *1002* компиляции без синтаксисаошибки.И если вы можете использовать предварительные объявления, а не вложенные включения, сделайте это.

Причина этого в том, что в C ++ (в отличие от C #, iiuc) отсутствует контроль экспорта.Все, что вы включаете из заголовка, будет видно включающим из заголовка, что может быть большим количеством мусора, который пользователи вашего интерфейса не должны видеть.

4 голосов
/ 26 августа 2010

Вообще говоря, заголовки должны находиться в файле cpp.Для стандартных библиотек (и, возможно, для 3-й библиотеки) вы можете вставить их в заголовки.Однако заголовки, определенные специально для вашего проекта, должны по возможности помещаться в файлы cpp.

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

Вот почему прямое объявление и шаблон PIMPL (Pointer to IMPLementation, or opaque pointer)популярныЭто позволяет вам перенести хотя бы некоторые изменения / реализацию из заголовочного файла.Например:

// header file:
class SomeType;

class AnotherType
{
private:
    SomeType *m_pimpl;
};

не требует, чтобы вы включали "sometype.h", тогда как:

// header file
class AnotherType
{
private:
    SomeType m_impl;
};

делает.РЕДАКТИРОВАТЬ: На самом деле вам не нужно включать "sometype.h" в "anothertype.h", если вы ВСЕГДА включаете "sometype.h" перед "anothertype.h" в КАЖДЫЙ файл cpp, который включает в себя "anothertype.h".

Иногда бывает трудно переместить файл заголовка в файл cpp.В этот момент у вас есть решение - лучше ли абстрагировать код, чтобы вы могли это сделать, или лучше просто добавить include?

4 голосов
/ 26 августа 2010

Включайте заголовки в другой заголовок только в случае крайней необходимости. Если заголовок может идти только в исходном файле, то это лучшее место. Вы можете использовать предварительные объявления классов в заголовке, если вы используете только указатели и ссылки на них. Ваши классы DrawScene, GameState, Grid и InputHandler выглядят так, как будто они попадают в эту категорию.

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

3 голосов
/ 26 августа 2010

Не кладите слишком много (читай, ненужного) #includes в ваш .h файл. Это может привести к увеличению времени сборки, например, всякий раз, когда вы меняете Camera.h, вы меняете Controller.h, поэтому все, что включает Controller.h, необходимо будет перестраивать. Даже если это только комментарий, который изменился.

Используйте предварительные объявления, если вы храните только элементы указателя, затем добавьте #includes в файл cpp.

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

В C ++ можно включить всю встроенную реализацию в определение класса, файл, так же, как вы это делаете в Java, но это действительно нарушает правило интерфейса / реализации .h / .cpp.

2 голосов
/ 26 августа 2010

Заголовочные файлы содержат объявления функций, классов и других объектов, тогда как файлы cpp предназначены для реализации этих ранее объявленных объектов.

Заголовочные файлы существуют в основном по историческим причинам.Компилятор C ++ легче построить, если определения всех функций, классов и т. Д., Которые будут использоваться вашим кодом, приведены до того, как вы их на самом деле вызовете.

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

...