Мои заголовочные файлы выглядят так:
// 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
все детали реализации не видно из интерфейса.
Мои вопросы: Я прав? Может ли эта практика негативно повлиять на мой код?
** Это неправдоподобно, но количество включений (и использованных средств защиты включений) может влиять на скорость компиляции для очень больших проектов; эта статья интересная.
Это вопрос стиля и личных предпочтений.
Для заголовочных файлов мое личное предпочтение — сделать заголовочный файл самостоятельным, но едва ли. Под «стоять самостоятельно» я имею в виду, что я должен быть в состоянии #include
этот заголовок в некотором произвольном исходном файле, и этот исходный файл все еще будет компилироваться.
#include "some_random_header_file.h"int main () {}
Вышесказанное всегда должно компилироваться. Я имею в виду, что заголовок должен быть свободным от #include
директивы. Если некоторые #include
не обеспечивает функциональность, используемую непосредственно в заголовочном файле, я не #include
этот другой заголовок в заголовочном файле.
Для исходных файлов мое личное предпочтение #include
каждый заголовок, который обеспечивает функциональность, используемую в исходном файле. Если код исходный файл вызывает std::string::append
, этот исходный файл был лучше #include <string>
— даже если какой-то другой заголовок уже включил его.
Ты прав. Файл cpp является модулем компиляции. Вот где используются заголовки. Все, что включено в эти заголовки, также находится в файле cpp.
Стоит отметить, что:
std::string
какusing std::string
или даже хуже using namespace std;
using
операторы как удобно в файле cpp.Вы не хотите вводить больше типов, чем необходимо людям, включая ваши заголовки.
Это вопрос стиля, а не правильности.
Тем не менее, это считается хорошим стилем только включать вещи, которые абсолютно необходимы. Так что если вашему интерфейсу нужны эти заголовки, то ваш .h
должен включить их.
В то же время считается хорошим стилем сделать каждый заголовок самодостаточным — то есть, чтобы использовать его возможности, достаточно включить его, не добавляя ничего другого.
Итак, учитывая эти два момента, вы правы иметь #include
директивы в вашем заголовке.
Если вы действительно обеспокоены #include
производительность, у вас есть несколько вариантов здесь: