Различие между реализацией класса в.h файле или в .cpp файле

"3" для тех случаев, я обычно вставлял свои сценарии

if(!arrayList[arrayList.length -1]) arrayList.pop();

, Вы могли сделать служебную функцию из этого.

31
задан Jack 20 December 2016 в 01:46
поделиться

6 ответов

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

Если определения функций-членов находятся в отдельной единице перевода (файл .cpp), то они компилируются один раз, и только объявления функций компилируются несколько раз.

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

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

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

// File class.h
class MyClass
{
    private:
        //attributes
    public:
       void method1(...);
       void method2(...);
       ...
};

inline void MyClass::method1(...)
{
     //implementation
}

inline void MyClass::method2(...)
{
     //implementation
}

Теперь что неявная встроенная строка не мешает, остаются некоторые различия между подходом «все заголовки» и подходом «заголовок плюс источник». То, как вы делите код между единицами перевода, влияет на то, что происходит в процессе его создания.

36
ответ дан 27 November 2019 в 22:20
поделиться

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

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

2
ответ дан 27 November 2019 в 22:20
поделиться

Да, компилятор попытается встроить метод, объявленный непосредственно в файл заголовка, например:

class A
{
 public:
   void method()
   {
   }
};

Я могу придумать следующие удобства в разделении реализации в файлах заголовков:

  1. У вас не будет раздувания кода из-за того, что один и тот же код будет включен в несколько единиц трансляции.
  2. Время компиляции сократится кардинально. Помните, что для любого модификация в заголовочном файле компилятор должен собрать все остальные файлы, которые прямо или косвенно включить его. Я думаю это будет очень разочарование для любого, чтобы построить весь двоичный файл снова просто для добавления пробел в заголовочном файле.
7
ответ дан 27 November 2019 в 22:20
поделиться

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

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

Как уже указывалось в некоторых других ответах, да, определение метода в блоке файла class заставит компилятор встроиться.

7
ответ дан 27 November 2019 в 22:20
поделиться

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

Я хочу сказать, что если у вас есть довольно маленькая библиотека, которая, как ожидается, будет многократно использоваться и перекомпилироваться в различных проектах, то это дает преимущества при интеграции с некоторыми другими проектами, в отличие от добавления дополнительных файлов в основной проект или перекомпиляции внешнего lib/obj файла.

.
0
ответ дан 27 November 2019 в 22:20
поделиться

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

1
ответ дан 27 November 2019 в 22:20
поделиться
Другие вопросы по тегам:

Похожие вопросы: