2015-02-02 5 views
10

я в курсе трех различных видов реализации «местах» для моих методов класса:Где я должен реализовать метод класса?

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; } 

В чем основные отличия между этими тремя подходами?

+3

# 3, вероятно, приведет к ошибке компоновщика (как только вы включите этот заголовок в несколько исходных файлов). –

+1

# 2 позволит компилятору встроить функцию там, где это необходимо (без необходимости оптимизации всей программы), поэтому она обычно используется для небольших функций getter/setter, как показано в вашем примере. Для шаблонных классов (только), # 1 не является опцией, а # 2 и # 3 становятся эквивалентными. – Cameron

+0

Для более быстрой скорости компиляции предпочитайте # 1 как можно больше. –

ответ

8

В этом вопросе есть три элемента: читаемость (насколько хорошо выглядит код), компиляция (насколько компилятор может ее оптимизировать) и скрытие реализации (если вы используете код как библиотеку, вы можете не захотеть явно поделитесь своим специальным соусом с миром).

Первый метод предоставляет только интерфейс для функции в файле заголовка. Это означает, что вы показываете хороший чистый интерфейс, и ваша реализация не отображается в открытом тексте. Тем не менее, код не может быть встроен в единицы компиляции, поэтому он может быть немного медленнее во время выполнения (на практике это имеет значение только для очень-очень маленького процента кода). ЭТО ДОЛЖНО БЫТЬ ВАШИМ ПУТЕМ ПО УМОЛЧАНИЮ.

Способ 2 подразумевает вложение. Длинные функции будут загромождать ваш класс, который (imho) плох. Также раскрывает вашу реализацию миру. Тем не менее, функция может быть встроена и менее подробна, чем определение ее в другом месте. Я резервирую это для очень маленьких функций.

Метод 3 на самом деле незаконным, так как вы будете нарушать правила на один четкостью, но следующие прекрасно:

//Foo.h 
class Foo { 
    int getVal() const; 
}; 

inline int Foo::getVal() const { 
    return 0; 
} 

Я использую это, когда я хочу, чтобы сохранить определение класса чистой, но хотите определение функции в файле заголовка (для встроенных или шаблонных функций).

+0

Практически любой современный компоновщик может встроить в единицы компиляции. –

+0

Кроме того, шаблоны меняют все, они заслуживают упоминания –

+0

@Mooing Duck, да, но вам нужно запустить другие проходы оптимизации после встраивания, чтобы получить лучшее, и это можно сделать только с оптимизацией времени ссылки. – sbabbi

2

(1) будет скомпилировать быстрее для большого проекта (нужно только компилировать определение getVal один раз в Foo.cpp, и нужно только перекомпилировать одну вещь, если изменения определения), и вы получите очень понятный интерфейс для класс для людей, которые хотят его найти. С другой стороны, вы не можете включить строку getVal().

(2) и (3) будут скомпилировать медленнее и добавить дополнительные зависимости к изменениям ваших определений. Но вы можете inline getVal(). Также это необходимо, если функция getVal является функцией шаблона. ПРИМЕЧАНИЕ. (3) вызовет ошибки компоновщика, если ваш заголовок включен несколько раз - вам нужно отметить, чтобы не наклеить вашу функцию inline. Это хорошая причина предпочесть (1) и (2) - (3).

Действительно, это не вопрос выбора (1) vs (2). Вы, вероятно, будете использовать оба в больших проектах - поместите определения функций, которые должны быть встроены (и шаблоны) в заголовок, и поставьте те, которые вложения не имеют смысла для cpp.

+2

Этот ответ неполный. Он описывает только скорость компиляции, которая не является единственной проблемой и, вероятно, не самая важная. – anatolyg

+0

@anatolyg Для моего проекта, который занимает несколько минут, чтобы построить, это самая важная проблема. –

+0

Единственное, чего не хватает в ответе, - это возможная проблема ODR, если заголовок включен несколько раз с 3); Не согласен с комментарием от @anatolyg и имеет upvoded –

0

Незначительное примечание перед тем, как я начну, есть много слов, которые очень похожи для описания этих вещей, я буду использовать объявление для части в файле заголовка (int getVal() const) и реализацию для части в файле cpp (int Foo::getVal() const). Извините, если они не совсем точны.

Также обратите внимание, что льготы являются штрафами для других, если это не ясно.

1) Определение метода в моем классе (.h-файл) и реализовать его в моем файле .cpp

Это считается стандартным методом, и, как правило, принимается равным по умолчанию (есть множество исключений, поэтому дефолт может быть немного сильным).

Отделяет декларацию от реализации. Это дает несколько преимуществ:

  • Вам нужно всего лишь выполнить компиляцию реализации. Это может потенциально сохранить время компиляции.
  • Вам нужна только декларация для ссылки. Это может избежать проблем с упорядочением и жизненно важно для циклических ссылок между классами.
  • Вы не распространяете свою реализацию, это может быть полезно для закрытых исходных систем, поскольку вам часто приходится распространять много файлов .h, чтобы другие могли подключаться к вашей системе.

2) Определите и реализуйте метод внутри моего класса (файл .h).

Это называется встроенной реализацией, его следует использовать только в простых реализациях. У него также есть несколько преимуществ:

  • Большинство компиляторов воспринимают это как огромный встроенный намек. Это не гарантирует inling, но это очень вероятно, что для простых методов может быть победой. Способы стиля собственности являются распространенным примером.
  • Ваша реализация тривиально найти, поскольку она прямо указана в декларации.

3) Определение метода внутри моего класса и реализовать его вне класса, но в моем файле заголовка.

Я не видел этого раньше, но было бы предположить, что это используется, когда определение является нетривиальной, но вы хотите инлайн преимущества 2. IdeaHat упоминает, что inline ключевое слово в этом случае требуется.

+1

# 3 распространен для сложных шаблонов. У вас относительно нормальное определение класса, а затем появляются определения сложных функций. Ключевое слово inline не требуется в случае с шаблоном. –

Смежные вопросы