"определение функции c ++ внутри заголовочного файла класса делает функцию встроенной"
Это не правда. Определение функции (то есть предоставление тела функции вместо простого объявления) внутри определения класса делает его встроенным. Под словом «делает его встроенным» я подразумеваю то же самое, что и для него встроенное ключевое слово. Но определения классов не обязательно должны быть в заголовках, а заголовки могут содержать иные вещи, чем определения классов.
Таким образом, в этом примере функция foo
неявно встроена. Функция bar
не является встроенной:
struct Foo {
void foo() {}
void bar();
};
void Foo::bar() {}
"Помещение встроенного ключевого слова рядом с функцией - это только предложение, и компилятор не обязательно будет следовать ему"
inline
имеет два эффекта. Одним из них является подсказка компилятору, которую он может игнорировать. Другой не является обязательным, и всегда имеет свой эффект. «Подсказка» заключается в том, что компилятору рекомендуется заменить вызовы этой функции копией кода для самой функции.
Гарантированный эффект состоит в том, что встроенная функция может быть определена в нескольких единицах перевода, и они могут быть связаны друг с другом без многократной ошибки определения, и компоновщик удаляет все копии, кроме одной. Таким образом, если приведенный выше пример появляется в заголовочном файле, который совместно используется несколькими единицами перевода, bar
должен быть явно помечен как встроенный. В противном случае компоновщик обнаружит несколько определений bar
, что недопустимо.
Несмотря на название, inline
в C ++ в основном касается второго, обязательного, а не первого, необязательного эффекта. Современные оптимизирующие компиляторы имеют свои собственные идеи относительно того, какие вызовы должны быть встроены, и не обращают большого внимания на inline
при принятии этого решения. Например, я видел, как это влияет на gcc при умеренных уровнях оптимизации, но на низких уровнях примерно ничего не указывается, а на высоких уровнях примерно все есть (если определение доступно, когда вызов компилируется), если это не делает функцию слишком большой.
Независимо от того, определена ли функция в заголовке или в файле cpp, она сама по себе абсолютно не влияет Вы можете смело представить, что #include выполняет копирование и вставку заголовочного файла в файл cpp в препроцессоре до того, как компилятор его увидит. Если функция определена в той же единице перевода, что и ее вызов, то код функции доступен для вставки компилятором. Если они находятся в разных единицах перевода, то код недоступен, и вызов может быть встроен только компоновщиком с оптимизацией всей программы или подобным. «Единица перевода» более или менее означает «файл cpp после того, как все заголовки были скопированы и вставлены в него».