Гаразд, якимось чином не експерт по C / C ++, але я думав, що сенс файлу заголовка - декларувати функції, тоді файл C / CPP повинен визначати реалізацію.
Справжнє призначення файлу заголовка полягає у спільному використанні коду між кількома вихідними файлами. Він зазвичай використовується для відокремлення декларацій від реалізацій для кращого управління кодом, але це не є вимогою. Можна написати код, який не покладається на файли заголовків, а можна написати код, який складається лише з файлів заголовків (бібліотеки STL та Boost - хороші приклади цього). Пам'ятайте, коли препроцесор зустрічає #include
оператор, він замінює оператор вмістом файлу, на який посилається, тоді компілятор бачить лише заповнений попередньо оброблений код.
Так, наприклад, якщо у вас є такі файли:
Foo.h:
#ifndef FooH
#define FooH
class Foo
{
public:
UInt32 GetNumberChannels() const;
private:
UInt32 _numberChannels;
};
#endif
Foo.cpp:
#include "Foo.h"
UInt32 Foo::GetNumberChannels() const
{
return _numberChannels;
}
Bar.cpp:
#include "Foo.h"
Foo f;
UInt32 chans = f.GetNumberChannels();
Препроцесор розбирає foo.cpp і Bar.cpp окремо і проводить наступний код , який компілятор потім розбирає:
Foo.cpp:
class Foo
{
public:
UInt32 GetNumberChannels() const;
private:
UInt32 _numberChannels;
};
UInt32 Foo::GetNumberChannels() const
{
return _numberChannels;
}
Bar.cpp:
class Foo
{
public:
UInt32 GetNumberChannels() const;
private:
UInt32 _numberChannels;
};
Foo f;
UInt32 chans = f.GetNumberChannels();
Bar.cpp компілюється у Bar.obj і містить посилання для виклику Foo::GetNumberChannels()
. Foo.cpp компілюється у Foo.obj і містить фактичну реалізацію Foo::GetNumberChannels()
. Після компіляції компоновщик потім збігає файли .obj та зв’язує їх між собою, щоб отримати остаточний виконуваний файл.
То чому в заголовку є реалізація?
Включаючи реалізацію методу всередині декларації методу, вона неявно оголошується як вкладена (існує фактичне inline
ключове слово, яке також може бути явно використано). Вказівка на те, що компілятор повинен вбудовувати функцію, є лише підказкою, яка не гарантує, що функція справді вбудована. Але якщо це так, то звідки б не було викликано вбудовану функцію, вміст функції копіюється безпосередньо на сайт виклику, замість того, щоб генерувати CALL
оператор, щоб перейти до функції та повернутися до абонента при виході. Потім компілятор може взяти до уваги навколишній код і, якщо це можливо, додатково оптимізувати скопійований код.
Це пов’язано з ключовим словом const?
Ні. const
Ключове слово просто вказує компілятору, що метод не змінить стан об’єкта, до якого його викликають під час виконання.
Яка саме вигода / сенс робити це таким чином, ніж визначення реалізації у файлі CPP?
При ефективному використанні це дозволяє компілятору, як правило, виробляти швидший та краще оптимізований машинний код.