Основное практическое отличие состоит в том, что если определения функций-членов находятся в теле заголовка, то, конечно, они компилируются один раз для каждой единицы перевода, которая включает этот заголовок. Когда ваш проект содержит несколько сотен или тысяч исходных файлов, и рассматриваемый класс довольно широко используется, это может означать много повторений. Даже если каждый класс используется только двумя или тремя другими, чем больше кода в заголовке, тем больше работы.
Если определения функций-членов находятся в собственных единицах перевода (файл .cpp), то они компилируются один раз, и только объявления функций компилируются несколько раз.
Это правда, что функции-члены, определенные (не только объявленные) в определении класса, неявно inline
. Но inline
не означает, что люди могут разумно догадаться, что это значит. inline
говорит, что допустимо, чтобы несколько определений функции появлялись в разных единицах перевода и впоследствии были связаны друг с другом. Это необходимо, если класс находится в заголовочном файле, который будут использовать разные исходные файлы, поэтому язык пытается быть полезным.
inline
также является подсказкой компилятору, что функция может быть полезна для вставки, но, несмотря на имя, это необязательно. Чем сложнее ваш компилятор, тем лучше он может принимать свои собственные решения относительно встраивания и тем меньше он нуждается в подсказках. Более важным, чем фактический встроенный тег, является то, доступна ли функция компилятору вообще. Если функция определена в другом модуле перевода, то она недоступна при компиляции вызова, и поэтому, если что-то собирается встроить вызов, то это должен быть компоновщик, а не компилятор.
Возможно, вы сможете лучше увидеть различия, если рассмотрите третий возможный способ сделать это:
// File class.h
class MyClass
{
private:
//attributes
public:
void method1(...);
void method2(...);
...
};
inline void MyClass::method1(...)
{
//implementation
}
inline void MyClass::method2(...)
{
//implementation
}
Теперь, когда неявный inline исключен, остаются некоторые различия между этим подходом «весь заголовок» и подходом «заголовок плюс источник». То, как вы делите свой код между единицами перевода, имеет последствия для того, что происходит при его создании.