c ++ # включают различия в стиле - PullRequest
7 голосов
/ 03 июня 2011

Итак, на днях я просматривал несколько старых книг по C ++ и заметил способ создания класса C ++, которого я никогда раньше не видел.Все, что я видел до этого момента, всегда использовало #include "header.h" и компилировало файлы реализации отдельно.Я видел, что автор этой книги на самом деле поместил директиву include в реализацию в конце заголовочного файла и исключил файл .cpp из компиляции.Кто-нибудь использовал этот стиль?

Например: у меня есть main.cpp employee.h employee.cpp

//main.cpp
#include <iostream>
#include <stdio.h>
#include <string>
#include "employee.h"
void main()
{/*some code*/}  

//employee.h
#ifndef EMPLOYEE_H
#define EMPLOYEE_H
class employee
{
   public:
   //public members
   private:
   //private members
}
#endif

//employee.cpp
#include "employee.h"
#include <string>
//public member definitions

Я бы обычно скомпилировал этот проект так:

g++ main.cpp employee.cpp

Но вПример автора выглядит следующим образом:

//main.cpp
#include <iostream>
#include <stdio.h>
#include <string>
#include "employee.h"
void main()
{/*some code*/}  

//employee.h
#ifndef EMPLOYEE_H
#define EMPLOYEE_H
class employee
{
   public:
   //public members
   private:
   //private members
}
#include "employee.cpp"  // <-- the line of code that caught my attention
#endif

//employee.cpp
 #include <string>
//public member definitions

И полученный код компилируется как

g++ main.cpp

Это просто предпочтение стиля или есть какие-то реальные преимущества в этом?Я бы подумал, что это не очень хорошо масштабируется, но я не очень опытный программист на C ++.

Ответы [ 5 ]

3 голосов
/ 03 июня 2011

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

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

3 голосов
/ 03 июня 2011

Выполнение этого приведет к определению класса для каждой единицы перевода, в которую включен заголовочный файл.Это очень необычная парадигма, и она может быть опасной для вашего кодирования здоровья.В частности, если у вас есть main.cpp и foo.cpp, оба из которых #include "employee.h", то все методы в employee будут определены дважды, что является нарушением правила One Definition Rule и будетсоздавать ошибки компоновщика.Чтобы устранить эти ошибки компоновщика, вам нужно либо переместить определения в свои собственные единицы перевода, либо пометить их inline (что может или не может работать).

Это, однако, полезная идиома в некоторыхэкземпляров.Особенно с шаблонами, которые должны быть определены в единице перевода.В этом случае, когда вы хотите объявить и реализовать в отдельных файлах для удобства чтения, вы можете сделать конец файла #include.Когда я делаю это, я использую специальное расширение файла .hpp, чтобы показать, что файл особенный, поскольку он не предназначен для самостоятельной компиляции.См. этот ответ для примера.

2 голосов
/ 03 июня 2011

Это, безусловно, будет работать, но у него есть пара недостатков:

  • Более длительное время компиляции - обычно, если вы меняете один файл, вам нужно только скомпилировать этот файл, и компоновщик объединит его с другими более старыми результатами компиляции. Когда все включено в один файл, все нужно перекомпилировать сразу.
  • Потенциальная коллизия пространства имен - все символы, объявленные в одном модуле, теперь видны всем. Это может быть большой проблемой, если вы используете какие-либо макросы.
2 голосов
/ 03 июня 2011

Это, вероятно, не основная книга. В любом случае, если мы определяем правильность условием «он компилируется», то да, это вопрос стиля, и оба стиля верны.

Тем не менее, единственный по-настоящему правильный стиль, согласно стандарту и руководствам по проектированию, которые соответствуют другим языкам программирования, - это первый, соответствующий духу отдельной компиляции блоков перевода. Как вы сами сказали, второй стиль не очень хорошо масштабируется.

Еще один момент - это #include , который больше не является стандартным:

#include <cstdio>
0 голосов
/ 03 июня 2011

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

...