Включить заголовки только в интерфейс, а не в реализацию

Мои заголовочные файлы выглядят так:

// A.hpp --- A's interface

#ifndef MY_H
#define MY_H

#include<string>
#include<vector>

class A {
public:
A(const std::string& name);
std::vector<double> foo() const;
private:
std::string m_name;
};

#endif

И мои файлы реализации выглядят так:

// A.cpp --- A's interface implementation
#include<A.hpp>

#include<implementation_detail.hpp>

A::A(const std::string& name)
: m_name(name) { }

std::vector<double> A::foo() const {
std::vector<double> r;
r.push_back(1);
return r;
}

Моя позиция в том, что я не #include string или же vector в файле реализации, потому что они уже объявлены в интерфейсе, и #includeих использование в файле реализации в лучшем случае излишне, а в худшем — вредно **.

Конечно, AРеализация будет #include все детали реализации не видно из интерфейса.

Мои вопросы: Я прав? Может ли эта практика негативно повлиять на мой код?

** Это неправдоподобно, но количество включений (и использованных средств защиты включений) может влиять на скорость компиляции для очень больших проектов; эта статья интересная.

2

Решение

Это вопрос стиля и личных предпочтений.

Для заголовочных файлов мое личное предпочтение — сделать заголовочный файл самостоятельным, но едва ли. Под «стоять самостоятельно» я имею в виду, что я должен быть в состоянии #include этот заголовок в некотором произвольном исходном файле, и этот исходный файл все еще будет компилироваться.

#include "some_random_header_file.h"int main () {}

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

Для исходных файлов мое личное предпочтение #include каждый заголовок, который обеспечивает функциональность, используемую в исходном файле. Если код исходный файл вызывает std::string::append, этот исходный файл был лучше #include <string> — даже если какой-то другой заголовок уже включил его.

2

Другие решения

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

Стоит отметить, что:

  • Не включайте вещи, которые вам нужны, в файл cpp в шапке.
  • Будьте явными в ваших типах в шапке. То есть использование std::string как
    тип не using std::string или даже хуже using namespace std;
    в шапке.
  • Это нормально использовать using операторы как удобно в файле cpp.

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

1

Это вопрос стиля, а не правильности.

Тем не менее, это считается хорошим стилем только включать вещи, которые абсолютно необходимы. Так что если вашему интерфейсу нужны эти заголовки, то ваш .h должен включить их.

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

Итак, учитывая эти два момента, вы правы иметь #include директивы в вашем заголовке.

0

Если вы действительно обеспокоены #include производительность, у вас есть несколько вариантов здесь:

0
По вопросам рекламы [email protected]