2013-09-28 3 views
2

Почему плохой способ определения функций класса в файлах заголовков?Встроенные функции в файлах заголовков в C++

Допустим, у меня есть файл заголовка, и я определить функции класса в самом определении класса, как,

headerfile.hpp

#ifndef _HEADER_FILE_ 
#define _HEADER_FILE_ 

class node{ 
int i; 

public: 
int nextn(){ 
...... 
return i; 
} 
} 

#endif //_HEADER_FILE_ 

Таким образом, определяющее функцию в классе, как это делает функция «Inline». Так что если мы включим этот файл заголовка в два файла .cpp, это вызовет «ошибку множественного определения»? Неправильно ли использовать такие функции в определении класса?

ответ

2

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

+0

Итак, нет ничего плохого в определении функций в заголовочном файле, как это, если функции невелики? – starkk92

+0

@ starkk92 Я согласен с этим, но это стиль, поэтому другие люди могут не согласиться. – john

+0

Поскольку в вопросе не упоминается 'inline', вы можете сделать различие между * inline * и' inline' более понятным. –

0

Законно определять (встроенные) функции в вашем файле hpp. Обратите внимание, что некоторые люди предпочитают собирать их под выделенным расширением типа «inl.hpp», но это только предпочтение стиля.

0

Это не плохая практика, особенно когда вы пишете классы шаблонов/методы.

inline Методы ввода помогают вам соблюдать одно правило определения.

Для классов шаблонов вы должны inline методов в файле заголовка (также вы можете явно их создать, чтобы избежать inline -ing).

Плохая вещь о inline методов, после изменения каждого inline -ED метод все единицы, которые используют этот метод, придется повторно скомпилировать снова, но при перемещении их в .cpp файла компилятор может сделать объектный файл и использовать его для многих единиц перевода.

Итак, вам решать, принять ли ваша реализация или нет (если это возможно) inline.

1

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

  • Тип проверки и составления ваших иждивенцев дешевле. Что-то, что использует ваш класс, можно безопасно скомпилировать, не зная о вашей реализации.

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

Дело в том, чтобы помнить, что это на самом деле означает писать #include в верхней части файла в C++: это означает «взять все содержимое какой-либо другой файл, и поместить их здесь.» Поэтому, если вы используете класс во многих местах по всей вашей базе кода, он обрабатывается каждый раз и повторно компилируется в контексте этой единицы компиляции.

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

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

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

Для дальнейшего чтения, возможно, стоит проверить «предварительно скомпилированные заголовки».

5

Это плохая практика по следующим причинам: если вам нужно изменить код, скажем, добавить трассировку в простой сеттер (они обычно находятся в .h); то вам нужно будет перекомпилировать все файлы CPP, которые # включают изменение (и любую зависимость). В моем текущем проекте, который мог доходить до 1 часа, потерялся. Если позже вам понадобится добавить еще одну трассировку, то другой и т. Д. Вы быстро потеряете 1-2 дня или работаете в ожидании компилятора.

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

Другая (не очень хорошая) причина в том, что если вы ищете свою базу кода для строки «:: MyFonction», вы не найдете ее в объявлении, так как нет «::» (нам нужны только реализации). Но хорошая IDE должна найти его в любом случае, используя контекстный поиск вместо строкового поиска.