Где я должен реализовать метод класса?
Я знаю о трех разных вариантах реализации "местоположения" для моих методов класса:
1) Определите метод внутри моего класса (файл .h) и реализуйте его в моем файле .cpp
//.h
class Foo
{
int getVal() const;
};
//.cpp
int Foo::getVal() const
{ return 0; }
2) Определите и реализуйте метод внутри моего класса (файл .h).
//.h
class Foo
{
int getVal() const
{ return 0; }
};
3) Определите метод внутри моего класса и реализуйте его вне класса, но внутри моего файла заголовка.
//.h
class Foo
{
int getVal() const;
};
int Foo::getVal() const
{ return 0; }
Каковы основные различия между этими тремя подходами?
Ответы
Ответ 1
В этом вопросе есть три элемента: читаемость (насколько хорошо выглядит код), компиляция (насколько компилятор может ее оптимизировать) и скрытие реализации (если вы используете код как библиотеку, возможно, вам не захочется явно делиться ваш особый соус с миром).
Метод one предоставляет только интерфейс для функции в файле заголовка. Это означает, что вы показываете хороший чистый интерфейс, и ваша реализация не отображается в открытом тексте. Тем не менее, код не может быть встроен в единицы компиляции, поэтому он может быть немного медленнее во время выполнения (на практике это имеет значение только для очень-очень маленького процента кода). ЭТО ДОЛЖНО БЫТЬ ВАШИМ ПУТЕМ ПО УМОЛЧАНИЮ.
Метод 2 подразумевает вложение. Длинные функции будут загромождать ваш класс, который (imho) плох. Также раскрывает вашу реализацию миру. Тем не менее, функция может быть встроена и менее сложна, чем определение ее в другом месте. Я резервирую это для очень маленьких функций.
Метод 3 фактически является незаконным, так как вы нарушаете правило с одним определением, но все в порядке:
//Foo.h
class Foo {
int getVal() const;
};
inline int Foo::getVal() const {
return 0;
}
Я использую это, когда хочу, чтобы определение класса было чистым, но нужно определение функции в файле заголовка (для встроенных или шаблонных функций).
Ответ 2
(1) будет быстрее компилироваться для большого проекта (нужно только компилировать определение getVal
один раз в Foo.cpp и только перекомпилировать одну вещь, если определение изменится), и вы получите очень понятный интерфейс для класс для людей, которые хотят его найти. С другой стороны, вы не можете встроить getVal()
.
(2) и (3) будут скомпилировать медленнее и добавить дополнительные зависимости к изменениям ваших определений. Но вы можете inline getVal()
. Также это необходимо, если getVal
является функцией шаблона. ПРИМЕЧАНИЕ (3) вызовет ошибки компоновщика, если ваш заголовок включен несколько раз - вам нужно отметить, чтобы не помечать вашу функцию inline
. Это хорошая причина предпочесть (1) и (2) - (3).
Действительно, это не вопрос выбора (1) vs (2). Вы, вероятно, будете использовать оба в больших проектах - поместите определения функций, которые должны быть встроены (и шаблоны) в заголовок, и поставьте те, которые вложения не имеют смысла для cpp.
Ответ 3
Небольшое примечание перед тем, как я начну, есть много слов, которые очень похожи для описания этих вещей, я буду использовать объявление для части в файле заголовка (int getVal() const
) и реализацию для части в cpp файл (int Foo::getVal() const
). Извините, если они не совсем точны.
Также обратите внимание, что преимущества - это штрафы для других, если это не ясно.
1) Определите метод внутри моего класса (файл .h) и реализуйте его в моем файле .cpp
Это считается стандартным методом и обычно считается стандартным (существует множество исключений, поэтому значение по умолчанию может быть немного сильным).
Отделяет декларацию от реализации. Это дает несколько преимуществ:
- Вам нужно только один раз выполнить компиляцию. Это может потенциально сохранить время компиляции.
- Вам нужна только декларация для ссылки. Это может избежать проблем с упорядочением и жизненно важно для циклических ссылок между классами.
- Вы не распространяете свою реализацию, это может быть полезно для систем с закрытыми исходными кодами, поскольку вам часто приходится пропускать много файлов .h, чтобы другие могли подключаться к вашей системе.
2) Определите и реализуйте метод внутри моего класса (файл .h).
Это называется встроенной реализацией, она должна использоваться только в простых реализациях. Он также имеет несколько преимуществ:
- Большинство компиляторов воспринимают это как огромный встроенный намек. Это не гарантирует inling, но это очень вероятно, что для простых методов может быть победой. Способы стиля собственности - общий пример.
- Ваша реализация тривиально найти, поскольку она прямо в декларации.
3) Определите метод внутри моего класса и реализуйте его вне класса, но внутри моего файла заголовка.
Я раньше этого не видел, но предполагал, что он используется, когда определение нетривиально, но вы хотите использовать встроенные преимущества 2. IdeaHat упоминает, что в этом случае требуется ключевое слово inline
.