С++, действительно ли частные функции действительно должны быть в файле заголовка?

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

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

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

Это избавит от необходимости объявлять любые частные функции в заголовочном файле.

Мне нравится следовать соглашениям, поэтому теперь я хочу спросить, считается ли это установленным соглашением в C++, что нестатические частные функции должны быть в заголовочном файле? Как насчет статических функций или статических констант?

РЕДАКТИРОВАТЬ: Я собираюсь вставить некоторый код, чтобы объяснить, что я получаю:

.h файл:

#ifndef SOME_CLASS_H
#define SOME_CLASS_H

class SomeClass
{
private:
    int x;
public:
    void combineWithX(int y);
};

#endif

файл.cpp

#include "SomeClass.h"

void someHelper(int* x)
{
    *x = (*x) + 1;
}

void SomeClass::combineWithX(int y)
{
    someHelper(&x);
    x += y;
}

Обратите внимание, что someHelper(int* x) в файле cpp ссылается на закрытый элемент x по духу, но не напрямую, и, следовательно, не должен появляться в заголовке. Мне интересно, считается ли такая вещь "плохим стилем"?

Ответ 1

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

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

Вам может быть интересно посмотреть идиому pImpl (подробнее)

Ответ 2

Простая идиома нужна только

  1. если вам нужно вывести "переменные" закрытого члена из публичного заголовка (для поддержания бинарной совместимости новых выпусков - если вы не знаете, что это значит, это, вероятно, не является проблемой)
  2. Если этот дизайн облегчает понимание

Если вы хотите только удалить закрытые функции-члены из открытого заголовка, достаточно использовать внутренний класс. Это не имеет штраф за перенаправление как идиома PImpl.

публичный.h файл

#ifndef SOME_CLASS_H
#define SOME_CLASS_H

class SomeClass
{
private:
    struct Private;
    int x;
public:
    void combineWithX(int y);
};

#endif

в.cpp файле

#include "SomeClass.h"

/** Declare all private member functions of SomeClass here
    This class can access not only private members of SomeClass
    but also friends of SomeClass. */
struct SomeClass::Private
{
  static void someHelper(SomeClass& self)
  {
    self.x = self.x + 1;
  }
};

void SomeClass::combineWithX(int y)
{
    Private::someHelper(*this);
    x += y;
}

SomeClass::Private может иметь любое количество вспомогательных функций, которые имеют полный доступ ко всем private/друзьям SomeClass, без необходимости объявлять какие-либо из них в заголовочном файле.